|
|
/************************************************************************************************
Copyright (c) 2001 Microsoft Corporation
Module Name: Service.cpp. Abstract: Implements the CService class. See Service.h for details. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/
#include "stdafx.h"
#include "Service.h"
// static variables initialization
const DWORD CService::dwStateNoChange = 0xFFFFFFFF;
/************************************************************************************************
Member: CService::CService, constructor, public. Synopsis: Initializes internal variables, such as event logging defaults. Effects: Arguments: [szName] - the SCM short name for the service. [szDisplay] - the SCM display name for the service. [dwType] - see CreateService for further documentation. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ CService::CService(LPCTSTR szName, LPCTSTR szDisplay, DWORD dwType) : m_dwType(dwType) { ASSERT(!(NULL == szName)); ASSERT(!(NULL == szDisplay)); m_hServiceStatus = NULL; m_dwRequestedControl = 0;
// Control Events
m_hWatcherThread = NULL;
m_dwState = 0; m_dwControlsAccepted = 0; m_dwCheckpoint = 0; m_dwWaitHint = 0;
// Initialize event handles to NULL
for(int i = 0; i < nNumServiceEvents; i++) m_hServiceEvent[i] = NULL;
// Copy string names
_tcsncpy(m_szName, szName, nMaxServiceLen); _tcsncpy(m_szDisplay, szDisplay, nMaxServiceLen);
// Set up class critical section
InitializeCriticalSection(&m_cs); }
/************************************************************************************************
Member: CService::~CService, destructor, public. Synopsis: Deinitializes internal variables. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ CService::~CService() { DeleteCriticalSection(&m_cs); }
/************************************************************************************************
Member: CService::PreInit, destructor, public. Synopsis: Initialialization of variables. This is performed before launching the watcher thread and notifying status to the SCM. Notes: (*) If you override this, call the base class version in the beginning!! History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::PreInit() { // Initialize Events
for(int i = 0; i < nNumServiceEvents; i++) { m_hServiceEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL); if(!m_hServiceEvent[i]) { AbortService(); } } }
/************************************************************************************************
Member: CService::PreInit, destructor, public. Synopsis: Initialialization of variables. This is performed before launching the watcher thread and notifying status to the SCM. Notes: (*) If you override this, call the base class version in the beginning!! History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::DeInit() { // Wait for the watcher thread to terminate
if(m_hWatcherThread) { // Wait a reasonable amount of time
WaitForSingleObject(m_hWatcherThread, 10000); CloseHandle(m_hWatcherThread); }
// Uninitialize any resources created in Init()
for(int i = 0 ; i < nNumServiceEvents ; i++) { if(m_hServiceEvent[i]) CloseHandle(m_hServiceEvent[i]); } }
/************************************************************************************************
Member: CService::ServiceMainMember, protected Synopsis: does the main service thread processing. (ServiceMain() equivalent) Notes: This is delegated from the static thread entry-point. History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::ServiceMainMember(DWORD argc, LPTSTR* argv, LPHANDLER_FUNCTION pf, LPTHREAD_START_ROUTINE pfnWTP) { OnBeforeStart(); PreInit(); SetupHandlerInside(pf); ParseArgs(argc, argv); LaunchWatcherThread(pfnWTP); Init(); OnAfterStart(); Run(); DeInit(); }
/************************************************************************************************
Member: CService::SetupHandlerInside, protected Synopsis: Register the control handler for the service. Arguments: [lpHandlerProc] - pointer to the function implementing the SCM event handling. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ bool CService::SetupHandlerInside(LPHANDLER_FUNCTION lpHandlerProc) { m_hServiceStatus = RegisterServiceCtrlHandler(m_szName, lpHandlerProc); if(!m_hServiceStatus) { AbortService(); }
SetStatus(SERVICE_START_PENDING, 1, 5000); return true; }
/************************************************************************************************
Member: CService::HandlerMember, protected Synopsis: Handles service start, stop, etc. requests from the SCM Arguments: [dwControl] - event request code. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::HandlerMember(DWORD dwControl) { // Keep an additional control request of the same type
// from coming in when you're already handling it
if(m_dwRequestedControl == dwControl) return;
switch(dwControl) { case SERVICE_CONTROL_STOP: m_dwRequestedControl = dwControl;
// Notify the service to stop...
OnStopRequest(); SetEvent(m_hServiceEvent[STOP]); break;
case SERVICE_CONTROL_PAUSE: m_dwRequestedControl = dwControl;
// Notify the service to pause...
OnPauseRequest(); SetEvent(m_hServiceEvent[PAUSE]); break;
case SERVICE_CONTROL_CONTINUE: if(GetStatus() != SERVICE_RUNNING) { m_dwRequestedControl = dwControl;
// Notify the service to continue...
OnContinueRequest(); SetEvent(m_hServiceEvent[CONTINUE]); } break;
case SERVICE_CONTROL_SHUTDOWN: m_dwRequestedControl = dwControl;
OnShutdownRequest(); SetEvent(m_hServiceEvent[SHUTDOWN]); break;
case SERVICE_CONTROL_INTERROGATE: // Return current status on interrogation
SetStatus(GetStatus()); break;
default: // User Defined
m_dwRequestedControl = dwControl; HandleUserDefined(dwControl); } }
void CService::LaunchWatcherThread(LPTHREAD_START_ROUTINE pfnWTP) { if(NULL != pfnWTP) { m_hWatcherThread = (HANDLE)_beginthreadex(0, 0, (unsigned (WINAPI*)(void*))pfnWTP, 0, 0, NULL); } if(!m_hWatcherThread) { AbortService(); } }
DWORD CService::WatcherThreadMemberProc() { DWORD dwWait = 0; bool bControlWait = true;
// Wait for any events to signal
while(bControlWait) { dwWait = WaitForMultipleObjects(nNumServiceEvents, m_hServiceEvent, FALSE, INFINITE);
switch(dwWait - WAIT_OBJECT_0) { case STOP: bControlWait = false; break;
case PAUSE: OnPause(); ResetEvent(m_hServiceEvent[PAUSE]); break;
case CONTINUE: OnContinue(); ResetEvent(m_hServiceEvent[CONTINUE]); break;
case SHUTDOWN: OnShutdown(); bControlWait = false; break; } } //Wait for the global shutdown event
while(1) { dwWait = WaitForSingleObject(g_hShutDown, 5000); if(WAIT_OBJECT_0==dwWait || WAIT_ABANDONED == dwWait) { break; } else if(WAIT_TIMEOUT == dwWait) { SetStatus(SERVICE_STOP_PENDING, 1, 10000); } } return 0; }
void CService::SetStatus(DWORD dwNewState, DWORD dwNewCheckpoint, DWORD dwNewHint, DWORD dwNewControls, DWORD dwExitCode, DWORD dwSpecificExit) { // The only state that can set Exit Codes is STOPPED
// Fix if necessary, just in case not set properly.
if(dwNewState != SERVICE_STOPPED) { dwExitCode = S_OK; dwSpecificExit = 0; }
// Only pending states can set checkpoints or wait hints,
// and pending states *must* set wait hints
if((SERVICE_STOPPED == dwNewState) || (SERVICE_PAUSED == dwNewState) || (SERVICE_RUNNING == dwNewState)) { // Requires hint and checkpoint == 0
// Fix it so that NO_CHANGE from previous state doesn't cause nonzero
dwNewHint = 0; dwNewCheckpoint = 0; } else { // Requires hint and checkpoint != 0
if(dwNewHint <= 0 || dwNewCheckpoint <=0) { AbortService(); } }
// Function can be called by multiple threads - protect member data
EnterCriticalSection(&m_cs);
// Alter states if changing
m_dwState = dwNewState;
if(dwNewCheckpoint != dwStateNoChange) { m_dwCheckpoint = dwNewCheckpoint; }
if(dwNewHint != dwStateNoChange) { m_dwWaitHint = dwNewHint; }
if(dwNewControls != dwStateNoChange) { m_dwControlsAccepted = dwNewControls; }
SERVICE_STATUS ss = {m_dwType, m_dwState, m_dwControlsAccepted, dwExitCode, dwSpecificExit, m_dwCheckpoint, m_dwWaitHint};
LeaveCriticalSection(&m_cs);
SetServiceStatus(m_hServiceStatus, &ss); }
/************************************************************************************************
Member: CService::AbortService, protected Synopsis: Generic error handler, call this when you fall in to a critical error and must abort the service. Arguments: [dwErrorNum] - Error code reported back to SCM. Notes: History: 01/31/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::AbortService(DWORD dwErrorNum /*= GetLastError()*/) { // clean up service and stop service notifying error to the SCM
OnStopRequest(); DeInit(); OnStop(dwErrorNum); ExitProcess(dwErrorNum); }
/************************************************************************************************
Member: CService::Init, overridable, public. Synopsis: Override this to implement initialization code for your specific service. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::Init() {}
/************************************************************************************************
Member: CService::HandleUserDefined, overridable, public. Synopsis: Override this to implement custom SCM requests to your service. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::HandleUserDefined(DWORD /*dwControl*/) {}
/************************************************************************************************
Member: CService::OnPause, overridable, public. Synopsis: Override this to implement code that runs when the service pauses. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnPause() {}
/************************************************************************************************
Member: CService::OnContinue, overridable, public. Synopsis: Override this to implement code that runs when the service resumes from a pause. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnContinue() {}
/************************************************************************************************
Member: CService::OnShutdown, overridable, public. Synopsis: Override this to implement code that runs when service is stopped by a shutdown. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnShutdown() {}
/************************************************************************************************
Member: CService::ParseArgs, overridable, public. Synopsis: Override this to implement parsing of service command line parameters. Notes: History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::ParseArgs(DWORD /*argc*/, LPTSTR* /*argv*/) {}
/************************************************************************************************
Member: CService::OnBeforeStart, overridable, public. Synopsis: Override this to add code that's run before trying to start the service. Notes: A common use would be to log that the service will try to start. History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnBeforeStart() {}
/************************************************************************************************
Member: CService::OnAfterStart, overridable, public. Synopsis: Override this to add code that's run just after the service was started. Notes: A common use would be to log that the service was successfully started. History: 01/25/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnAfterStart() {}
/************************************************************************************************
Member: CService::OnStopRequest, overridable, public. Synopsis: Override this to add code that's run when the service receives a stop request. Notes: A common use is to log that the service received the stop request. This function DOESN'T run in the main thread. Protect resources if needed. History: 02/05/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnStopRequest() {}
/************************************************************************************************
Member: CService::OnPauseRequest, overridable, public. Synopsis: Override this to add code that's run when the service receives a pause request. Notes: A common use is to log that the service received the pause request. This function DOESN'T run in the main thread. Protect resources if needed. History: 02/05/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnPauseRequest() {}
/************************************************************************************************
Member: CService::OnContinueRequest, overridable, public. Synopsis: Override this to add code that's run when the service receives a continue request. Notes: A common use is to log that the service received the continue request. This function DOESN'T run in the main thread. Protect resources if needed. History: 02/05/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnContinueRequest() {}
/************************************************************************************************
Member: CService::OnShutdownRequest, overridable, public. Synopsis: Override this to add code that's run when the service receives a shutdown request. Notes: A common use is to log that the service received the shutdown request. This function DOESN'T run in the main thread. Protect resources if needed. History: 02/05/2001 - created, Luciano Passuello (lucianop). ************************************************************************************************/ void CService::OnShutdownRequest() {}
// End of file Service.cpp.
|