1 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
2 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
3 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
6 // Copyright (C) 1993-1997 Microsoft Corporation. All Rights Reserved.
10 // PURPOSE: Implements functions required by all services
14 // main(int argc, char **argv);
15 // service_ctrl(DWORD dwCtrlCode);
16 // service_main(DWORD dwArgc, LPTSTR *lpszArgv);
17 // CmdInstallService();
18 // CmdRemoveService();
19 // ControlHandler ( DWORD dwCtrlType );
20 // GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
24 // AUTHOR: Craig Link - Microsoft Developer Support
28 * modified Mar.07, 2002 by Feng Qin <fqin@ncsa.uiuc.edu>
31 * removed some functions we don't use at all
32 * add code to start the service immediately after service is installed
34 * $Id: service.c,v 1.1.1.1 2004/05/18 01:50:44 kgibbs Exp $
49 SERVICE_STATUS ssStatus; // current status of the service
50 SERVICE_STATUS_HANDLE sshStatusHandle;
55 // FUNCTION: service_main
57 // PURPOSE: To perform actual initialization of the service
60 // dwArgc - number of command line arguments
61 // lpszArgv - array of command line arguments
67 // This routine performs the service initialization and then calls
68 // the user defined ServiceStart() routine to perform majority
71 void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv) {
72 // register our service control handler:
74 sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
76 if ( !sshStatusHandle )
79 // SERVICE_STATUS members that don't change in example
81 ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
82 ssStatus.dwServiceSpecificExitCode = 0;
84 // report the status to the service control manager.
86 if ( !ReportStatusToSCMgr(
87 SERVICE_START_PENDING, // service state
88 NO_ERROR, // exit code
93 ServiceStart( dwArgc, lpszArgv );
97 // try to report the stopped status to the service control manager.
99 if ( sshStatusHandle )
100 (VOID)ReportStatusToSCMgr(
111 // FUNCTION: service_ctrl
113 // PURPOSE: This function is called by the SCM whenever
114 // ControlService() is called on this service.
117 // dwCtrlCode - type of control requested
124 VOID WINAPI service_ctrl(DWORD dwCtrlCode) {
125 // Handle the requested control code.
127 switch ( dwCtrlCode ) {
130 // SERVICE_STOP_PENDING should be reported before
131 // setting the Stop Event - hServerStopEvent - in
132 // ServiceStop(). This avoids a race condition
133 // which may result in a 1053 - The Service did not respond...
135 case SERVICE_CONTROL_STOP:
136 ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
141 // Update the service status.
143 case SERVICE_CONTROL_INTERROGATE:
146 // invalid control code
152 ReportStatusToSCMgr(SERVICE_STOPPED, NO_ERROR, 0);
153 // ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
159 // FUNCTION: ReportStatusToSCMgr()
161 // PURPOSE: Sets the current status of the service and
162 // reports it to the Service Control Manager
165 // dwCurrentState - the state of the service
166 // dwWin32ExitCode - error code to report
167 // dwWaitHint - worst case estimate to next checkpoint
175 BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
176 DWORD dwWin32ExitCode,
178 static DWORD dwCheckPoint = 1;
182 if ( dwCurrentState == SERVICE_START_PENDING )
183 ssStatus.dwControlsAccepted = 0;
185 ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
187 ssStatus.dwCurrentState = dwCurrentState;
188 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
189 ssStatus.dwWaitHint = dwWaitHint;
191 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
192 ( dwCurrentState == SERVICE_STOPPED ) )
193 ssStatus.dwCheckPoint = 0;
195 ssStatus.dwCheckPoint = dwCheckPoint++;
198 // Report the status of the service to the service control manager.
200 if ( !(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)) ) {
201 AddToMessageLog(TEXT("SetServiceStatus"));
209 // FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
211 // PURPOSE: Allows any thread to log an error message
214 // lpszMsg - text for message
221 VOID AddToMessageLog(LPTSTR lpszMsg) {
224 LPTSTR lpszStrings[2];
227 dwErr = GetLastError();
229 // Use event logging to log the error.
231 hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
235 _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
236 lpszStrings[0] = szMsg;
237 lpszStrings[1] = lpszMsg;
239 if ( hEventSource != NULL ) {
240 ReportEvent(hEventSource, // handle of event source
241 EVENTLOG_ERROR_TYPE, // event type
244 NULL, // current user's SID
245 2, // strings in lpszStrings
246 0, // no bytes of raw data
247 lpszStrings, // array of error strings
248 NULL); // no raw data
250 (VOID) DeregisterEventSource(hEventSource);
257 ///////////////////////////////////////////////////////////////////
259 // The following code handles service installation and removal
262 // FUNCTION: CmdInstallService()
264 // PURPOSE: Installs the service and Starts it
267 // argc: number of arguments
268 // argv: all of the arguments including the program's name
275 void CmdInstallService(int argc, char **argv) {
276 SC_HANDLE schService;
277 SC_HANDLE schSCManager;
281 if ( GetModuleFileName( NULL, szPath, 512 ) == 0 ) {
282 _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
286 schSCManager = OpenSCManager(
287 NULL, // machine (NULL == local)
288 NULL, // database (NULL == default)
289 SC_MANAGER_ALL_ACCESS // access required
291 if ( schSCManager ) {
292 schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
294 schService = CreateService(
295 schSCManager, // SCManager database
296 TEXT(SZSERVICENAME), // name of service
297 TEXT(SZSERVICEDISPLAYNAME), // name to display
298 SERVICE_ALL_ACCESS, // desired access
299 SERVICE_WIN32_OWN_PROCESS, // service type
300 SERVICE_DEMAND_START, // start type
301 SERVICE_ERROR_NORMAL, // error control type
302 szPath, // service's binary
303 NULL, // no load ordering group
304 NULL, // no tag identifier
305 TEXT(SZDEPENDENCIES), // dependencies
306 NULL, // LocalSystem account
307 NULL); // no password
309 _tprintf(TEXT("%s already installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
312 if ( QueryServiceStatus( schService, &ssStatus ) ) {
314 if ( ssStatus.dwCurrentState == SERVICE_STOPPED ) {
315 rc = StartService(schService, argc-1, argv+1);
320 _tprintf(TEXT("%s started.\n"), TEXT(SZSERVICEDISPLAYNAME) );
323 CloseServiceHandle(schService);
325 _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
328 CloseServiceHandle(schSCManager);
330 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
338 // FUNCTION: CmdRemoveService()
340 // PURPOSE: Stops and removes the service
346 // TRUE: service exists and is removed
347 // FALSE: service doesn't exist
351 BOOL CmdRemoveService() {
352 BOOL isExist = FALSE;
353 SC_HANDLE schService;
354 SC_HANDLE schSCManager;
356 schSCManager = OpenSCManager(
357 NULL, // machine (NULL == local)
358 NULL, // database (NULL == default)
359 SC_MANAGER_ALL_ACCESS // access required
361 if ( schSCManager ) {
362 schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
366 // try to stop the service
367 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) ) {
368 _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
371 while ( QueryServiceStatus( schService, &ssStatus ) ) {
372 if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING ) {
379 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
380 _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
382 _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
386 // now remove the service
387 if ( DeleteService(schService) )
388 _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
390 _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
393 CloseServiceHandle(schService);
396 CloseServiceHandle(schSCManager);
398 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
404 // FUNCTION: CmdStartService()
406 // PURPOSE: Start service if it exists
409 // argc: number of arguments
410 // argv: arguments including program's name
413 // TRUE: service exists and is started
414 // FALSE: service doesn't exist
418 BOOL CmdStartService(int argc, char **argv) {
419 BOOL isExist = FALSE;
420 SC_HANDLE schService;
421 SC_HANDLE schSCManager;
423 schSCManager = OpenSCManager(
424 NULL, // machine (NULL == local)
425 NULL, // database (NULL == default)
426 SC_MANAGER_ALL_ACCESS // access required
428 if ( schSCManager ) {
429 schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
433 if ( QueryServiceStatus( schService, &ssStatus ) ) {
435 if ( ssStatus.dwCurrentState == SERVICE_STOPPED ) {
436 rc = StartService(schService, argc-1, argv+1);
441 _tprintf(TEXT("%s started.\n"), TEXT(SZSERVICEDISPLAYNAME) );
443 CloseServiceHandle(schService);
445 CloseServiceHandle(schSCManager);
447 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
456 // FUNCTION: GetLastErrorText
458 // PURPOSE: copies error message text to string
461 // lpszBuf - destination buffer
462 // dwSize - size of buffer
465 // destination buffer
469 LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize ) {
471 LPTSTR lpszTemp = NULL;
473 dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
481 // supplied buffer is not long enough
482 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
483 lpszBuf[0] = TEXT('\0');
485 lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
486 _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
490 LocalFree((HLOCAL) lpszTemp );