// NTService.cpp // // Implementation of CNTService #include #include #include "NTService.h" #include "svchost.h" #include "PMSPService.h" #include //// static variables CNTService* g_pService = NULL; CRITICAL_SECTION g_csLock; CNTService::CNTService() { // // Set the default service name and version // strncpy(m_szServiceName, szServiceName, sizeof(m_szServiceName)-1); // strncpy(m_szServiceDisplayName, szServiceDisplayName, sizeof(m_szServiceDisplayName)-1); // m_iMajorVersion = 1; // m_iMinorVersion = 4; // set up the initial service status m_hServiceStatus = NULL; m_Status.dwServiceType = SERVICE_WIN32_SHARE_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()"); } //////////////////////////////////////////////////////////////////////////////////////// // Default command line argument parsing //////////////////////////////////////////////////////////////////////////////////////// // 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 GENERIC_READ); // access combined STANDARD_RIGHTS_READ, // SC_MANAGER_ENUMERATE_SERVICE, and // SC_MANAGER_QEURY_LOCK_STATUS if (hSCM) { // Try to open the service SC_HANDLE hService = ::OpenService(hSCM, SERVICE_NAME, SERVICE_QUERY_CONFIG); if (hService) { bResult = TRUE; ::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) { HANDLE hEventSource = NULL; const char* ps[3]; ps[0] = pszS1; ps[1] = pszS2; ps[2] = pszS3; WORD iStr = 0; for (int i = 0; i < 3; i++) { if (ps[i] != NULL) iStr++; else { // Ensure that the remaining arguments are NULL, zap them // if they are not. Otherwise, ReportEvent will fail for (; i < 3; i++) { if (ps[i] != NULL) { _ASSERTE(ps[i] == NULL); ps[i] = NULL; } } // We will break out of the outer for loop since i == 3 } } // Register event source hEventSource = ::RegisterEventSource( NULL, // local machine SERVICE_NAME); // source name if (hEventSource) { ::ReportEvent(hEventSource, wType, 0, dwID, NULL, // sid iStr, 0, ps, NULL); ::DeregisterEventSource(hEventSource); } } /////////////////////////////////////////////////////////////////////////////////////////// // status functions void CNTService::SetStatus(DWORD dwState) { DebugMsg("CNTService::SetStatus(%lu, %lu)", m_hServiceStatus, dwState); // If a stop is pending, the only next state we'll report is STOPPED. // If the Stop was issued while we are being started, the service thread // will start fully and then commence stopping (as the code is currently // structured). While it is starting, it will update the check point. // We ignore the state it sends in (START_PENDING) and lie to the SCM. if (m_Status.dwCurrentState != SERVICE_STOP_PENDING || dwState == SERVICE_STOPPED) { if (m_Status.dwCurrentState != dwState) { m_Status.dwCurrentState = dwState; m_Status.dwCheckPoint = 0; m_Status.dwWaitHint = 0; } } if (m_Status.dwCurrentState == SERVICE_STOP_PENDING || m_Status.dwCurrentState == SERVICE_START_PENDING || m_Status.dwCurrentState == SERVICE_PAUSE_PENDING || m_Status.dwCurrentState == SERVICE_CONTINUE_PENDING) { m_Status.dwCheckPoint++; m_Status.dwWaitHint = 500; } ::SetServiceStatus(m_hServiceStatus, &m_Status); } /////////////////////////////////////////////////////////////////////////////////////////// // Service initialization BOOL CNTService::Initialize() { DWORD dwLastError; DebugMsg("Entering CNTService::Initialize()"); // Perform the actual initialization BOOL bResult = OnInit(dwLastError); // Bump up the check point SetStatus(SERVICE_START_PENDING); if (!bResult) { m_Status.dwWin32ExitCode = dwLastError; CNTService::DebugMsg("The initialization process failed" ); return FALSE; } DebugMsg("Leaving CNTService::Initialize()"); return TRUE; } /////////////////////////////////////////////////////////////////////////////////////////////// // main function to do the real work of the service ////////////////////////////////////////////////////////////////////////////////////// // Control request handlers // static member function (callback) to handle commands from the // service control manager void CNTService::Handler(DWORD dwOpcode) { BOOL bStop = FALSE; __try { EnterCriticalSection (&g_csLock); // Get a pointer to the object CNTService* pService = g_pService; if (!pService) { __leave; } CNTService::DebugMsg("CNTService::Handler(%lu)", dwOpcode); switch (dwOpcode) { case SERVICE_CONTROL_STOP: // 1 pService->OnStop(); 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 - let the On* functions do this by calling SetStatus // CNTService::DebugMsg("Updating status (%lu, %lu)", // pService->m_hServiceStatus, // pService->m_Status.dwCurrentState); // ::SetServiceStatus(pService->m_hServiceStatus, &pService->m_Status); } __finally { LeaveCriticalSection (&g_csLock); } } // 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()"); } //////////////////////////////////////////////////////////////////////////////////////////// // Debugging support // #define WRITE_TO_LOG_FILE void CNTService::DebugMsg(const char* pszFormat, ...) { #if defined(DBG) || defined(WRITE_TO_LOG_FILE) char buf[1024]; sprintf(buf, "[Serial Number Library](%lu): ", GetCurrentThreadId()); va_list arglist; va_start(arglist, pszFormat); vsprintf(&buf[strlen(buf)], pszFormat, arglist); va_end(arglist); strcat(buf, "\n"); #if defined(DBG) OutputDebugString(buf); #endif #if defined(WRITE_TO_LOG_FILE) FILE* fp = fopen("c:\\WmdmService.txt", "a"); if (fp) { fprintf(fp, buf); fclose(fp); } #endif #endif }