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-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. #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 _CRTAPI1 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.         // SERVICE_STOP_PENDING should be reported before
  176.         // setting the Stop Event - hServerStopEvent - in
  177.         // ServiceStop().  This avoids a race condition
  178.         // which may result in a 1053 - The Service did not respond...
  179.         // error.
  180.         case SERVICE_CONTROL_STOP:
  181.             ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
  182.             ServiceStop();
  183.             return;
  184.         // Update the service status.
  185.         //
  186.         case SERVICE_CONTROL_INTERROGATE:
  187.             break;
  188.         // invalid control code
  189.         //
  190.         default:
  191.             break;
  192.     }
  193.     ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
  194. }
  195. //
  196. //  FUNCTION: ReportStatusToSCMgr()
  197. //
  198. //  PURPOSE: Sets the current status of the service and
  199. //           reports it to the Service Control Manager
  200. //
  201. //  PARAMETERS:
  202. //    dwCurrentState - the state of the service
  203. //    dwWin32ExitCode - error code to report
  204. //    dwWaitHint - worst case estimate to next checkpoint
  205. //
  206. //  RETURN VALUE:
  207. //    TRUE  - success
  208. //    FALSE - failure
  209. //
  210. //  COMMENTS:
  211. //
  212. BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
  213.                          DWORD dwWin32ExitCode,
  214.                          DWORD dwWaitHint)
  215. {
  216.     static DWORD dwCheckPoint = 1;
  217.     BOOL fResult = TRUE;
  218.     if ( !bDebug ) // when debugging we don't report to the SCM
  219.     {
  220.         if (dwCurrentState == SERVICE_START_PENDING)
  221.             ssStatus.dwControlsAccepted = 0;
  222.         else
  223.             ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  224.         ssStatus.dwCurrentState = dwCurrentState;
  225.         ssStatus.dwWin32ExitCode = dwWin32ExitCode;
  226.         ssStatus.dwWaitHint = dwWaitHint;
  227.         if ( ( dwCurrentState == SERVICE_RUNNING ) ||
  228.              ( dwCurrentState == SERVICE_STOPPED ) )
  229.             ssStatus.dwCheckPoint = 0;
  230.         else
  231.             ssStatus.dwCheckPoint = dwCheckPoint++;
  232.         // Report the status of the service to the service control manager.
  233.         //
  234.         if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus))) {
  235.             AddToMessageLog(TEXT("SetServiceStatus"));
  236.         }
  237.     }
  238.     return fResult;
  239. }
  240. //
  241. //  FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
  242. //
  243. //  PURPOSE: Allows any thread to log an error message
  244. //
  245. //  PARAMETERS:
  246. //    lpszMsg - text for message
  247. //
  248. //  RETURN VALUE:
  249. //    none
  250. //
  251. //  COMMENTS:
  252. //
  253. VOID AddToMessageLog(LPTSTR lpszMsg)
  254. {
  255.     TCHAR   szMsg[256];
  256.     HANDLE  hEventSource;
  257.     LPTSTR  lpszStrings[2];
  258.     if ( !bDebug )
  259.     {
  260.         dwErr = GetLastError();
  261.         // Use event logging to log the error.
  262.         //
  263.         hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
  264.         _stprintf(szMsg, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
  265.         lpszStrings[0] = szMsg;
  266.         lpszStrings[1] = lpszMsg;
  267.         if (hEventSource != NULL) {
  268.             ReportEvent(hEventSource, // handle of event source
  269.                 EVENTLOG_ERROR_TYPE,  // event type
  270.                 0,                    // event category
  271.                 0,                    // event ID
  272.                 NULL,                 // current user's SID
  273.                 2,                    // strings in lpszStrings
  274.                 0,                    // no bytes of raw data
  275.                 lpszStrings,          // array of error strings
  276.                 NULL);                // no raw data
  277.             (VOID) DeregisterEventSource(hEventSource);
  278.         }
  279.     }
  280. }
  281. ///////////////////////////////////////////////////////////////////
  282. //
  283. //  The following code handles service installation and removal
  284. //
  285. //
  286. //  FUNCTION: CmdInstallService()
  287. //
  288. //  PURPOSE: Installs the service
  289. //
  290. //  PARAMETERS:
  291. //    none
  292. //
  293. //  RETURN VALUE:
  294. //    none
  295. //
  296. //  COMMENTS:
  297. //
  298. void CmdInstallService()
  299. {
  300.     SC_HANDLE   schService;
  301.     SC_HANDLE   schSCManager;
  302.     TCHAR szPath[512];
  303.     if ( GetModuleFileName( NULL, szPath, 512 ) == 0 )
  304.     {
  305.         _tprintf(TEXT("Unable to install %s - %sn"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
  306.         return;
  307.     }
  308.     schSCManager = OpenSCManager(
  309.                         NULL,                   // machine (NULL == local)
  310.                         NULL,                   // database (NULL == default)
  311.                         SC_MANAGER_ALL_ACCESS   // access required
  312.                         );
  313.     if ( schSCManager )
  314.     {
  315.         schService = CreateService(
  316.             schSCManager,               // SCManager database
  317.             TEXT(SZSERVICENAME),        // name of service
  318.             TEXT(SZSERVICEDISPLAYNAME), // name to display
  319.             SERVICE_ALL_ACCESS,         // desired access
  320.             SERVICE_WIN32_OWN_PROCESS,  // service type
  321.             SERVICE_DEMAND_START,       // start type
  322.             SERVICE_ERROR_NORMAL,       // error control type
  323.             szPath,                     // service's binary
  324.             NULL,                       // no load ordering group
  325.             NULL,                       // no tag identifier
  326.             TEXT(SZDEPENDENCIES),       // dependencies
  327.             NULL,                       // LocalSystem account
  328.             NULL);                      // no password
  329.         if ( schService )
  330.         {
  331.             _tprintf(TEXT("%s installed.n"), TEXT(SZSERVICEDISPLAYNAME) );
  332.             CloseServiceHandle(schService);
  333.         }
  334.         else
  335.         {
  336.             _tprintf(TEXT("CreateService failed - %sn"), GetLastErrorText(szErr, 256));
  337.         }
  338.         CloseServiceHandle(schSCManager);
  339.     }
  340.     else
  341.         _tprintf(TEXT("OpenSCManager failed - %sn"), GetLastErrorText(szErr,256));
  342. }
  343. //
  344. //  FUNCTION: CmdRemoveService()
  345. //
  346. //  PURPOSE: Stops and removes the service
  347. //
  348. //  PARAMETERS:
  349. //    none
  350. //
  351. //  RETURN VALUE:
  352. //    none
  353. //
  354. //  COMMENTS:
  355. //
  356. void CmdRemoveService()
  357. {
  358.     SC_HANDLE   schService;
  359.     SC_HANDLE   schSCManager;
  360.     schSCManager = OpenSCManager(
  361.                         NULL,                   // machine (NULL == local)
  362.                         NULL,                   // database (NULL == default)
  363.                         SC_MANAGER_ALL_ACCESS   // access required
  364.                         );
  365.     if ( schSCManager )
  366.     {
  367.         schService = OpenService(schSCManager, TEXT(SZSERVICENAME), SERVICE_ALL_ACCESS);
  368.         if (schService)
  369.         {
  370.             // try to stop the service
  371.             if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
  372.             {
  373.                 _tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
  374.                 Sleep( 1000 );
  375.                 while( QueryServiceStatus( schService, &ssStatus ) )
  376.                 {
  377.                     if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
  378.                     {
  379.                         _tprintf(TEXT("."));
  380.                         Sleep( 1000 );
  381.                     }
  382.                     else
  383.                         break;
  384.                 }
  385.                 if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
  386.                     _tprintf(TEXT("n%s stopped.n"), TEXT(SZSERVICEDISPLAYNAME) );
  387.                 else
  388.                     _tprintf(TEXT("n%s failed to stop.n"), TEXT(SZSERVICEDISPLAYNAME) );
  389.             }
  390.             // now remove the service
  391.             if( DeleteService(schService) )
  392.                 _tprintf(TEXT("%s removed.n"), TEXT(SZSERVICEDISPLAYNAME) );
  393.             else
  394.                 _tprintf(TEXT("DeleteService failed - %sn"), GetLastErrorText(szErr,256));
  395.             CloseServiceHandle(schService);
  396.         }
  397.         else
  398.             _tprintf(TEXT("OpenService failed - %sn"), GetLastErrorText(szErr,256));
  399.         CloseServiceHandle(schSCManager);
  400.     }
  401.     else
  402.         _tprintf(TEXT("OpenSCManager failed - %sn"), GetLastErrorText(szErr,256));
  403. }
  404. ///////////////////////////////////////////////////////////////////
  405. //
  406. //  The following code is for running the service as a console app
  407. //
  408. //
  409. //  FUNCTION: CmdDebugService(int argc, char ** argv)
  410. //
  411. //  PURPOSE: Runs the service as a console application
  412. //
  413. //  PARAMETERS:
  414. //    argc - number of command line arguments
  415. //    argv - array of command line arguments
  416. //
  417. //  RETURN VALUE:
  418. //    none
  419. //
  420. //  COMMENTS:
  421. //
  422. void CmdDebugService(int argc, char ** argv)
  423. {
  424.     DWORD dwArgc;
  425.     LPTSTR *lpszArgv;
  426. #ifdef UNICODE
  427.     lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
  428. #else
  429.     dwArgc   = (DWORD) argc;
  430.     lpszArgv = argv;
  431. #endif
  432.     _tprintf(TEXT("Debugging %s.n"), TEXT(SZSERVICEDISPLAYNAME));
  433.     SetConsoleCtrlHandler( ControlHandler, TRUE );
  434.     ServiceStart( dwArgc, lpszArgv );
  435. }
  436. //
  437. //  FUNCTION: ControlHandler ( DWORD dwCtrlType )
  438. //
  439. //  PURPOSE: Handled console control events
  440. //
  441. //  PARAMETERS:
  442. //    dwCtrlType - type of control event
  443. //
  444. //  RETURN VALUE:
  445. //    True - handled
  446. //    False - unhandled
  447. //
  448. //  COMMENTS:
  449. //
  450. BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
  451. {
  452.     switch( dwCtrlType )
  453.     {
  454.         case CTRL_BREAK_EVENT:  // use Ctrl+C or Ctrl+Break to simulate
  455.         case CTRL_C_EVENT:      // SERVICE_CONTROL_STOP in debug mode
  456.             _tprintf(TEXT("Stopping %s.n"), TEXT(SZSERVICEDISPLAYNAME));
  457.             ServiceStop();
  458.             return TRUE;
  459.             break;
  460.     }
  461.     return FALSE;
  462. }
  463. //
  464. //  FUNCTION: GetLastErrorText
  465. //
  466. //  PURPOSE: copies error message text to string
  467. //
  468. //  PARAMETERS:
  469. //    lpszBuf - destination buffer
  470. //    dwSize - size of buffer
  471. //
  472. //  RETURN VALUE:
  473. //    destination buffer
  474. //
  475. //  COMMENTS:
  476. //
  477. LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
  478. {
  479.     DWORD dwRet;
  480.     LPTSTR lpszTemp = NULL;
  481.     dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
  482.                            NULL,
  483.                            GetLastError(),
  484.                            LANG_NEUTRAL,
  485.                            (LPTSTR)&lpszTemp,
  486.                            0,
  487.                            NULL );
  488.     // supplied buffer is not long enough
  489.     if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
  490.         lpszBuf[0] = TEXT('');
  491.     else
  492.     {
  493.         lpszTemp[lstrlen(lpszTemp)-2] = TEXT('');  //remove cr and newline character
  494.         _stprintf( lpszBuf, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
  495.     }
  496.     if ( lpszTemp )
  497.         LocalFree((HLOCAL) lpszTemp );
  498.     return lpszBuf;
  499. }