Coding Windows Services in C++

Warning! Some information on this page is older than 3 years now. I keep it for reference, but it probably doesn't reflect my current knowledge and beliefs.

18:31
Fri
01
Oct 2010

Coding Windows Services in C++

Services in Windows are like daemons in Linux - resident programs that work in background. I've recently learned how to code them in C++ using WinAPI. Here is a quick tutorial about this:

All the documentation you need to develop services can be found in MSDN Library. If you have it offline, go to: Win32 and COM Development / System Services / DLLs, Processes and Threads / SDK Documentation / DLLs, Processed, and Threads / Services. You can also read it online HERE. I talk only about native C and C++ code here, but services can also be written in .NET.

What are pros and cons of services, comparing to normal applications? Service can be automatically started with the system and work all the time, no matter if any user logs on and off. It can have extensive priviledges to access files on hard disk and the like, no matter what limitations do the logged-in user have. But service cannot interact directly with the user - it cannot show console or any window. So the only way for a service to do any input/output is to read some configuration files, write some log files or to communicate with some other client process ran by the user, e.g. via TCP socket connected to "localhost".

Service is written as a console application that uses special WinAPI functions to communicate with so called SCM - Service Control Manager. Example entry point routine looks like this:

// Standard console application entry point.
int main(int argc, char **argv)
{
    SERVICE_TABLE_ENTRY serviceTable[] = {
        { _T(""), &ServiceMain },
        { NULL, NULL }
    };
       
    if (StartServiceCtrlDispatcher(serviceTable))
        return 0;
    else if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
        return -1; // Program not started as a service.
    else
        return -2; // Other error.
}

StartServiceCtrlDispatcher is the first service-related function used here. It needs an array because a process can implement multiple different services, but I show only single-service process here. The function blocks for the entire execution time of working service and fails if program was run as normal application, not as a service. While service is working, a callback function is being executed, which I called ServiceMain here. It should initialize service and then execute all the code in loop until system wants to stop the service. You can also exit the function and thus stop the service at any time if you want (e.g. if some critical error occured).

// Main function to be executed as entire service code.
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
    // Must be called at start.
    g_ServiceStatusHandle = RegisterServiceCtrlHandlerEx(_T("SERVICE NAME"), &HandlerEx, NULL);
   
    // Startup code.
    ReportStatus(SERVICE_START_PENDING);
    g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    /* Here initialize service...
    Load configuration, acquire resources etc. */
    ReportStatus(SERVICE_RUNNING);

    /* Main service code
    Loop, do some work, block if nothing to do,
    wait or poll for g_StopEvent... */
    while (WaitForSingleObject(g_StopEvent, 3000) != WAIT_OBJECT_0)
    {
        // This sample service does "BEEP!" every 3 seconds.
        Beep(1000, 100);
    }

    ReportStatus(SERVICE_STOP_PENDING);
    /* Here finalize service...
    Save all unsaved data etc., but do it quickly.
    If g_SystemShutdown, you can skip freeing memory etc. */
    CloseHandle(g_StopEvent);
    ReportStatus(SERVICE_STOPPED);
}

RegisterServiceCtrlHandlerEx is a function that must be called first to register your application as a service, pass its name and a pointer to your control event handler function. Then you do some initialization, execute main service code in a loop and after it's time to stop it, do the cleanup and exit.

Service should report its state to the SCM with SetServiceStatus function. It can be called at any time and from any thread and informs the system about if your service is stopped, running, starting, stopping, paused etc. This function takes quite sophisticated SERVICE_STATUS structure, but I believe it can be simplified to three main cases which I enclosed in the following functions: ReportStatus reports basic status like SERVICE_STOPPED, SERVICE_RUNNING, SERVICE_START_PENDING or SERVICE_STOP_PENDING.

SERVICE_STATUS_HANDLE g_ServiceStatusHandle; 
HANDLE g_StopEvent;
DWORD g_CurrentState = 0;
bool g_SystemShutdown = false;

