/[pkg-mixmaster]/trunk/Mix/Src/service.c
ViewVC logotype

Contents of /trunk/Mix/Src/service.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.5