Click here to Skip to main content
15,888,527 members
Articles / Desktop Programming / ATL
Article

CREATING MULTIPLE WINDOW SERVICES USING INI CONFIG FILE

Rate me:
Please Sign up or sign in to vote.
4.09/5 (5 votes)
11 Mar 20063 min read 43K   494   25   5
MULTIPLE WINDOW SERVICES

Sample Image - multiservices.jpg

Introduction

This project demonstrates how one can configure a windows service to run as multiple services. I discovered that very little code is needed to make the basic ATL Service project that is created using the Visual Studio Wizard into a project that could create and run multiple services using the same executable. For my example I’m only going to create 3 services.

I spent a week trying to come up with a solution to my problem by looking at other code examples to no avail with every example using hard coded multiple service names in the SERVICE_TABLE_ENTRY table which was not an option for me. My example makes it very simple to create and run as many window services that the Service Component Manager can handle using the same executable and an INI file for each service you want to create. I even demonstrate that each service is running its own INI file by writing out to the Event Viewer log the name of the service running and its INI file.

To get started the _tWinMain method was modified to take a second argument for installing and uninstalling a windows service which would be a fully qualified path to an INI file. This is the backbone of the whole project and is used to create the service name by reading the SERVICENAME setting from the INI file and appending it to the project name which in this case is “ThisIs”. The INI file path is also stored in the registry for the service created and is reloaded in the ServiceMain when the service is started . I’m sure someone will come up with an alternative solution of passing any old name instead of an INI file path for the second argument which is fine depending on your environment.

All of my code changes are tagged as "//DG" and be sure to uninstall a service before recompiling a new build or it will stay in a "Performing registration" mode until you kill the process in task manager.

First step is to include the windows.h header file and two global variables used during service registration and for the creation of a service name at the top of the ThisIs.cpp file. We need this so we can read the INI files and also to read and write to the registry

#include "stdafx.h"
#include "resource.h"
#include <INITGUID.H>
#include "ThisIs.h"
#include <windows.h>	//DG
#include "ThisIs_i.c"

#include <stdio.h>

CServiceModule _Module;

char configfile[100];	//DG
char sServiceName[30];	//DG

BEGIN_OBJECT_MAP(ObjectMap)
END_OBJECT_MAP()

