ReactOS 0.4.16-dev-197-g92996da
service.c
Go to the documentation of this file.
1/*---------------------------------------------------------------------------
2THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
3ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
4TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5PARTICULAR PURPOSE.
6
7Copyright (C) Microsoft Corporation. All rights reserved.
8
9MODULE: service.c
10
11PURPOSE: Implements functions required by all Windows NT services
12
13FUNCTIONS:
14 main(int argc, char **argv);
15 service_ctrl(DWORD dwCtrlCode);
16 service_main(DWORD dwArgc, LPTSTR *lpszArgv);
17 CmdInstallService();
18 CmdRemoveService();
19 CmdDebugService(int argc, char **argv);
20 ControlHandler ( DWORD dwCtrlType );
21 GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
22
23 ---------------------------------------------------------------------------*/
24#include <windows.h>
25#ifndef STANDALONE_NFSD
26#include <stdio.h>
27#include <stdlib.h>
28#include <process.h>
29#include <tchar.h>
30
31#include "service.h"
32
33// internal variables
34SERVICE_STATUS ssStatus; // current status of the service
39
40// internal function prototypes
41VOID WINAPI service_ctrl(DWORD dwCtrlCode);
42VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
45VOID CmdDebugService(int argc, char **argv);
46BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
48
49//
50// FUNCTION: main
51//
52// PURPOSE: entrypoint for service
53//
54// PARAMETERS:
55// argc - number of command line arguments
56// argv - array of command line arguments
57//
58// RETURN VALUE:
59// none
60//
61// COMMENTS:
62// main() either performs the command line task, or
63// call StartServiceCtrlDispatcher to register the
64// main service thread. When the this call returns,
65// the service has stopped, so exit.
66//
67void __cdecl main(int argc, char **argv)
68{
69 SERVICE_TABLE_ENTRY dispatchTable[] =
70 {
72 { NULL, NULL}
73 };
74
75 if ( (argc > 1) &&
76 ((*argv[1] == '-') || (*argv[1] == '/')) )
77 {
78 if ( _stricmp( "install", argv[1]+1 ) == 0 )
79 {
81 }
82 else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
83 {
85 }
86 else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
87 {
88 bDebug = TRUE;
90 }
91 else
92 {
93 goto dispatch;
94 }
95 exit(0);
96 }
97
98 // if it doesn't match any of the above parameters
99 // the service control manager may be starting the service
100 // so we must call StartServiceCtrlDispatcher
101 dispatch:
102 // this is just to be friendly
103 printf( "%s -install to install the service\n", SZAPPNAME );
104 printf( "%s -remove to remove the service\n", SZAPPNAME );
105 printf( "%s -debug <params> to run as a console app for debugging\n", SZAPPNAME );
106 printf( "\nStartServiceCtrlDispatcher being called.\n" );
107 printf( "This may take several seconds. Please wait.\n" );
108
109 if (!StartServiceCtrlDispatcher(dispatchTable))
110 AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed."));
111}
112
113
114
115//
116// FUNCTION: service_main
117//
118// PURPOSE: To perform actual initialization of the service
119//
120// PARAMETERS:
121// dwArgc - number of command line arguments
122// lpszArgv - array of command line arguments
123//
124// RETURN VALUE:
125// none
126//
127// COMMENTS:
128// This routine performs the service initialization and then calls
129// the user defined ServiceStart() routine to perform majority
130// of the work.
131//
132void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
133{
134
135 // register our service control handler:
136 //
138
139 if (!sshStatusHandle)
140 goto cleanup;
141
142 // SERVICE_STATUS members that don't change in example
143 //
146
147
148 // report the status to the service control manager.
149 //
151 SERVICE_START_PENDING, // service state
152 NO_ERROR, // exit code
153 3000)) // wait hint
154 goto cleanup;
155
156 ServiceStart( dwArgc, lpszArgv );
157
158 cleanup:
159
160 // try to report the stopped status to the service control manager.
161 //
162 if (sshStatusHandle)
165 dwErr,
166 0);
167
168 return;
169}
170
171
172
173//
174// FUNCTION: service_ctrl
175//
176// PURPOSE: This function is called by the SCM whenever
177// ControlService() is called on this service.
178//
179// PARAMETERS:
180// dwCtrlCode - type of control requested
181//
182// RETURN VALUE:
183// none
184//
185// COMMENTS:
186//
188{
189 // Handle the requested control code.
190 //
191
192 switch (dwCtrlCode)
193 {
194 // Stop the service.
195 //
196 // SERVICE_STOP_PENDING should be reported before
197 // setting the Stop Event - hServerStopEvent - in
198 // ServiceStop(). This avoids a race condition
199 // which may result in a 1053 - The Service did not respond...
200 // error.
203 ServiceStop();
204 return;
205
206 // Update the service status.
207 //
209 break;
210
211 // invalid control code
212 //
213 default:
214 break;
215
216 }
217
219}
220
221
222
223//
224// FUNCTION: ReportStatusToSCMgr()
225//
226// PURPOSE: Sets the current status of the service and
227// reports it to the Service Control Manager
228//
229// PARAMETERS:
230// dwCurrentState - the state of the service
231// dwWin32ExitCode - error code to report
232// dwWaitHint - worst case estimate to next checkpoint
233//
234// RETURN VALUE:
235// TRUE - success
236// FALSE - failure
237//
238// COMMENTS:
239//
241 DWORD dwWin32ExitCode,
242 DWORD dwWaitHint)
243{
244 static DWORD dwCheckPoint = 1;
245 BOOL fResult = TRUE;
246
247
248 if ( !bDebug ) // when debugging we don't report to the SCM
249 {
250 if (dwCurrentState == SERVICE_START_PENDING)
252 else
254
255 ssStatus.dwCurrentState = dwCurrentState;
256 ssStatus.dwWin32ExitCode = dwWin32ExitCode;
257 ssStatus.dwWaitHint = dwWaitHint;
258
259 if ( ( dwCurrentState == SERVICE_RUNNING ) ||
260 ( dwCurrentState == SERVICE_STOPPED ) )
262 else
263 ssStatus.dwCheckPoint = dwCheckPoint++;
264
265
266 // Report the status of the service to the service control manager.
268 if (!fResult)
269 AddToMessageLog(TEXT("SetServiceStatus"));
270 }
271 return fResult;
272}
273
274
275
276//
277// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
278//
279// PURPOSE: Allows any thread to log an error message
280//
281// PARAMETERS:
282// lpszMsg - text for message
283//
284// RETURN VALUE:
285// none
286//
287// COMMENTS:
288//
290{
291 TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
292 HANDLE hEventSource;
293 LPTSTR lpszStrings[2];
294
295 if ( !bDebug )
296 {
298
299 // Use event logging to log the error.
300 //
301 hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
302
303#ifndef __REACTOS__
304 _stprintf_s(szMsg,(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
305#else
306 _sntprintf(szMsg,(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
307#endif
308 lpszStrings[0] = szMsg;
309 lpszStrings[1] = lpszMsg;
310
311 if (hEventSource != NULL)
312 {
313 ReportEvent(hEventSource, // handle of event source
314 EVENTLOG_ERROR_TYPE, // event type
315 0, // event category
316 0, // event ID
317 NULL, // current user's SID
318 2, // strings in lpszStrings
319 0, // no bytes of raw data
320 lpszStrings, // array of error strings
321 NULL); // no raw data
322
323 (VOID) DeregisterEventSource(hEventSource);
324 }
325 }
326}
327
328
329
330
332//
333// The following code handles service installation and removal
334//
335
336
337//
338// FUNCTION: CmdInstallService()
339//
340// PURPOSE: Installs the service
341//
342// PARAMETERS:
343// none
344//
345// RETURN VALUE:
346// none
347//
348// COMMENTS:
349//
351{
352 SC_HANDLE schService;
353 SC_HANDLE schSCManager;
354
355 TCHAR szPath[512];
356
357 if ( GetModuleFileName( NULL, szPath, 512 ) == 0 )
358 {
359 _tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
360 return;
361 }
362
363 schSCManager = OpenSCManager(
364 NULL, // machine (NULL == local)
365 NULL, // database (NULL == default)
367 );
368 if ( schSCManager )
369 {
370 schService = CreateService(
371 schSCManager, // SCManager database
372 TEXT(SZSERVICENAME), // name of service
373 TEXT(SZSERVICEDISPLAYNAME), // name to display
374 SERVICE_QUERY_STATUS, // desired access
375 SERVICE_WIN32_OWN_PROCESS, // service type
376 SERVICE_AUTO_START, // start type
377 SERVICE_ERROR_NORMAL, // error control type
378 szPath, // service's binary
379 NULL, // no load ordering group
380 NULL, // no tag identifier
381 TEXT(SZDEPENDENCIES), // dependencies
382 NULL, // LocalSystem account
383 NULL); // no password
384
385 if ( schService )
386 {
387 _tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
388 CloseServiceHandle(schService);
389 }
390 else
391 {
392 _tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
393 }
394
395 CloseServiceHandle(schSCManager);
396 }
397 else
398 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
399}
400
401
402
403//
404// FUNCTION: CmdRemoveService()
405//
406// PURPOSE: Stops and removes the service
407//
408// PARAMETERS:
409// none
410//
411// RETURN VALUE:
412// none
413//
414// COMMENTS:
415//
417{
418 SC_HANDLE schService;
419 SC_HANDLE schSCManager;
420
421 schSCManager = OpenSCManager(
422 NULL, // machine (NULL == local)
423 NULL, // database (NULL == default)
424 SC_MANAGER_CONNECT // access required
425 );
426 if ( schSCManager )
427 {
428 schService = OpenService(schSCManager, TEXT(SZSERVICENAME), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
429
430 if (schService)
431 {
432 // try to stop the service
433 if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
434 {
435 _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
436 Sleep( 1000 );
437
438 while ( QueryServiceStatus( schService, &ssStatus ) )
439 {
441 {
442 _tprintf(TEXT("."));
443 Sleep( 1000 );
444 }
445 else
446 break;
447 }
448
450 _tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
451 else
452 _tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
453
454 }
455
456 // now remove the service
457 if ( DeleteService(schService) )
458 _tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
459 else
460 _tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
461
462
463 CloseServiceHandle(schService);
464 }
465 else
466 _tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
467
468 CloseServiceHandle(schSCManager);
469 }
470 else
471 _tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
472}
473
474
475
476
478//
479// The following code is for running the service as a console app
480//
481
482
483//
484// FUNCTION: CmdDebugService(int argc, char ** argv)
485//
486// PURPOSE: Runs the service as a console application
487//
488// PARAMETERS:
489// argc - number of command line arguments
490// argv - array of command line arguments
491//
492// RETURN VALUE:
493// none
494//
495// COMMENTS:
496//
497void CmdDebugService(int argc, char ** argv)
498{
499 DWORD dwArgc;
500 LPTSTR *lpszArgv;
501
502#ifdef UNICODE
503 lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
504 if (NULL == lpszArgv)
505 {
506 // CommandLineToArvW failed!!
507 _tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
508 return;
509 }
510#else
511 dwArgc = (DWORD) argc;
512 lpszArgv = argv;
513#endif
514
515 _tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
516
518
519 ServiceStart( dwArgc, lpszArgv );
520
521#ifdef UNICODE
522// Must free memory allocated for arguments
523
524 GlobalFree(lpszArgv);
525#endif // UNICODE
526
527}
528
529
530//
531// FUNCTION: ControlHandler ( DWORD dwCtrlType )
532//
533// PURPOSE: Handled console control events
534//
535// PARAMETERS:
536// dwCtrlType - type of control event
537//
538// RETURN VALUE:
539// True - handled
540// False - unhandled
541//
542// COMMENTS:
543//
545{
546 switch ( dwCtrlType )
547 {
548 case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
549 case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
550 _tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
551 ServiceStop();
552 return TRUE;
553 break;
554
555 }
556 return FALSE;
557}
558
559//
560// FUNCTION: GetLastErrorText
561//
562// PURPOSE: copies error message text to string
563//
564// PARAMETERS:
565// lpszBuf - destination buffer
566// dwSize - size of buffer
567//
568// RETURN VALUE:
569// destination buffer
570//
571// COMMENTS:
572//
574{
575 DWORD dwRet;
576 LPTSTR lpszTemp = NULL;
577
579 NULL,
580 GetLastError(),
582 (LPTSTR)&lpszTemp,
583 0,
584 NULL );
585
586 // supplied buffer is not long enough
587 if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
588 lpszBuf[0] = TEXT('\0');
589 else
590 {
591 if (NULL != lpszTemp)
592 {
593 lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
594#ifndef __REACTOS__
595 _stprintf_s( lpszBuf, dwSize, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
596#else
597 _sntprintf( lpszBuf, dwSize, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
598#endif
599 }
600 }
601
602 if ( NULL != lpszTemp )
603 LocalFree((HLOCAL) lpszTemp );
604
605 return lpszBuf;
606}
607#endif
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
static int argc
Definition: ServiceArgs.c:12
#define __cdecl
Definition: accygwin.h:79
#define VOID
Definition: acefi.h:82
void dispatch(HANDLE hStopEvent)
Definition: dispatch.c:70
BOOL WINAPI ControlHandler(DWORD dwCtrlType)
Definition: service.c:544
SERVICE_STATUS ssStatus
Definition: service.c:34
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
Definition: service.c:240
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: service.c:132
BOOL bDebug
Definition: service.c:37
VOID CmdInstallService()
Definition: service.c:350
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
Definition: service.c:187
TCHAR szErr[256]
Definition: service.c:38
DWORD dwErr
Definition: service.c:36
VOID AddToMessageLog(LPTSTR lpszMsg)
Definition: service.c:289
VOID CmdDebugService(int argc, char **argv)
Definition: service.c:497
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
Definition: service.c:573
SERVICE_STATUS_HANDLE sshStatusHandle
Definition: service.c:35
VOID CmdRemoveService()
Definition: service.c:416
#define _stricmp
Definition: cat.c:22
#define NO_ERROR
Definition: dderror.h:5
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
BOOL WINAPI DeregisterEventSource(IN HANDLE hEventLog)
Definition: eventlog.c:473
static void cleanup(void)
Definition: main.c:1335
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Definition: console.c:2109
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2019
int main()
Definition: test.c:6
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
#define printf
Definition: freeldr.h:97
HGLOBAL NTAPI GlobalFree(HGLOBAL hMem)
Definition: heapmem.c:611
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1594
#define _tprintf
Definition: tchar.h:506
#define TEXT(s)
Definition: k32.h:26
LPCWSTR szPath
Definition: env.c:37
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:56
#define argv
Definition: mplay32.c:18
VOID ServiceStop()
Definition: nfs41_daemon.c:156
VOID ServiceStart(DWORD argc, LPTSTR *argv)
Definition: nfs41_daemon.c:381
#define DELETE
Definition: nt_native.h:57
#define DWORD
Definition: nt_native.h:44
BOOL WINAPI QueryServiceStatus(SC_HANDLE hService, LPSERVICE_STATUS lpServiceStatus)
Definition: scm.c:2845
BOOL WINAPI DeleteService(SC_HANDLE hService)
Definition: scm.c:921
BOOL WINAPI ControlService(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus)
Definition: scm.c:622
BOOL WINAPI CloseServiceHandle(SC_HANDLE hSCObject)
Definition: scm.c:580
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:997
#define LANG_NEUTRAL
Definition: nls.h:22
#define exit(n)
Definition: config.h:202
#define SZSERVICENAME
Definition: service.h:67
#define SZSERVICEDISPLAYNAME
Definition: service.h:69
#define SZDEPENDENCIES
Definition: service.h:71
#define SZAPPNAME
Definition: service.h:65
LPWSTR *WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int *numargs)
Definition: shell32_main.c:79
DWORD dwServiceType
Definition: winsvc.h:99
DWORD dwWin32ExitCode
Definition: winsvc.h:102
DWORD dwControlsAccepted
Definition: winsvc.h:101
DWORD dwWaitHint
Definition: winsvc.h:105
DWORD dwCurrentState
Definition: winsvc.h:100
DWORD dwCheckPoint
Definition: winsvc.h:104
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
#define FormatMessage
Definition: winbase.h:3819
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define ReportEvent
Definition: winbase.h:3923
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:448
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:444
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:449
#define lstrlen
Definition: winbase.h:3900
#define RegisterEventSource
Definition: winbase.h:3918
#define GetModuleFileName
Definition: winbase.h:3855
#define CTRL_C_EVENT
Definition: wincon.h:68
#define CTRL_BREAK_EVENT
Definition: wincon.h:69
#define WINAPI
Definition: msvc.h:6
#define EVENTLOG_ERROR_TYPE
Definition: winnt_old.h:2834
#define SERVICE_STOPPED
Definition: winsvc.h:21
#define SERVICE_ACCEPT_STOP
Definition: winsvc.h:28
#define SERVICE_QUERY_STATUS
Definition: winsvc.h:55
#define OpenSCManager
Definition: winsvc.h:575
#define CreateService
Definition: winsvc.h:569
#define SC_MANAGER_CREATE_SERVICE
Definition: winsvc.h:15
#define SC_MANAGER_CONNECT
Definition: winsvc.h:14
#define SERVICE_STOP_PENDING
Definition: winsvc.h:23
#define StartServiceCtrlDispatcher
Definition: winsvc.h:586
LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION
Definition: winsvc.h:553
#define SERVICE_STOP
Definition: winsvc.h:58
#define SERVICE_START_PENDING
Definition: winsvc.h:22
#define SERVICE_RUNNING
Definition: winsvc.h:24
#define SERVICE_CONTROL_STOP
Definition: winsvc.h:36
#define RegisterServiceCtrlHandler
Definition: winsvc.h:583
#define SERVICE_CONTROL_INTERROGATE
Definition: winsvc.h:39
#define OpenService
Definition: winsvc.h:576
#define SERVICE_AUTO_START
Definition: cmtypes.h:977
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:962
#define SERVICE_ERROR_NORMAL
Definition: cmtypes.h:982
char TCHAR
Definition: xmlstorage.h:189
#define _sntprintf
Definition: xmlstorage.h:201
CHAR * LPTSTR
Definition: xmlstorage.h:192