void ReportStatus(DWORD state)
{
    g_CurrentState = state;
    SERVICE_STATUS serviceStatus = {
        SERVICE_WIN32_OWN_PROCESS,
        g_CurrentState,
        state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
        NO_ERROR,
        0,
        0,
        0,
    };
    SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

Third member of the SERVICE_STATUS structure - dwControlsAccepted - indicates which events will be accepted by the service after this call. I want to accept events informing about system shutdown and allow user to stop the service. I could also pass SERVICE_ACCEPT_PAUSE_CONTINUE here, which means I supported pausing and resuming the service.

ReportProgressStatus function reports service status during initialization and finalization - SERVICE_START_PENDING, SERVICE_STOP_PENDING, SERVICE_CONTINUE_PENDING, SERVICE_PAUSE_PENDING. I don't actually use it, but if the startup or shutdown of your service takes a lot of time, you should periodically report progress with this function. CheckPoint is simply a counter that should be incremented with each call, telling that service is making some progress. WaitHint is an estimated time it will take to finish initialization, finalization or to perform its next step. By default, system waits about 30 seconds for your service to start or stop and you should not exceed that without a good reason.

void ReportProgressStatus(DWORD state, DWORD checkPoint, DWORD waitHint)
{
    g_CurrentState = state;
    SERVICE_STATUS serviceStatus = {
        SERVICE_WIN32_OWN_PROCESS,
        g_CurrentState,
        state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
        NO_ERROR,
        0,
        checkPoint,
        waitHint,
    };
    SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

Finally, there is a way for a service to shutdown and inform the system that some critical error occured. To do this, report SERVICE_STOPPED and pass error code. The code will be saved along with information about service failture to the system event log.

void ReportErrorStatus(DWORD errorCode)
{
    g_CurrentState = SERVICE_STOPPED;
    SERVICE_STATUS serviceStatus = {
        SERVICE_WIN32_OWN_PROCESS,
        g_CurrentState,
        0,
        ERROR_SERVICE_SPECIFIC_ERROR,
        errorCode,
        0,
        0,
    };
    SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

HandlerEx is a function to handle events sent by the system to control your service - stop it, pause, inform about the system shutdown or simply query for current status. You must always call SetServiceStatus in this function. It can be executed in different thread, so you must synchronize it with the code in ServiceMain. I do this with g_StopEvent - an event that will be set when the service should exit.

// Handler for service control events.
DWORD WINAPI HandlerEx(DWORD control, DWORD eventType, void *eventData, void *context)
{
    switch (control)
    {
    // Entrie system is shutting down.
    case SERVICE_CONTROL_SHUTDOWN:
        g_SystemShutdown = true;
        // continue...
    // Service is being stopped.
    case SERVICE_CONTROL_STOP:
        ReportStatus(SERVICE_STOP_PENDING);
        SetEvent(g_StopEvent);
        break;
    // Ignoring all other events, but we must always report service status.
    default:
        ReportStatus(g_CurrentState);
        break;
    }
    return NO_ERROR;
}

That's all the code I wanted to show. Now, because service cannot be run as normal program, you must learn how to install and uninstall it. Fortunately there is a simple command line program for this distributed with Windows - sc. To install your service, enter following command (exactly like this, with "binPath=" SPACE "PATH"):

sc create SERVICE_NAME binPath= FULL_PATH_TO_EXE_FILE

To uninstall it:

sc delete SERVICE_NAME

To control your service - start it, stop it or query its status - use commands:

sc start SERVICE_NAME
sc stop SERVICE_NAME
sc query SERVICE_NAME

Or simply run Administrative Tools / Services (another way to access it is Start / Run / "services.msc").

Two kinds of command line arguments can be passed to a service. First are argc, argv parameters taken by main function. They come from a command line fixed during installation of the service. Second are argc, argv arguments taken by ServiceMain function. They are different - argv[0] is the service name and the rest are arguments that you passed as additional parameters when calling "sc start" command.

Of course there is more to be told on this subject. Service can depend on some other services, can be automatically started with the system or only on demand, can have priviledges of a selected user or one of standard ones, like "LocalSystem" (biggest priviledges on local system, the default), "LocalService" or "NetworkService". See MSDN Library for details.

Comments (2) | Tags: c++ windows winapi | Author: Adam Sawicki | Share

Comments

sneha
2016-04-08 17:42:32
Hi,

I am running multiple windows service but when I give sc start "svc name" its only running 1st service.Below is code snippet for the same, any inputs where I am going wrong will be of great help.


#include "MyService.h"
#include <string>
#include<iostream>
#include<Windows.h>
#include<tchar.h>

#include<string>

static int isMyStarted = 0;
static int isMy1Started = 0;
/********************************************************************************
Function Name : ServiceMain
Input parameter : DWORD argc, LPTSTR *argv
Output Parameter : None
Return value : void
Description : Main function responsible for registering the service
control handler with service control manager and
creates worker thread.
*********************************************************************************/
VOID WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;

// Register our service control handler with the SCM
g_StatusHandle = RegisterServiceCtrlHandler(My_SERVICE_NAME, ServiceCtrlHandler);

if(g_StatusHandle == NULL)
{
goto EXIT;
}

// Tell the service controller we are starting
ZeroMemory(&g_ServiceStatus, sizeof(g_ServiceStatus));
g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
//g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwServiceSpecificExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;

if(SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
debugLog("d:\My_logs.txt", "Unable to set event in line ");
}

/*
* Perform tasks necessary to start the service here
*/

// create a service stop event to wait on later
g_ServiceStopEvent = createEvent(NULL, TRUE, FALSE, NULL);
if(g_ServiceStopEvent == NULL)
{
// Error creating event
// Tell service controller we are stopped and exit
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = GetLastError();
g_ServiceStatus.dwCheckPoint = 1;

if(SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
debugLog("d:\My_logs.txt", "Unable to set event in line ");
}
goto EXIT;
}

// Tell the service controller we are started
//g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 0;

if(SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
debugLog("d:\My_logs.txt", "Unable to set event in line ");
}

// Start a thread that will perform the main task of the service
debugLog("d:\My_logs.txt", "starting worker thread ");
HANDLE hThread = createThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);

// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);

/*
* Perform any cleanup tasks
*/

CloseHandle(g_ServiceStopEvent);

// Tell the service controller we are stopped
//g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 3;

if(SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
debugLog("d:\My_logs.txt", "Unable to set event in line ");
}

EXIT: return;
}


/********************************************************************************
Function Name : ServiceCtrlHandler
Input parameter : DWORD CtrlCode
Output Parameter : None
Return value : void
Description : Registered in Servicemain which processes the control
requests received by SCM.
*********************************************************************************/
VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
{

switch(CtrlCode)
{
case SERVICE_CONTROL_STOP:

if(g_ServiceStatus.dwCurrentState != SERVICE_RUNNING)
break;

/*
* Perform tasks necessary to stop the service here
*/

//g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;

if(SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
debugLog("d:\My_logs.txt", "My:Unable to set event in line ");
}

// This will signal the worker thread to start shutting down
if(! SetEvent(g_ServiceStopEvent))
{
debugLog("d:\My_logs.txt", "My:Not Stopped Service ");
}
else
{
debugLog("d:\My_logs.txt", "My: Stopped Service ");
}

break;

default:
break;
}
}

/********************************************************************************
Function Name : ServiceWorkerThread
Input parameter : LPVOID lpParam
Output Parameter : None
Return value : DWORD ERROR_SUCCESS/ERROR_FAIL
Description : Worker thread that does actual processing i.e. checks
if the My process is killed, if killed it will create
the process again
*********************************************************************************/
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
{
while(true)
{
if(0 == isMyStarted)
{
debugLog("d:\My_logs.txt"," isMyStarted ",isMyStarted);
int iRet = createProcess();
isMyStarted = 1;
if(-1 == iRet)
{
debugLog("d:\My_logs.txt", "create process failed!");
break;
}
}
HANDLE handles[2];
handles[0] = pi.hProcess;
handles[1] = g_ServiceStopEvent;
DWORD dwRet = WaitForMultipleObjects(2, handles, false, INFINITE);
if(WAIT_OBJECT_0 == dwRet)
{
debugLog("d:\My_logs.txt", "My server down");
isMyStarted = 0;
continue;
}
if(WAIT_OBJECT_0 + 1 == dwRet)
{
//debugLog("d:\My_logs.txt", "Service stop received");
if(pi.hProcess != NULL)
{
//debugLog("d:\My_logs.txt", "KIlling!! ",pi.dwProcessId);
if(!TerminateProcess(pi.hProcess, 0))
{
DWORD err = ::GetLastError();
debugLog("d:\My_logs.txt", "Terminate err ", err);
}
}
return ERROR_SUCCESS;
}
}
return -1;
}


/********************************************************************************
Function Name : createProcess
Input parameter : None
Output Parameter : None
Return value : int 0/-1: 0 if createProcess succeeds
: : -1 if createProcess fails
Description : creates child process that will start the required java process.
*********************************************************************************/
int createProcess()
{
char *pcEnv = NULL;
char *pcEnvLan = NULL;
std::string commandLineStr;

pcEnv = getenv("GEHC_SECURITY_HOME");
si.cb = sizeof(si);
pcEnvLan = getenv("GEHC_SEC_LANG");
debugLog("d:\My_logs.txt",pcEnv);

if(pcEnv == NULL || pcEnvLan == NULL)
{
debugLog("d:\My_logs.txt", "Environment GEHC_SECURITY_HOME not set");
//g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus.dwWin32ExitCode = 0;
g_ServiceStatus.dwCheckPoint = 4;

if(SetServiceStatus(g_StatusHandle, &g_ServiceStatus) == FALSE)
{
debugLog("d:\My_logs.txt", "Unable to set event in line ");
fclose(fp);
}
return -1;
}
std ::string str(pcEnv);
std :: string str1(pcEnvLan);


commandLineStr =
commandLineStr + "java -cp "
+" -Dterra.My1.model=CLIENT_SERVER com.ge.med.terra.eaaa.server.MyServer %*";

char *pcStr = new char[commandLineStr.length() + 1];

strcpy(pcStr, commandLineStr.c_str());
debugLog("d:\My_logs.txt", pcStr);
int iRet = createProcess(NULL, // No module name (use command line)
(LPTSTR)pcStr, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation Flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi);
if(iRet == 0)
{
DWORD dw = GetLastError();
debugLog("d:\My_logs.txt","createfailed", dw);
delete[] pcStr;
return -1;
}
debugLog("d:\My_logs.txt", "Process started: ",pi.dwProcessId);
return 0;
}

/********************************************************************************
Function Name : ServiceMain
Input parameter : DWORD argc, LPTSTR *argv
Output Parameter : None
Return value : void
Description : Main function responsible for registering the service
control handler with service control manager and
creates worker thread.
*********************************************************************************/
VOID WINAPI ServiceMain1(DWORD argc, LPTSTR *argv)
{
DWORD Status = E_FAIL;

// Register our service control handler with the SCM
g_StatusHandle1 = RegisterServiceCtrlHandler(My1_SERVICE_NAME, ServiceCtrlHandler);

if(g_StatusHandle1 == NULL)
{
goto EXIT;
}

// Tell the service controller we are starting
ZeroMemory(&g_ServiceStatus1, sizeof(g_ServiceStatus1));
g_ServiceStatus1.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
//g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus1.dwCurrentState = SERVICE_START_PENDING;
g_ServiceStatus1.dwWin32ExitCode = 0;
g_ServiceStatus1.dwServiceSpecificExitCode = 0;
g_ServiceStatus1.dwCheckPoint = 0;

if(SetServiceStatus(g_StatusHandle1, &g_ServiceStatus1) == FALSE)
{
OutputDebugString(
_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}

/*
* Perform tasks necessary to start the service here
*/

// create a service stop event to wait on later
g_ServiceStopEvent1 = createEvent(NULL, TRUE, FALSE, NULL);
if(g_ServiceStopEvent1 == NULL)
{
// Error creating event
// Tell service controller we are stopped and exit
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus1.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus1.dwWin32ExitCode = GetLastError();
g_ServiceStatus1.dwCheckPoint = 1;

if(SetServiceStatus(g_StatusHandle1, &g_ServiceStatus1) == FALSE)
{
OutputDebugString(
_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}
goto EXIT;
}

// Tell the service controller we are started
//g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus1.dwCurrentState = SERVICE_RUNNING;
g_ServiceStatus1.dwWin32ExitCode = 0;
g_ServiceStatus1.dwCheckPoint = 0;

if(SetServiceStatus(g_StatusHandle1, &g_ServiceStatus1) == FALSE)
{
OutputDebugString(
_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}

// Start a thread that will perform the main task of the service
debugLog("d:\My1_logs.txt", "starting worker thread");
HANDLE hThread = createThread(NULL, 0, ServiceWorkerThread, NULL, 0, NULL);

// Wait until our worker thread exits signaling that the service needs to stop
WaitForSingleObject(hThread, INFINITE);

/*
* Perform any cleanup tasks
*/

CloseHandle(g_ServiceStopEvent1);

// Tell the service controller we are stopped
//g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus1.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus1.dwWin32ExitCode = 0;
g_ServiceStatus1.dwCheckPoint = 3;

if(SetServiceStatus(g_StatusHandle1, &g_ServiceStatus1) == FALSE)
{
OutputDebugString(
_T("My Sample Service: ServiceMain: SetServiceStatus returned error"));
}

EXIT: return;
}

VOID WINAPI ServiceCtrlHandler1(DWORD CtrlCode)
{
switch(CtrlCode)
{
case SERVICE_CONTROL_STOP:

if(g_ServiceStatus1.dwCurrentState != SERVICE_RUNNING)
break;

/*
* Perform tasks necessary to stop the service here
*/
//g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus1.dwCurrentState = SERVICE_STOPPED;
g_ServiceStatus1.dwWin32ExitCode = 0;
g_ServiceStatus1.dwCheckPoint = 4;

if(SetServiceStatus(g_StatusHandle1, &g_ServiceStatus1) == FALSE)
{
debugLog("d:\My_logs.txt", "My1:Service Stop err");
}
// This will signal the worker thread to start shutting down
if(! SetEvent(g_ServiceStopEvent1))
{
debugLog("d:\My_logs.txt", "My1:Not Stopped Service ");
}
else
{
debugLog("d:\My_logs.txt", "My1: Stopped Service ");
}
break;
default:
break;
}
}

/********************************************************************************
Function Name : ServiceWorkerThread
Input parameter : LPVOID lpParam
Output Parameter : None
Return value : DWORD ERROR_SUCCESS/ERROR_FAIL
Description : Worker thread that does actual processing i.e. starts
My1 process and checks if the My1 process is killed, if killed it will
start process again
*********************************************************************************/
DWORD WINAPI ServiceWorkerThread1(LPVOID lpParam)
{
while(true)
{
if(0 == isMy1Started)
{
int iRet = createProcess();
isMy1Started = 1;
if(-1 == iRet)
{
debugLog("d:\My_logs.txt", "create process failed!");
break;
}
}
HANDLE handles[2];
handles[0] = pi1.hProcess;
handles[1] = g_ServiceStopEvent1;
DWORD dwRet = WaitForMultipleObjects(2, handles, false, INFINITE);
if(WAIT_OBJECT_0 == dwRet)
{
debugLog("d:\My_logs.txt", "My server down");
isMy1Started = 0;
continue;
}
if(dwRet == WAIT_OBJECT_0 + 1)
{
//debugLog("d:\My_logs.txt", "Service stop received");
if(pi1.hProcess != NULL)
{
if(!TerminateProcess(pi1.hProcess, 0))
{
DWORD err = ::GetLastError();
debugLog("d:\My_logs.txt", "Terminate err ", err);
}
}
return ERROR_SUCCESS;
}
}
return -1;
}

/********************************************************************************
Function Name : createProcess
Input parameter : None
Output Parameter : None
Return value : int 0/-1: 0 if createProcess succeeds
: : -1 if createProcess fails
Description : creates child process that will start the required java process.
*********************************************************************************/
int createProcess1()
{
char *pcEnv = NULL;
std::string commandLineStr;
pcEnv = getenv("GEHC_SECURITY_HOME");
si1.cb = sizeof(si1);

debugLog("d:\My_logs.txt",pcEnv);

if(pcEnv == NULL)
{
debugLog("d:\My_logs.txt", "Environment GEHC_SECURITY_HOME not set");
//g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN;
g_ServiceStatus1.dwControlsAccepted = SERVICE_ACCEPT_STOP;
g_ServiceStatus1.dwCurrentState = SERVICE_STOP_PENDING;
g_ServiceStatus1.dwWin32ExitCode = 0;
g_ServiceStatus1.dwCheckPoint = 4;

if(SetServiceStatus(g_StatusHandle1, &g_ServiceStatus1) == FALSE)
{
debugLog("d:\My_logs.txt", "Unable to set event in line ");
fclose(fp);
}
return -1;
}
std::string str(pcEnv);
commandLineStr =
commandLineStr + "java -cp "
+ " com.ge.med.terra.server.myServer %*";
char *pcStr = new char[commandLineStr.length() + 1];
strcpy(pcStr, commandLineStr.c_str());
debugLog("d:\My_logs.txt", pcStr);

int iRet = CreateProcess( NULL, // No module name (use command line)
(LPTSTR)pcStr, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation Flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si1, // Pointer to STARTUPINFO structure
&pi1);
if(iRet == 0)
{
return -1;
}
debugLog("d:\My_logs.txt", "Process started: ",pi1.dwProcessId);
return 0;
}
void debugLog(const char* fileName, const char *str, int value)
{
fp = fopen(fileName, "a");
fprintf(fp, "%s%i\n", str, value);
fclose(fp);
}

void debugLog(const char* fileName, const char *str)
{
fp = fopen(fileName, "a");
fputs(str, fp);
fputs("\n", fp);
fclose(fp);
}

int main()
{

SERVICE_TABLE_ENTRY ServiceTable[] = { { My_SERVICE_NAME,
(LPSERVICE_MAIN_FUNCTION) ServiceMain }, { My1_SERVICE_NAME,
(LPSERVICE_MAIN_FUNCTION) ServiceMain1 },{ NULL, NULL } };

if(StartServiceCtrlDispatcher(ServiceTable) == FALSE)
{
return GetLastError();
}

return 0;
}
Adam Sawicki
2016-04-13 20:26:41
I'm sorry but I don't have time to analyze your code - I have my own code and bugs to fix.

Post comment

Nick *
Your name or nickname
E-mail
Your contact information (optional, will not be shown)
Text *
Content of your comment
Calculate *
(* - required field)
STAT NO AD [Stat] [Admin] [STAT NO AD] [pub] [Mirror] Copyright © 2004-2017 Adam Sawicki
Copyright © 2004-2017 Adam Sawicki