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

Telnet服务器

开发平台:

Visual C++

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