SERVICE.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:16k
源码类别:

Windows编程

开发平台:

Visual C++

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