//---------------------------------------------------------------------------- // // Copyright (C) Intel Corporation, 2007 - 2008. // // File: BaseService.cpp // // Contents: Provides a base class for a service that will exist as // part of a service application. BaseService must be // derived when creating a new service class. // // Notes: To use this class you should derived this class and // implement the following methods: // ServiceInitialization - initialization of the service. // _ServiceCtrlHandler - take care of calling the callback // function specified for each // control operations. // ServiceMainLoop - Service main application // //---------------------------------------------------------------------------- #include "BaseService.h" #include "WindowsEventLog.h" #include "MPSMessageFile.h" #include #include // The single, static service instance pointer. BaseService* BaseService::m_pService = NULL; //***************************************************************************** // Name: ServiceBase // Description: Constructor - initializes a new instance of the // BaseService class and set the service name. //***************************************************************************** BaseService::BaseService(LPCTSTR pszServiceName): m_ServiceHandle() { m_pService = this; m_ServiceName = pszServiceName; m_InitFlag = false; eventLogger = new WindowsEventLog(APPLICATION, m_ServiceName.c_str(), EVENT_LOG_CATEGORY_COUNT); } //***************************************************************************** // Name : InitializeService // Description: The service initialization function. // This function does all the initialization code for the service //***************************************************************************** int BaseService::InitializeService(DWORD dwServiceType, DWORD dwControlsAccepted, DWORD dwWaitHint) { _ASSERT(m_ServiceName.empty() == false ); // Set the dispatcher table (pass it to the service ctrl iapatcher function). m_ServiceDispatcher[0].lpServiceName = const_cast(m_ServiceName.c_str()); m_ServiceDispatcher[0].lpServiceProc = ServiceMain; m_ServiceDispatcher[1].lpServiceName = NULL; m_ServiceDispatcher[1].lpServiceProc = NULL; // setting the service current status - before registering the service m_ServiceStatus.dwCheckPoint = 0; m_ServiceStatus.dwControlsAccepted = dwControlsAccepted; m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; m_ServiceStatus.dwServiceSpecificExitCode = 0; m_ServiceStatus.dwServiceType = dwServiceType; m_ServiceStatus.dwWaitHint = dwWaitHint; m_ServiceStatus.dwWin32ExitCode = 0; m_InitFlag = true; return 0; // success } //***************************************************************************** // Name : ServiceMain // Description: this is the actual service main that gets called as soon as the // service runs. //***************************************************************************** void WINAPI BaseService::ServiceMain(DWORD argc,LPTSTR *argv) { m_pService->_ServiceMain(argc,argv); } //***************************************************************************** // Name : WriteToErrorLog // Description: Write an error message to the Windows Event log. //***************************************************************************** void BaseService::WriteToErrorLog(const char *message) { mutex.acquire(); ACE_TCHAR szBuf[1024]; ACE_OS::sprintf(szBuf, " [%s] %s\n", m_ServiceName.c_str(), message); const ACE_TCHAR *lpStrings[] = {szBuf}; unsigned int NumOfStrings = 1; if (eventLogger != NULL) { eventLogger->LogEvent(SERVICE_GENERAL, SERVICE_ERROR_MESSAGE, EVENTLOG_ERROR_TYPE, lpStrings,NumOfStrings, NULL, 0); } mutex.release(); } //***************************************************************************** // Name : getFormatMessage // Description: Gets the windows system error description from a windows system // error code //***************************************************************************** void BaseService::getFormatMessage(DWORD errorCode, string &errorBuf) { void *errorMsgBuf = NULL; DWORD dwFormatFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM; FormatMessageA(dwFormatFlags, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &errorMsgBuf, 0, NULL); /* Free error message buf */ errorBuf = (char*) errorMsgBuf; if (errorMsgBuf != NULL) { LocalFree(errorMsgBuf); } } //***************************************************************************** // Name : ServiceMain // Description: non-static function which does all the job of the service main //***************************************************************************** void WINAPI BaseService::_ServiceMain(DWORD argc,LPTSTR *argv) { _ASSERT(m_InitFlag == true); // check for call to initialize DWORD status; DWORD specificError; string errorBuf; // Register the service m_ServiceHandle = RegisterServiceCtrlHandlerEx( m_ServiceName.c_str(), BaseService::ServiceCtrlHandler, NULL); // Check for errors. if (m_ServiceHandle == (SERVICE_STATUS_HANDLE)0) { getFormatMessage(GetLastError(), errorBuf); WriteToErrorLog(errorBuf.c_str()); return; } // Update the service status BOOL res = UpdateService(SERVICE_START_PENDING); if (res == FALSE) { getFormatMessage(GetLastError(), errorBuf); WriteToErrorLog(errorBuf.c_str()); return; } // This is where the service does its work. status = ServiceInitialization(argc,argv, &specificError); // Handle error condition if (status != NO_ERROR) { m_ServiceStatus.dwWin32ExitCode = status; m_ServiceStatus.dwServiceSpecificExitCode = specificError; getFormatMessage(GetLastError(), errorBuf); WriteToErrorLog(errorBuf.c_str()); UpdateService (SERVICE_STOPPED); return; } // Set the service status. if( !UpdateService(SERVICE_RUNNING) ) { getFormatMessage(GetLastError(), errorBuf); WriteToErrorLog(errorBuf.c_str()); return; } // Loop while no error and do your job. ServiceMainLoop(); if (!UpdateService(SERVICE_STOPPED)) { getFormatMessage(GetLastError(), errorBuf); WriteToErrorLog(errorBuf.c_str()); return; } return; } //***************************************************************************** // Name : ServiceCtrlHandler // Description: This is the service control handler which was registered to SCM. // call the non-static function that implements the code for service // control handler //***************************************************************************** DWORD WINAPI BaseService::ServiceCtrlHandler( DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext) { return m_pService->_ServiceCtrlHandler(dwControl, dwEventType, lpEventData, lpContext); } //***************************************************************************** // Name : StartDispatcher // Description: Connect to the SCM and start the control dispatcher thread // The dispatcher thread loops, waiting for incoming control // requests for the services specified in the dispatch table. //***************************************************************************** DWORD BaseService::StartDispatcher() { if( !StartServiceCtrlDispatcher(m_ServiceDispatcher) ) { string errorBuf; getFormatMessage(GetLastError(), errorBuf); WriteToErrorLog(errorBuf.c_str()); return -1; } return 0; } //***************************************************************************** // Name : UpdateService // Description: Updates the status of the service using the SetServiceStatus SCM // function. //***************************************************************************** BOOL BaseService::UpdateService(DWORD dwCurrentState) { m_ServiceStatus.dwCurrentState = dwCurrentState; BOOL status = SetServiceStatus(m_ServiceHandle,&m_ServiceStatus); return status; }