ReactOS  0.4.12-dev-75-g00dd17e
service.c
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------
2 THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
3 ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
4 TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
5 PARTICULAR PURPOSE.
6 
7 Copyright (C) Microsoft Corporation. All rights reserved.
8 
9 MODULE: service.c
10 
11 PURPOSE: Implements functions required by all Windows NT services
12 
13 FUNCTIONS:
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
34 SERVICE_STATUS ssStatus; // current status of the service
38 TCHAR szErr[256];
39 
40 // internal function prototypes
41 VOID WINAPI service_ctrl(DWORD dwCtrlCode);
42 VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
45 VOID CmdDebugService(int argc, char **argv);
46 BOOL 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 //
67 void __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;
89  CmdDebugService(argc, argv);
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 //
132 void 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  //
145  ssStatus.dwServiceSpecificExitCode = 0;
146 
147 
148  // report the status to the service control manager.
149  //
150  if (!ReportStatusToSCMgr(
151  SERVICE_START_PENDING, // service state
152  NO_ERROR, // exit code
153  3000)) // wait hint
154  goto cleanup;
155 
156 
157  ServiceStart( dwArgc, lpszArgv );
158 
159  cleanup:
160 
161  // try to report the stopped status to the service control manager.
162  //
163  if (sshStatusHandle)
166  dwErr,
167  0);
168 
169  return;
170 }
171 
172 
173 
174 //
175 // FUNCTION: service_ctrl
176 //
177 // PURPOSE: This function is called by the SCM whenever
178 // ControlService() is called on this service.
179 //
180 // PARAMETERS:
181 // dwCtrlCode - type of control requested
182 //
183 // RETURN VALUE:
184 // none
185 //
186 // COMMENTS:
187 //
189 {
190  // Handle the requested control code.
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)
251  ssStatus.dwControlsAccepted = 0;
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 ) )
261  ssStatus.dwCheckPoint = 0;
262  else
263  ssStatus.dwCheckPoint = dwCheckPoint++;
264 
265 
266  // Report the status of the service to the service control manager.
267  fResult = SetServiceStatus(sshStatusHandle, &ssStatus);
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  {
297  dwErr = GetLastError();
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)
366  SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE // access required
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  {
440  if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
441  {
442  _tprintf(TEXT("."));
443  Sleep( 1000 );
444  }
445  else
446  break;
447  }
448 
449  if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
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 //
497 void 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(),
581  LANG_NEUTRAL,
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
VOID CmdRemoveService()
Definition: service.c:416
BOOL WINAPI ControlHandler(DWORD dwCtrlType)
Definition: service.c:544
static int argc
Definition: ServiceArgs.c:12
#define _tprintf
Definition: tchar.h:506
#define SERVICE_ERROR_NORMAL
Definition: cmtypes.h:980
#define TRUE
Definition: types.h:120
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
#define CTRL_BREAK_EVENT
Definition: wincon.h:66
SERVICE_STATUS_HANDLE sshStatusHandle
Definition: service.c:35
DWORD dwCurrentState
Definition: winsvc.h:100
#define SC_MANAGER_CONNECT
Definition: winsvc.h:14
#define __cdecl
Definition: accygwin.h:79
static DWORD
Definition: service.c:38
#define SZAPPNAME
Definition: service.h:65
#define LANG_NEUTRAL
Definition: nls.h:22
#define FORMAT_MESSAGE_ARGUMENT_ARRAY
Definition: winbase.h:405
#define SERVICE_ACCEPT_STOP
Definition: winsvc.h:28
#define CTRL_C_EVENT
Definition: wincon.h:65
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
Definition: service.c:132
LPSERVICE_MAIN_FUNCTIONA LPSERVICE_MAIN_FUNCTION
Definition: winsvc.h:553
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define SERVICE_START_PENDING
Definition: winsvc.h:22
DWORD dwServiceSpecificExitCode
Definition: winsvc.h:103
VOID CmdInstallService()
Definition: service.c:350
BOOL WINAPI DeleteService(SC_HANDLE hService)
Definition: scm.c:915
#define CreateService
Definition: winsvc.h:569
#define NO_ERROR
Definition: dderror.h:5
BOOL bDebug
Definition: service.c:37
#define _stricmp
Definition: cat.c:22
VOID CmdDebugService(int argc, char **argv)
Definition: service.c:497
#define OpenService
Definition: winsvc.h:576
static char ** argv
Definition: ServiceArgs.c:11
CHAR * LPTSTR
Definition: xmlstorage.h:192
BOOL WINAPI SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE_STATUS lpServiceStatus)
Definition: sctrl.c:957
VOID AddToMessageLog(LPTSTR lpszMsg)
Definition: service.c:289
DWORD dwCheckPoint
Definition: winsvc.h:104
#define SERVICE_STOPPED
Definition: winsvc.h:21
#define RegisterServiceCtrlHandler
Definition: winsvc.h:583
#define EVENTLOG_ERROR_TYPE
Definition: winnt_old.h:2630
LPWSTR WINAPI GetCommandLineW(VOID)
Definition: proc.c:2043
#define StartServiceCtrlDispatcher
Definition: winsvc.h:586
BOOL WINAPI DECLSPEC_HOTPATCH SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine, BOOL Add)
Definition: console.c:2111
#define SERVICE_RUNNING
Definition: winsvc.h:24
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:400
LPWSTR *WINAPI CommandLineToArgvW(LPCWSTR lpCmdline, int *numargs)
Definition: shell32_main.c:76
VOID ServiceStop()
Definition: nfs41_daemon.c:156
BOOL WINAPI CloseServiceHandle(SC_HANDLE hSCObject)
Definition: scm.c:576
smooth NULL
Definition: ftsmooth.c:416
#define SERVICE_CONTROL_INTERROGATE
Definition: winsvc.h:39
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
Definition: service.c:188
#define SERVICE_QUERY_STATUS
Definition: winsvc.h:55
#define SC_MANAGER_CREATE_SERVICE
Definition: winsvc.h:15
#define SERVICE_WIN32_OWN_PROCESS
Definition: cmtypes.h:960
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:404
VOID ServiceStart(DWORD argc, LPTSTR *argv)
Definition: nfs41_daemon.c:380
DWORD dwErr
Definition: service.c:36
char TCHAR
Definition: xmlstorage.h:189
#define OpenSCManager
Definition: winsvc.h:575
unsigned int BOOL
Definition: ntddk_ex.h:94
DWORD dwWaitHint
Definition: winsvc.h:105
DWORD dwWin32ExitCode
Definition: winsvc.h:102
unsigned long DWORD
Definition: ntddk_ex.h:95
BOOL WINAPI QueryServiceStatus(SC_HANDLE hService, LPSERVICE_STATUS lpServiceStatus)
Definition: scm.c:2787
DWORD dwServiceType
Definition: winsvc.h:99
HGLOBAL NTAPI GlobalFree(HGLOBAL hMem)
Definition: heapmem.c:611
#define GetModuleFileName
Definition: winbase.h:3645
void __cdecl main(int argc, char **argv)
Definition: service.c:67
#define FormatMessage
Definition: winbase.h:3609
#define SZDEPENDENCIES
Definition: service.h:71
#define VOID
Definition: acefi.h:82
#define _sntprintf
Definition: xmlstorage.h:201
#define ReportEvent
Definition: winbase.h:3713
void dispatch(HANDLE hStopEvent)
Definition: dispatch.c:66
#define WINAPI
Definition: msvc.h:20
#define SZSERVICENAME
Definition: service.h:67
#define RegisterEventSource
Definition: winbase.h:3708
DWORD dwControlsAccepted
Definition: winsvc.h:101
#define lstrlen
Definition: winbase.h:3690
#define TEXT(s)
Definition: k32.h:26
LPCWSTR szPath
Definition: env.c:35
#define SERVICE_STOP
Definition: winsvc.h:58
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
BOOL WINAPI ControlService(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus)
Definition: scm.c:618
BOOL WINAPI DeregisterEventSource(IN HANDLE hEventLog)
Definition: eventlog.c:473
LPTSTR GetLastErrorText(LPTSTR lpszBuf, DWORD dwSize)
Definition: service.c:573
#define SERVICE_AUTO_START
Definition: cmtypes.h:975
TCHAR szErr[256]
Definition: service.c:38
SERVICE_STATUS ssStatus
Definition: service.c:34
char * cleanup(char *str)
Definition: wpickclick.c:99
#define SERVICE_CONTROL_STOP
Definition: winsvc.h:36
void exit(int exitcode)
Definition: _exit.c:33
static SERVICE_STATUS_HANDLE(WINAPI *pRegisterServiceCtrlHandlerExA)(LPCSTR
#define SERVICE_STOP_PENDING
Definition: winsvc.h:23
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
#define DELETE
Definition: nt_native.h:57
#define printf
Definition: config.h:203
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
Definition: service.c:240
#define SZSERVICEDISPLAYNAME
Definition: service.h:69