home *** CD-ROM | disk | FTP | other *** search
/ PCNET 2006 September - Disc 1 / PCNET_CD_2006_09.iso / surpriz / MSRMesh-VirtualWIFI.MSI / Service.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2005-06-24  |  15.4 KB  |  581 lines

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