www.pudn.com > SMS PLAN.rar > NTService.cpp
// NTService.cpp // // Implementation of CNTService #include#include #include "NTService.h" // static variables CNTService* CNTService::m_pThis = NULL; CNTService::CNTService(const char* szServiceName) { // copy the address of the current object so we can access it from // the static member callback functions. // WARNING: This limits the application to only one CNTService object. m_pThis = this; // Set the default service name and version strncpy(m_szServiceName, szServiceName, sizeof(m_szServiceName)-1); m_iMajorVersion = 1; m_iMinorVersion = 0; m_hEventSource = NULL; // set up the initial service status m_hServiceStatus = NULL; m_Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; m_Status.dwCurrentState = SERVICE_STOPPED; m_Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; m_Status.dwWin32ExitCode = 0; m_Status.dwServiceSpecificExitCode = 0; m_Status.dwCheckPoint = 0; m_Status.dwWaitHint = 0; m_bIsRunning = FALSE; } CNTService::~CNTService() { DebugMsg("CNTService::~CNTService()"); if (m_hEventSource) { ::DeregisterEventSource(m_hEventSource); } } //////////////////////////////////////////////////////////////////////////////////////// // Default command line argument parsing // Returns TRUE if it found an arg it recognised, FALSE if not // Note: processing some arguments causes output to stdout to be generated. BOOL CNTService::ParseStandardArgs(int argc, char* argv[]) { // See if we have any command line args we recognise if (argc <= 1) return FALSE; if (_stricmp(argv[1], "-v") == 0) { // Spit out version info printf("%s Version %d.%d\n", m_szServiceName, m_iMajorVersion, m_iMinorVersion); printf("The service is %s installed\n", IsInstalled() ? "currently" : "not"); return TRUE; // say we processed the argument } else if (_stricmp(argv[1], "-i") == 0) { // Request to install. if (IsInstalled()) { printf("%s is already installed\n", m_szServiceName); } else { // Try and install the copy that's running if (Install()) { printf("%s installed\n", m_szServiceName); } else { printf("%s failed to install. Error %d\n", m_szServiceName, GetLastError()); } } return TRUE; // say we processed the argument } else if (_stricmp(argv[1], "-u") == 0) { // Request to uninstall. if (!IsInstalled()) { printf("%s is not installed\n", m_szServiceName); } else { // Try and remove the copy that's installed if (Uninstall()) { // Get the executable file path char szFilePath[_MAX_PATH]; ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); printf("%s removed. (You must delete the file (%s) yourself.)\n", m_szServiceName, szFilePath); } else { printf("Could not remove %s. Error %d\n", m_szServiceName, GetLastError()); } } return TRUE; // say we processed the argument } else if (_stricmp(argv[1], "-d") == 0) { if(IsInstalled()&&m_hServiceStatus==SERVICE_RUNNING) { AddLog("服务程序正在运行,请先关闭%s再进行调试。",szSubServiceName); return TRUE; } m_bIsRunning=1; Run(); return TRUE; // say we processed the argument } // Don't recognise the args return FALSE; } //////////////////////////////////////////////////////////////////////////////////////// // Install/uninstall routines // Test if the service is currently installed BOOL CNTService::IsInstalled() { BOOL bResult = FALSE; // Open the Service Control Manager SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access if (hSCM) { // Try to open the service SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, SERVICE_QUERY_CONFIG); if (hService) { bResult = TRUE; ::CloseServiceHandle(hService); } ::CloseServiceHandle(hSCM); } return bResult; } BOOL CNTService::Install() { // Open the Service Control Manager SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access if (!hSCM) return FALSE; // Get the executable file path char szFilePath[_MAX_PATH]; ::GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); // Create the service SC_HANDLE hService = ::CreateService(hSCM, m_szServiceName, m_szServiceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START, // start condition SERVICE_ERROR_NORMAL, szFilePath, NULL, NULL, NULL, NULL, NULL); if (!hService) { ::CloseServiceHandle(hSCM); return FALSE; } // make registry entries to support logging messages // Add the source name as a subkey under the Application // key in the EventLog service portion of the registry. char szKey[256]; HKEY hKey = NULL; strcpy(szKey, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"); strcat(szKey, m_szServiceName); if (::RegCreateKey(HKEY_LOCAL_MACHINE, szKey, &hKey) != ERROR_SUCCESS) { ::CloseServiceHandle(hService); ::CloseServiceHandle(hSCM); return FALSE; } // Add the Event ID message-file name to the 'EventMessageFile' subkey. ::RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, (CONST BYTE*)szFilePath, strlen(szFilePath) + 1); // Set the supported types flags. DWORD dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; ::RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, (CONST BYTE*)&dwData, sizeof(DWORD)); ::RegCloseKey(hKey); LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_INSTALLED, m_szServiceName); // tidy up ::CloseServiceHandle(hService); ::CloseServiceHandle(hSCM); return TRUE; } BOOL CNTService::Uninstall() { // Open the Service Control Manager SC_HANDLE hSCM = ::OpenSCManager(NULL, // local machine NULL, // ServicesActive database SC_MANAGER_ALL_ACCESS); // full access if (!hSCM) return FALSE; BOOL bResult = FALSE; SC_HANDLE hService = ::OpenService(hSCM, m_szServiceName, DELETE); if (hService) { if (::DeleteService(hService)) { LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_REMOVED, m_szServiceName); bResult = TRUE; } else { LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_NOTREMOVED, m_szServiceName); } ::CloseServiceHandle(hService); } ::CloseServiceHandle(hSCM); return bResult; } /////////////////////////////////////////////////////////////////////////////////////// // Logging functions // This function makes an entry into the application event log void CNTService::LogEvent(WORD wType, DWORD dwID, const char* pszS1, const char* pszS2, const char* pszS3) { const char* ps[3]; ps[0] = pszS1; ps[1] = pszS2; ps[2] = pszS3; int iStr = 0; for (int i = 0; i < 3; i++) { if (ps[i] != NULL) iStr++; } // Check the event source has been registered and if // not then register it now if (!m_hEventSource) { m_hEventSource = ::RegisterEventSource(NULL, // local machine m_szServiceName); // source name } if (m_hEventSource) { ::ReportEvent(m_hEventSource, wType, 0, dwID, NULL, // sid iStr, 0, ps, NULL); } } ////////////////////////////////////////////////////////////////////////////////////////////// // Service startup and registration BOOL CNTService::StartService() { SERVICE_TABLE_ENTRY st[] = { {m_szServiceName, ServiceMain}, {NULL, NULL} }; DebugMsg("Calling StartServiceCtrlDispatcher()"); BOOL b = ::StartServiceCtrlDispatcher(st); DebugMsg("Returned from StartServiceCtrlDispatcher()"); return b; } // static member function (callback) void CNTService::ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv) { // Get a pointer to the C++ object CNTService* pService = m_pThis; pService->DebugMsg("Entering CNTService::ServiceMain()"); // Register the control request handler pService->m_Status.dwCurrentState = SERVICE_START_PENDING; pService->m_hServiceStatus = RegisterServiceCtrlHandler(pService->m_szServiceName, Handler); if (pService->m_hServiceStatus == NULL) { pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_CTRLHANDLERNOTINSTALLED); return; } // Start the initialisation if (pService->Initialize()) { // Do the real work. // When the Run function returns, the service has stopped. pService->m_bIsRunning = TRUE; pService->m_Status.dwWin32ExitCode = 0; pService->m_Status.dwCheckPoint = 0; pService->m_Status.dwWaitHint = 0; pService->Run(); } // Tell the service manager we are stopped pService->SetStatus(SERVICE_STOPPED); pService->DebugMsg("Leaving CNTService::ServiceMain()"); } /////////////////////////////////////////////////////////////////////////////////////////// // status functions void CNTService::SetStatus(DWORD dwState) { DebugMsg("CNTService::SetStatus(%lu, %lu)", m_hServiceStatus, dwState); m_Status.dwCurrentState = dwState; ::SetServiceStatus(m_hServiceStatus, &m_Status); } /////////////////////////////////////////////////////////////////////////////////////////// // Service initialization BOOL CNTService::Initialize() { DebugMsg("Entering CNTService::Initialize()"); // Start the initialization SetStatus(SERVICE_START_PENDING); // Perform the actual initialization BOOL bResult = OnInit(); // Set final state m_Status.dwWin32ExitCode = GetLastError(); m_Status.dwCheckPoint = 0; m_Status.dwWaitHint = 0; if (!bResult) { LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_FAILEDINIT); SetStatus(SERVICE_STOPPED); return FALSE; } LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STARTED); SetStatus(SERVICE_RUNNING); DebugMsg("Leaving CNTService::Initialize()"); return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////// // main function to do the real work of the service // This function performs the main work of the service. // When this function returns the service has stopped. void CNTService::Run() { DebugMsg("Entering CNTService::Run()"); while (m_bIsRunning) { DebugMsg("Sleeping..."); Sleep(5000); } // nothing more to do DebugMsg("Leaving CNTService::Run()"); } ////////////////////////////////////////////////////////////////////////////////////// // Control request handlers // static member function (callback) to handle commands from the // service control manager void CNTService::Handler(DWORD dwOpcode) { // Get a pointer to the object CNTService* pService = m_pThis; pService->DebugMsg("CNTService::Handler(%lu)", dwOpcode); switch (dwOpcode) { case SERVICE_CONTROL_STOP: // 1 pService->SetStatus(SERVICE_STOP_PENDING); pService->OnStop(); pService->m_bIsRunning = FALSE; pService->LogEvent(EVENTLOG_INFORMATION_TYPE, EVMSG_STOPPED); break; case SERVICE_CONTROL_PAUSE: // 2 pService->OnPause(); break; case SERVICE_CONTROL_CONTINUE: // 3 pService->OnContinue(); break; case SERVICE_CONTROL_INTERROGATE: // 4 pService->OnInterrogate(); break; case SERVICE_CONTROL_SHUTDOWN: // 5 pService->OnShutdown(); break; default: if (dwOpcode >= SERVICE_CONTROL_USER) { if (!pService->OnUserControl(dwOpcode)) { pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST); } } else { pService->LogEvent(EVENTLOG_ERROR_TYPE, EVMSG_BADREQUEST); } break; } // Report current status pService->DebugMsg("Updating status (%lu, %lu)", pService->m_hServiceStatus, pService->m_Status.dwCurrentState); ::SetServiceStatus(pService->m_hServiceStatus, &pService->m_Status); } // Called when the service is first initialized BOOL CNTService::OnInit() { DebugMsg("CNTService::OnInit()"); return TRUE; } // Called when the service control manager wants to stop the service void CNTService::OnStop() { if(hServerStopEvent) { SetEvent(hServerStopEvent); AddLog("发送消息,准备停止服务%s.\n",szSubServiceName); } } // called when the service is interrogated void CNTService::OnInterrogate() { DebugMsg("CNTService::OnInterrogate()"); } // called when the service is paused void CNTService::OnPause() { DebugMsg("CNTService::OnPause()"); } // called when the service is continued void CNTService::OnContinue() { DebugMsg("CNTService::OnContinue()"); } // called when the service is shut down void CNTService::OnShutdown() { DebugMsg("CNTService::OnShutdown()"); } // called when the service gets a user control message BOOL CNTService::OnUserControl(DWORD dwOpcode) { DebugMsg("CNTService::OnUserControl(%8.8lXH)", dwOpcode); return FALSE; // say not handled } //////////////////////////////////////////////////////////////////////////////////////////// // Debugging support void CNTService::DebugMsg(const char* pszFormat, ...) { char buf[1024]; sprintf(buf, "[%s](%lu): ", m_szServiceName, GetCurrentThreadId()); va_list arglist; va_start(arglist, pszFormat); vsprintf(&buf[strlen(buf)], pszFormat, arglist); va_end(arglist); strcat(buf, "\n"); OutputDebugString(buf); }