238 lines
8.1 KiB
C++
238 lines
8.1 KiB
C++
//----------------------------------------------------------------------------
|
|
//
|
|
// 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 <iostream>
|
|
#include <fstream>
|
|
|
|
|
|
// 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<LPTSTR>(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;
|
|
}
|