Second we need to modify the default _tWinMain created by the ATL wizard to Accept our second argument which will be the full path to our INI config file.

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, 
    HINSTANCE /*hPrevInstance*/, LPTSTR lpCmdLine, int /*nShowCmd*/)
{
    
	/* USAGE SECTION 
		
	  TO INSTALL SERVICEA
		
		  thisis -install C:\ThisIs\ServiceA.ini

		  (This will create a service called ThisIsServiceA"

	  TO INSTALL SERVICEB
		
		  thisis -install C:\ThisIs\ServiceB.ini

		  (This will create a service called ThisIsServiceB"

	  TO INSTALL SERVICEC
		
		  thisis -install C:\ThisIs\ServiceC.ini

		  (This will create a service called ThisIsServiceC"
	  
	  TO UNINSTALL SERVICEA
		  
		  thisis -uninstall C:\ThisIs\ServiceA.ini


	  Please note that the SERVICENAME in the ini file is appended to the project name
	  so when you open up the Services window in Administrative Tools you should see
	  a service called "ThisIsServiceA" if you run the "thisis -install C:\ThisIs\ServiceA.ini"
	  command from a DOS prompt.
	*/
	
	lpCmdLine = GetCommandLine(); //this line necessary for _ATL_MIN_CRT
    _Module.Init(ObjectMap, hInstance, IDS_SERVICENAME, &LIBID_THISISLib);
    _Module.m_bService = TRUE;
	
    TCHAR szTokens[] = _T("-/");
	
	//lpCmdLine = "-install C:\\ThisIs\\ServiceA.ini";

    LPCTSTR lpszToken = FindOneOf(lpCmdLine, szTokens);

    while (lpszToken != NULL)
    {
        if (memcmp(lpszToken, "uninstall",9)==0)	//DG
		{
            strcpy(configfile,lpszToken + 10);		//DG

			if(strlen(configfile) <= 0)				//DG
			{
				MessageBox(NULL, _T("You didn't specify a config file argument."), "ThisIs", MB_OK);
				return 0;
			}
			
			_Module.LoadConfigSettings();			//DG
			strcat(_Module.m_szServiceName,sServiceName);	//DG

			if (strlen(sServiceName) == 0)			//DG
			{
				MessageBox(NULL, _T("Unable to read SERVICENAME key in config file."), "ThisIs", MB_OK);
				return 0;
			}
			
			return _Module.UnregisterServer();
		}

        // Register as Local Server
        if (memcmp(lpszToken, "regserver",9)==0)	//DG
		{
            strcpy(configfile,lpszToken + 10);		//DG

			if(strlen(configfile) <= 0)				//DG
			{
				MessageBox(NULL, _T("You didn't specify a config file argument."), "ThisIs", MB_OK);
				return 0;
			}	
			
			_Module.LoadConfigSettings();			//DG
			strcat(_Module.m_szServiceName,sServiceName);	//DG

			if (strlen(sServiceName) == 0)			//DG
			{
				MessageBox(NULL, _T("Unable to read SERVICENAME key in config file."), "ThisIs", MB_OK);
				return 0;
			}
			
			return _Module.RegisterServer(TRUE, FALSE);
		}
        
        // Register as Service
        if (memcmp(lpszToken, "install",7)==0)		//DG
		{
            strcpy(configfile,lpszToken + 8);		//DG

			if(strlen(configfile) <= 0)				//DG
			{
				MessageBox(NULL, _T("You didn't specify a config file argument."), "ThisIs", MB_OK);
				return 0;
			}
			
			_Module.LoadConfigSettings();			//DG
			strcat(_Module.m_szServiceName,sServiceName);	//DG

			if (strlen(sServiceName) == 0)			//DG
			{
				MessageBox(NULL, _T("Unable to read SERVICENAME key in config file."), "ThisIs", MB_OK);
				return 0;
			}

			return _Module.RegisterServer(TRUE, TRUE);
		}
        
        lpszToken = FindOneOf(lpszToken, szTokens);
    }

    // Are we Service or Local Server
    CRegKey keyAppID;
    LONG lRes = keyAppID.Open(HKEY_CLASSES_ROOT, _T("AppID"), KEY_READ);
    
	if (lRes != ERROR_SUCCESS)
        return lRes;

    CRegKey key;
    lRes = key.Open(keyAppID, _T("{0D327CD4-741C-4E5D-BD84-4DB303595E0A}"), KEY_READ);
    
	if (lRes != ERROR_SUCCESS)
        return lRes;

    TCHAR szValue[_MAX_PATH];
    DWORD dwLen = _MAX_PATH;
    lRes = key.QueryValue(szValue, _T("LocalService"), &dwLen);

    _Module.m_bService = FALSE;

    if (lRes == ERROR_SUCCESS)
        _Module.m_bService = TRUE;
	
	_Module.Start();	

    // When we get here, the service has been stopped
    return _Module.m_status.dwWin32ExitCode;
}

Next we need to add some code to the Install() function so we can create a new registry hive location called Parameters so we can save the path of our INI file for the service we're going to install.

