tdcservice.cpp
上传用户:qdlite
上传日期:2007-01-07
资源大小:26k
文件大小:16k
源码类别:

系统编程

开发平台:

Visual C++

  1. #include "TDCSERVICE.H"
  2. /**# implementation TDCService:: id(C_0851959163) */
  3. // TDCService.cpp
  4. //
  5. // Implementation of TDCService
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include "tdcservice.h"
  9. // static variables
  10. TDCService* TDCService::m_pThis = NULL;
  11. TDCService::TDCService(const char* szServiceName)
  12. {
  13.     // copy the address of the current object so we can access it from
  14.     // the static member callback functions. 
  15.     // WARNING: This limits the application to only one TDCService object. 
  16.     m_pThis = this;
  17.     
  18.     // Set the default service name and version
  19.     strncpy(m_szServiceName, szServiceName, sizeof(m_szServiceName)-1);
  20.     m_iMajorVersion = 1;
  21.     m_iMinorVersion = 0;
  22.     m_hEventSource = NULL;
  23.     // set up the initial service status 
  24.     m_hServiceStatus = NULL;
  25.     m_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  26.     m_Status.dwCurrentState = SERVICE_STOPPED;
  27.     m_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
  28.     m_Status.dwWin32ExitCode = 0;
  29.     m_Status.dwServiceSpecificExitCode = 0;
  30.     m_Status.dwCheckPoint = 0;
  31.     m_Status.dwWaitHint = 0;
  32.     m_bIsRunning = FALSE;
  33. }
  34. TDCService::~TDCService()
  35. {
  36.     DebugMsg("TDCService::~TDCService()");
  37.     if (m_hEventSource) {
  38.         ::DeregisterEventSource(m_hEventSource);
  39.     }
  40. }
  41. ////////////////////////////////////////////////////////////////////////////////////////
  42. // Default command line argument parsing
  43. // Returns TRUE if it found an arg it recognised, FALSE if not
  44. // Note: processing some arguments causes output to stdout to be generated.
  45. BOOL TDCService::ParseStandardArgs(int argc, char* argv[])
  46. {
  47.     // See if we have any command line args we recognise
  48.     if (argc <= 1) return FALSE;
  49.     if (stricmp(argv[1], "-v") == 0) {
  50.         // Spit out version info
  51.         printf("%s Version %d.%dn",
  52.                m_szServiceName, m_iMajorVersion, m_iMinorVersion);
  53.         printf("The service is %s installedn",
  54.                IsInstalled() ? "currently" : "not");
  55.         return TRUE; // say we processed the argument
  56.     } else if (stricmp(argv[1], "-i") == 0) {
  57.         // Request to install.
  58.         if (IsInstalled()) {
  59.             printf("%s is already installedn", m_szServiceName);
  60.         } else {
  61.             // Try and install the copy that's running
  62.             if (Install()) {
  63.                 printf("%s installedn", m_szServiceName);
  64.             } else {
  65.                 printf("%s failed to install. Error %dn", m_szServiceName, GetLastError());
  66.             }
  67.         }
  68.         return TRUE; // say we processed the argument
  69.     } else if (stricmp(argv[1], "-u") == 0) {
  70.         // Request to uninstall.
  71.         if (!IsInstalled()) {
  72.             printf("%s is not installedn", m_szServiceName);
  73.         } else {
  74.             // Try and remove the copy that's installed
  75.             if (Uninstall()) {
  76.                 // Get the executable file path
  77.                 char szFilePath[_MAX_PATH];
  78.                 ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
  79.                 printf("%s removed. (You must delete the file (%s) yourself.)n",
  80.                        m_szServiceName, szFilePath);
  81.             } else {
  82.                 printf("Could not remove %s. Error %dn", m_szServiceName, GetLastError());
  83.             }
  84.         }
  85.         return TRUE; // say we processed the argument
  86.     
  87.     } else { // don't recognize any of the arguments so want to print a list
  88.      printf( "%s Service.nn", m_szServiceName );
  89.       printf( "*   -v, report the name and version number of the servicen");
  90. printf( "*   -i, installs the servicen");
  91. printf( "*   -u, removes the servicen");
  92. return TRUE;
  93.     }
  94.     // Don't recognise the args
  95. //    return FALSE;
  96. }
  97. ////////////////////////////////////////////////////////////////////////////////////////
  98. // Install/uninstall routines
  99. // Test if the service is currently installed
  100. BOOL TDCService::IsInstalled()
  101. {
  102.     BOOL bResult = FALSE;
  103.     // Open the Service Control Manager
  104.     SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
  105.                                      NULL, // ServicesActive database
  106.                                      SC_MANAGER_ALL_ACCESS); // full access
  107.     if (hSCM) {
  108.         // Try to open the service
  109.         SC_HANDLE hService = ::OpenService(hSCM,
  110.                                            m_szServiceName,
  111.                                            SERVICE_QUERY_CONFIG);
  112.         if (hService) {
  113.             bResult = TRUE;
  114.             ::CloseServiceHandle(hService);
  115.         }
  116.         ::CloseServiceHandle(hSCM);
  117.     }
  118.     
  119.     return bResult;
  120. }
  121. BOOL TDCService::Install()
  122. {
  123.     // Open the Service Control Manager
  124.     SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
  125.                                      NULL, // ServicesActive database
  126.                                      SC_MANAGER_ALL_ACCESS); // full access
  127.     if (!hSCM) return FALSE;
  128.     // Get the executable file path
  129.     char szFilePath[_MAX_PATH];
  130.     ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath));
  131.     // Create the service
  132.     SC_HANDLE hService = ::CreateService(hSCM,
  133.                                          m_szServiceName,
  134.                                          m_szServiceName,
  135.                                          SERVICE_ALL_ACCESS,
  136.                                          SERVICE_WIN32_OWN_PROCESS,
  137.                                          SERVICE_DEMAND_START,        // start condition
  138.                                          SERVICE_ERROR_NORMAL,
  139.                                          szFilePath,
  140.                                          NULL,
  141.                                          NULL,
  142.                                          NULL,
  143.                                          NULL,
  144.                                          NULL);
  145.     if (!hService) {
  146.         ::CloseServiceHandle(hSCM);
  147.         return FALSE;
  148.     }
  149.     // make registry entries to support logging messages
  150.     // Add the source name as a subkey under the Application
  151.     // key in the EventLog service portion of the registry.
  152.     char szKey[256];
  153.     HKEY hKey = NULL;
  154.     strcpy(szKey, "SYSTEM\CurrentControlSet\Services\EventLog\Application\");
  155.     strcat(szKey, m_szServiceName);
  156.     if (::RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) {
  157.         ::CloseServiceHandle(hService);
  158.         ::CloseServiceHandle(hSCM);
  159.         return FALSE;
  160.     }
  161.     // Add the Event ID message-file name to the 'EventMessageFile' subkey.
  162.     ::RegSetValueEx(hKey,
  163.                     "EventMessageFile",
  164.                     0,
  165.                     REG_EXPAND_SZ, 
  166.                     (CONST BYTE*)szFilePath,
  167.                     strlen(szFilePath) + 1);     
  168.     // Set the supported types flags.
  169.     DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
  170.     ::RegSetValueEx(hKey,
  171.                     "TypesSupported",
  172.                     0,
  173.                     REG_DWORD,
  174.                     (CONST BYTE*)&dwData,
  175.                      sizeof(DWORD));
  176.     ::RegCloseKey(hKey);
  177.     LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, m_szServiceName);
  178.     // tidy up
  179.     ::CloseServiceHandle(hService);
  180.     ::CloseServiceHandle(hSCM);
  181.     return TRUE;
  182. }
  183. BOOL TDCService::Uninstall()
  184. {
  185.     // Open the Service Control Manager
  186.     SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine
  187.                                      NULL, // ServicesActive database
  188.                                      SC_MANAGER_ALL_ACCESS); // full access
  189.     if (!hSCM) return FALSE;
  190.     BOOL bResult = FALSE;
  191.     SC_HANDLE hService = ::OpenService(hSCM,
  192.                                        m_szServiceName,
  193.                                        DELETE);
  194.     if (hService) {
  195.         if (::DeleteService(hService)) {
  196.             LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, m_szServiceName);
  197.             bResult = TRUE;
  198.         } else {
  199.             LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, m_szServiceName);
  200.         }
  201.         ::CloseServiceHandle(hService);
  202.     }
  203.     
  204.     ::CloseServiceHandle(hSCM);
  205.     return bResult;
  206. }
  207. ///////////////////////////////////////////////////////////////////////////////////////
  208. // Logging functions
  209. // This function makes an entry into the application event log
  210. void TDCService::LogEvent(WORD wType, DWORD dwID,
  211.                           const char* pszS1,
  212.                           const char* pszS2,
  213.                           const char* pszS3)
  214. {
  215.     const char* ps[3];
  216.     ps[0] = pszS1;
  217.     ps[1] = pszS2;
  218.     ps[2] = pszS3;
  219.     int iStr = 0;
  220.     for (int i = 0; i < 3; i++) {
  221.         if (ps[i] != NULL) iStr++;
  222.     }
  223.         
  224.     // Check the event source has been registered and if
  225.     // not then register it now
  226.     if (!m_hEventSource) {
  227.         m_hEventSource = ::RegisterEventSource(NULL,  // local machine
  228.                                                m_szServiceName); // source name
  229.     }
  230.     if (m_hEventSource) {
  231.         ::ReportEvent(m_hEventSource,
  232.                       wType,
  233.                       0,
  234.                       dwID,
  235.                       NULL, // sid
  236.                       iStr,
  237.                       0,
  238.                       ps,
  239.                       NULL);
  240.     }
  241. }
  242. //////////////////////////////////////////////////////////////////////////////////////////////
  243. // Service startup and registration
  244. BOOL TDCService::StartService()
  245. {
  246.     SERVICE_TABLE_ENTRY st[] = {
  247.         {m_szServiceName, ServiceMain},
  248.         {NULL, NULL}
  249.     };
  250.     DebugMsg("Calling StartServiceCtrlDispatcher()");
  251.     BOOL b = ::StartServiceCtrlDispatcher(st);
  252.     DebugMsg("Returned from StartServiceCtrlDispatcher()");
  253.     return b;
  254. }
  255. // static member function (callback)
  256. void TDCService::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv)
  257. {
  258.     // Get a pointer to the C++ object
  259.     TDCService* pService = m_pThis;
  260.     
  261.     pService->DebugMsg("Entering TDCService::ServiceMain()");
  262.     // Register the control request handler
  263.     pService->m_Status.dwCurrentState = SERVICE_START_PENDING;
  264.     pService->m_hServiceStatus = RegisterServiceCtrlHandler(pService->m_szServiceName,
  265.                                                            Handler);
  266.     if (pService->m_hServiceStatus == NULL) {
  267.         pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_CTRLHANDLERNOTINSTALLED);
  268.         return;
  269.     }
  270.     // Start the initialisation
  271.     if (pService->Initialize()) {
  272.         // Do the real work. 
  273.         // When the Run function returns, the service has stopped.
  274.         pService->m_bIsRunning = TRUE;
  275.         pService->m_Status.dwWin32ExitCode = 0;
  276.         pService->m_Status.dwCheckPoint = 0;
  277.         pService->m_Status.dwWaitHint = 0;
  278.         pService->Run();
  279.     }
  280.     // Tell the service manager we are stopped
  281.     pService->SetStatus(SERVICE_STOPPED);
  282.     pService->DebugMsg("Leaving TDCService::ServiceMain()");
  283. }
  284. ///////////////////////////////////////////////////////////////////////////////////////////
  285. // status functions
  286. void TDCService::SetStatus(DWORD dwState)
  287. {
  288.     DebugMsg("TDCService::SetStatus(%lu, %lu)", m_hServiceStatus, dwState);
  289.     m_Status.dwCurrentState = dwState;
  290.     ::SetServiceStatus(m_hServiceStatus, &m_Status);
  291. }
  292. ///////////////////////////////////////////////////////////////////////////////////////////
  293. // Service initialization
  294. BOOL TDCService::Initialize()
  295. {
  296.     DebugMsg("Entering TDCService::Initialize()");
  297.     // Start the initialization
  298.     SetStatus(SERVICE_START_PENDING);
  299.     // Perform the actual initialization
  300.     BOOL bResult = OnInit();
  301.     // Set final state
  302.     m_Status.dwWin32ExitCode = GetLastError();
  303.     m_Status.dwCheckPoint = 0;
  304.     m_Status.dwWaitHint = 0;
  305.     if (!bResult) {
  306.         LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_FAILEDINIT);
  307.         SetStatus(SERVICE_STOPPED);
  308.         return FALSE;
  309.     }
  310.     LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STARTED);
  311.     SetStatus(SERVICE_RUNNING);
  312.     DebugMsg("Leaving TDCService::Initialize()");
  313.     return TRUE;
  314. }
  315. ///////////////////////////////////////////////////////////////////////////////////////////////
  316. // main function to do the real work of the service
  317. // This function performs the main work of the service. 
  318. // When this function returns the service has stopped.
  319. void TDCService::Run()
  320. {
  321.     DebugMsg("Entering TDCService::Run()");
  322.     while (m_bIsRunning) {
  323.         DebugMsg("Sleeping...");
  324.         Sleep(5000);
  325.     }
  326.     // nothing more to do
  327.     DebugMsg("Leaving TDCService::Run()");
  328. }
  329. //////////////////////////////////////////////////////////////////////////////////////
  330. // Control request handlers
  331. // static member function (callback) to handle commands from the
  332. // service control manager
  333. void TDCService::Handler(DWORD dwOpcode)
  334. {
  335.     // Get a pointer to the object
  336.     TDCService* pService = m_pThis;
  337.     
  338.     pService->DebugMsg("TDCService::Handler(%lu)", dwOpcode);
  339.     switch (dwOpcode) {
  340.     case SERVICE_CONTROL_STOP: // 1
  341.         pService->SetStatus(SERVICE_STOP_PENDING);
  342.         pService->OnStop();
  343.         pService->m_bIsRunning = FALSE;
  344.         pService->LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STOPPED);
  345.         break;
  346.     case SERVICE_CONTROL_PAUSE: // 2
  347.         pService->OnPause();
  348.         break;
  349.     case SERVICE_CONTROL_CONTINUE: // 3
  350.         pService->OnContinue();
  351.         break;
  352.     case SERVICE_CONTROL_INTERROGATE: // 4
  353.         pService->OnInterrogate();
  354.         break;
  355.     case SERVICE_CONTROL_SHUTDOWN: // 5
  356.         pService->OnShutdown();
  357.         break;
  358.     default:
  359.         if (dwOpcode >= SERVICE_CONTROL_USER) {
  360.             if (!pService->OnUserControl(dwOpcode)) {
  361.                 pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
  362.             }
  363.         } else {
  364.             pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST);
  365.         }
  366.         break;
  367.     }
  368.     // Report current status
  369.     pService->DebugMsg("Updating status (%lu, %lu)",
  370.                        pService->m_hServiceStatus,
  371.                        pService->m_Status.dwCurrentState);
  372.     ::SetServiceStatus(pService->m_hServiceStatus, &pService->m_Status);
  373. }
  374.         
  375. // Called when the service is first initialized
  376. BOOL TDCService::OnInit()
  377. {
  378.     DebugMsg("TDCService::OnInit()");
  379. return TRUE;
  380. }
  381. // Called when the service control manager wants to stop the service
  382. void TDCService::OnStop()
  383. {
  384.     DebugMsg("TDCService::OnStop()");
  385. }
  386. // called when the service is interrogated
  387. void TDCService::OnInterrogate()
  388. {
  389.     DebugMsg("TDCService::OnInterrogate()");
  390. }
  391. // called when the service is paused
  392. void TDCService::OnPause()
  393. {
  394.     DebugMsg("TDCService::OnPause()");
  395. }
  396. // called when the service is continued
  397. void TDCService::OnContinue()
  398. {
  399.     DebugMsg("TDCService::OnContinue()");
  400. }
  401. // called when the service is shut down
  402. void TDCService::OnShutdown()
  403. {
  404.     DebugMsg("TDCService::OnShutdown()");
  405. }
  406. // called when the service gets a user control message
  407. BOOL TDCService::OnUserControl(DWORD dwOpcode)
  408. {
  409.     DebugMsg("TDCService::OnUserControl(%8.8lXH)", dwOpcode);
  410.     return FALSE; // say not handled
  411. }
  412. ////////////////////////////////////////////////////////////////////////////////////////////
  413. // Debugging support
  414. void TDCService::DebugMsg(const char* pszFormat, ...)
  415. {
  416.     char buf[1024];
  417.     sprintf(buf, "[%s](%lu): ", m_szServiceName, GetCurrentThreadId());
  418. va_list arglist;
  419. va_start(arglist, pszFormat);
  420.     vsprintf(&buf[strlen(buf)], pszFormat, arglist);
  421. va_end(arglist);
  422.     strcat(buf, "n");
  423.     OutputDebugString(buf);
  424. }