inline BOOL CServiceModule::Install()
{
    
	char regpath[200];	//DG

	if (IsInstalled())
        return TRUE;

    SC_HANDLE hSCM = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hSCM == NULL)
    {
        MessageBox(NULL, _T("Couldn't open service manager"), m_szServiceName, MB_OK);
        return FALSE;
    }

    // Get the executable file path
    TCHAR szFilePath[_MAX_PATH];
    ::GetModuleFileName(NULL, szFilePath, _MAX_PATH);

    SC_HANDLE hService = ::CreateService(
        hSCM, m_szServiceName, m_szServiceName,
        SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
        SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
        szFilePath, NULL, NULL, _T("RPCSS\0"), NULL, NULL);

    if (hService == NULL)
    {
        ::CloseServiceHandle(hSCM);
        MessageBox(NULL, _T("Couldn't create service"), m_szServiceName, MB_OK);
        return FALSE;
    }

    ::CloseServiceHandle(hService);
    ::CloseServiceHandle(hSCM);
	
	/*DG BEGIN save config file path to registry*/
	DWORD maxlen = 100;											

	strcpy(regpath,"SYSTEM\\CurrentControlSet\\Services\\");	
	strcat(regpath,m_szServiceName);							
	strcat(regpath,"\\Parameters");								

	CRegKey keyAppID;											
	keyAppID.Create(HKEY_LOCAL_MACHINE,_T(regpath));
	keyAppID.SetValue(configfile, "CONFIGFILE");
	/*DG END*/

    return TRUE;
}

Next we need to declare the LoadConfigSettings routine for reading values from our INI file in the CServiceModule class module in the StdAfx.h.

class CServiceModule : public CComModule
{
public:
	HRESULT RegisterServer(BOOL bRegTypeLib, BOOL bService);
	HRESULT UnregisterServer();
	void Init(_ATL_OBJMAP_ENTRY* p, HINSTANCE h, UINT nServiceNameID, const GUID* plibid = NULL);
    void Start();
	void ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv);
    void Handler(DWORD dwOpcode);
    void Run();
    BOOL IsInstalled();
    BOOL Install();
    BOOL Uninstall();
	LONG Unlock();
	void LogEvent(LPCTSTR pszFormat, ...);
    void SetServiceStatus(DWORD dwState);
    void SetupAsLocalServer();
	void LoadConfigSettings(); //DG

//Implementation
private:
	static void WINAPI _ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv);
    static void WINAPI _Handler(DWORD dwOpcode);

// data members
public:
    TCHAR m_szServiceName[256];
    SERVICE_STATUS_HANDLE m_hServiceStatus;
    SERVICE_STATUS m_status;
	DWORD dwThreadID;
	BOOL m_bService;
};

extern CServiceModule _Module;
#include <ATLCOM.H>

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_STDAFX_H__D0A5ADBC_7B3A_4E70_9027_BD4E9D5562D5__INCLUDED)

Next step we add the LoadConfigSettings routine to the ThisIs.cpp file

void CServiceModule::LoadConfigSettings()	//DG
{
	char szDefault[255];
	GetPrivateProfileString("MAIN", "SERVICENAME", szDefault, sServiceName, 255, configfile); 
	/* Continue to add more entries as needed to read INI file settings */
}

Now here is where we come to the most important part and the key to the whole process of getting multiple services to run. As far as the service executable is concerned it thinks it is called "ThisIs" but we're going to change it's internal run time Service Name and give it a new alias within the ServiceMain routine upon startup by changing the internal public variable m_szServiceName to the name of the running service. All of the code generated by the ATL service wizard is dependent upon this variable so by modifying it you force the entire application to fall in line.

To understand what i'm saying you need to know that the first argument passed in the ServiceMain argument array is the name of the service that was started.

inline void CServiceModule::ServiceMain(DWORD dwArgc , LPTSTR*  lpszArgv )	//DG
{
    
	/*DG BEGIN */
		char msg[200];	
		char regpath[200];	

		/*Set Internal m_szServiceName variable to whatever service was started*/
		strcpy(m_szServiceName,(char *)lpszArgv[0]);
		strcpy(sServiceName,m_szServiceName);

		DWORD maxlen = 100;											

		strcpy(regpath,"SYSTEM\\CurrentControlSet\\Services\\");	
		strcat(regpath,m_szServiceName);							
		strcat(regpath,"\\Parameters");								

		CRegKey keyAppID;											
		keyAppID.Create(HKEY_LOCAL_MACHINE,_T(regpath));
		keyAppID.QueryValue(configfile,"CONFIGFILE",&maxlen);

		//LoadConfigSettings();							//DG

		strcpy(msg,m_szServiceName);
		strcat(msg," is configured to run with INI file: ");
		strcat(msg,configfile);
		LogEvent(_T(msg));
	/*DG END*/

	// Register the control request handler
    m_status.dwCurrentState = SERVICE_START_PENDING;
    m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler);
    if (m_hServiceStatus == NULL)
    {
        LogEvent(_T("Handler not installed"));
        return;
    }
    SetServiceStatus(SERVICE_START_PENDING);

    m_status.dwWin32ExitCode = S_OK;
    m_status.dwCheckPoint = 0;
    m_status.dwWaitHint = 0;

    // When the Run function returns, the service has stopped.
    Run();

    SetServiceStatus(SERVICE_STOPPED);
    LogEvent(_T("Service stopped"));
}

And that's all folks!

In my production version I have a built in timer in the Run() function and a host of other routines to connect to databases which is where the INI file comes in or you can choose to save it all in the registry.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionunable to start multiple service using servicectrldispatcher Pin
Member 122020458-Apr-16 6:14
Member 122020458-Apr-16 6:14 
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

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_SHARE_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 " + "\""
+ str.c_str()+ "\\eat\\jar\\eat.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\iungo.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\HDX.jar\";" +"\""
+ str.c_str()+ "\\my\\jar\\HDXser.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\antlr-runtime-3.1.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\jstyleparser-1.16-BSD.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\slf4j-api-1.7.5.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\slf4j-jdk14-1.7.5.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\my.jar\";" + "\""
+ str.c_str()+ "\\my\\jar\\commons-codec-1.9.jar\""
+ " -DGEHC_SECURITY_HOME=" + "\"" +str.c_str() + "\""
+ " -DGEHC_SEC_LANG=" + str1.c_str()
+" -Dterra.eat.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);
debugLog("d:\my_logs.txt", "In main1: ");
if(g_StatusHandle1 == NULL)
{
goto EXIT;
}

// Tell the service controller we are starting
ZeroMemory(&g_ServiceStatus1, sizeof(g_ServiceStatus1));
g_ServiceStatus1.dwServiceType = SERVICE_WIN32_SHARE_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)
{
debugLog("d:\my_logs.txt", "int ctrl1: ");
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)
{
debugLog("d:\my_logs.txt", "in wrkr thrd1: ");
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 " + "\""
+ str.c_str()+ "/eat/jar/eat.jar\";" + "\""
+ str.c_str()+ "/eat/integration/eatsample.jar\";" + "\""
+ str.c_str()+"/eat/integration/eatTest.jar\";" +"\""
+ str.c_str()+ "/eat/3p/mail.jar\""
+ " -DGEHC_SECURITY_HOME=" + "/" +str.c_str() + "\""
+ " -DGEHC_SEC_LANG=%GEHC_SEC_LANG% -Dterra.eat.model=CLIENT_SERVER"
+ " com.ge.med.terra.eat.server.my1Server %*";
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;
}

modified 8-Apr-16 23:30pm.

Generalusing dll in window service Pin
shaeron14-Dec-06 20:02
shaeron14-Dec-06 20:02 
QuestionIncomplete? Pin
HobbitCoder13-Mar-06 2:14
HobbitCoder13-Mar-06 2:14 
AnswerRe: Incomplete? Pin
Diego Gil13-Mar-06 15:09
Diego Gil13-Mar-06 15:09 
GeneralRe: Incomplete? Pin
HobbitCoder13-Mar-06 23:53
HobbitCoder13-Mar-06 23:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.