diff options
Diffstat (limited to 'general/WinHEC 2017 Lab/Toaster Driver/Service/ServiceBase.cpp')
| -rw-r--r-- | general/WinHEC 2017 Lab/Toaster Driver/Service/ServiceBase.cpp | 566 |
1 files changed, 566 insertions, 0 deletions
diff --git a/general/WinHEC 2017 Lab/Toaster Driver/Service/ServiceBase.cpp b/general/WinHEC 2017 Lab/Toaster Driver/Service/ServiceBase.cpp new file mode 100644 index 00000000..117d740c --- /dev/null +++ b/general/WinHEC 2017 Lab/Toaster Driver/Service/ServiceBase.cpp @@ -0,0 +1,566 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#include "stdafx.h" +#pragma region Includes + +#include "ServiceBase.h" +#include <assert.h> +#include <strsafe.h> +#include <evntprov.h> +#include <Evntrace.h> +#pragma endregion + +// +// HSA Service trace event provider +// {BE2E880E-F79F-4C30-9C95-09F003A0A7EA} +// +EXTERN_C __declspec(selectany) const GUID HSA_SERVICE_PROVIDER_GUID = { 0xbe2e880e, 0xf79f, 0x4c30,{ 0x9c, 0x95, 0x9, 0xf0, 0x3, 0xa0, 0xa7, 0xea } }; + +#pragma region Static Members + +// Initialize the singleton service instance. +CServiceBase *CServiceBase::s_service = nullptr; + + +// +// FUNCTION: CServiceBase::Run(CServiceBase &) +// +// PURPOSE: Register the executable for a service with the Service Control +// Manager (SCM). After you call Run(ServiceBase), the SCM issues a Start +// command, which results in a call to the OnStart method in the service. +// This method blocks until the service has stopped. +// +// PARAMETERS: +// * service - the reference to a CServiceBase object. It will become the +// singleton service instance of this service application. +// +// RETURN VALUE: If the function succeeds, the return value is TRUE. If the +// function fails, the return value is FALSE. To get extended error +// information, call GetLastError. +// +BOOL CServiceBase::Run(CServiceBase &service) +{ + s_service = &service; + + SERVICE_TABLE_ENTRY serviceTable[] = + { + { service.m_name, ServiceMain }, + { nullptr, nullptr } + }; + + // Connects the main thread of a service process to the service control + // manager, which causes the thread to be the service control dispatcher + // thread for the calling process. This call returns when the service has + // stopped. The process should simply terminate when the call returns. + return StartServiceCtrlDispatcher(serviceTable); +} + + +// +// FUNCTION: CServiceBase::ServiceMain(DWORD, PWSTR *) +// +// PURPOSE: Entry point for the service. It registers the handler function +// for the service and starts the service. +// +// PARAMETERS: +// * dwArgc - number of command line arguments +// * lpszArgv - array of command line arguments +// +void WINAPI CServiceBase::ServiceMain(DWORD dwArgc, PWSTR *pszArgv) +{ + assert(s_service != NULL); + + // Register the handler function for the service + s_service->m_statusHandle = RegisterServiceCtrlHandler( + s_service->m_name, ServiceCtrlHandler); + + if (s_service->m_statusHandle == NULL) + { + throw GetLastError(); + } + + // Start the service. + s_service->Start(dwArgc, pszArgv); +} + + +// +// FUNCTION: CServiceBase::ServiceCtrlHandler(DWORD) +// +// PURPOSE: The function is called by the SCM whenever a control code is +// sent to the service. +// +// PARAMETERS: +// * dwCtrlCode - the control code. This parameter can be one of the +// following values: +// +// SERVICE_CONTROL_CONTINUE +// SERVICE_CONTROL_INTERROGATE +// SERVICE_CONTROL_NETBINDADD +// SERVICE_CONTROL_NETBINDDISABLE +// SERVICE_CONTROL_NETBINDREMOVE +// SERVICE_CONTROL_PARAMCHANGE +// SERVICE_CONTROL_PAUSE +// SERVICE_CONTROL_SHUTDOWN +// SERVICE_CONTROL_STOP +// +// This parameter can also be a user-defined control code ranges from 128 +// to 255. +// +void WINAPI CServiceBase::ServiceCtrlHandler(DWORD dwCtrl) +{ + switch (dwCtrl) + { + case SERVICE_CONTROL_STOP: s_service->Stop(); break; + case SERVICE_CONTROL_PAUSE: s_service->Pause(); break; + case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break; + case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break; + case SERVICE_CONTROL_INTERROGATE: break; + default: break; + } +} + +#pragma endregion + + +#pragma region Service Constructor and Destructor + +// +// FUNCTION: CServiceBase::CServiceBase(PWSTR, BOOL, BOOL, BOOL) +// +// PURPOSE: The constructor of CServiceBase. It initializes a new instance +// of the CServiceBase class. The optional parameters (fCanStop, +/// fCanShutdown and fCanPauseContinue) allow you to specify whether the +// service can be stopped, paused and continued, or be notified when system +// shutdown occurs. +// +// PARAMETERS: +// * pszServiceName - the name of the service +// * fCanStop - the service can be stopped +// * fCanShutdown - the service is notified when system shutdown occurs +// * fCanPauseContinue - the service can be paused and continued +// +CServiceBase::CServiceBase( + PWSTR pszServiceName, + BOOL fCanStop, + BOOL fCanShutdown, + BOOL fCanPauseContinue) +{ + // Service name must be a valid string and cannot be NULL. + m_name = (pszServiceName == nullptr) ? L"" : pszServiceName; + + m_statusHandle = nullptr; + + // The service runs in its own process. + m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + + // The service is starting. + m_status.dwCurrentState = SERVICE_START_PENDING; + + // The accepted commands of the service. + DWORD dwControlsAccepted = 0; + if (fCanStop) + dwControlsAccepted |= SERVICE_ACCEPT_STOP; + if (fCanShutdown) + dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN; + if (fCanPauseContinue) + dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE; + m_status.dwControlsAccepted = dwControlsAccepted; + + m_status.dwWin32ExitCode = NO_ERROR; + m_status.dwServiceSpecificExitCode = 0; + m_status.dwCheckPoint = 0; + m_status.dwWaitHint = 0; + + NTSTATUS status = EventRegister(&HSA_SERVICE_PROVIDER_GUID, + nullptr, + nullptr, + &m_etwRegHandle); + if (ERROR_SUCCESS != status) + { + wprintf(L"Provider not registered. EventRegister failed with %d\n", status); + } +} + + +// +// FUNCTION: CServiceBase::~CServiceBase() +// +// PURPOSE: The virtual destructor of CServiceBase. +// +CServiceBase::~CServiceBase(void) +{ + if (m_etwRegHandle != NULL) + { + EventUnregister(m_etwRegHandle); + } +} + +#pragma endregion + + +#pragma region Service Start, Stop, Pause, Continue, and Shutdown + +// +// FUNCTION: CServiceBase::Start(DWORD, PWSTR *) +// +// PURPOSE: The function starts the service. It calls the OnStart virtual +// function in which you can specify the actions to take when the service +// starts. If an error occurs during the startup, the error will be logged +// in the Application event log, and the service will be stopped. +// +// PARAMETERS: +// * dwArgc - number of command line arguments +// * lpszArgv - array of command line arguments +// +void CServiceBase::Start(DWORD dwArgc, PWSTR *pszArgv) +{ + WriteEventLogEntry(L"Service trying to start.", TRACE_LEVEL_ERROR); + try + { + // Tell SCM that the service is starting. + SetServiceStatus(SERVICE_START_PENDING); + + // Perform service-specific initialization. + OnStart(dwArgc, pszArgv); + + // Tell SCM that the service is started. + SetServiceStatus(SERVICE_RUNNING); + } + catch (DWORD dwError) + { + // Log the error. + WriteErrorLogEntry(L"Service Start", dwError); + + // Set the service status to be stopped. + SetServiceStatus(SERVICE_STOPPED, dwError); + } + catch (...) + { + // Log the error. + WriteEventLogEntry(L"Service failed to start.", TRACE_LEVEL_ERROR); + + // Set the service status to be stopped. + SetServiceStatus(SERVICE_STOPPED); + } +} + + +// +// FUNCTION: CServiceBase::OnStart(DWORD, PWSTR *) +// +// PURPOSE: When implemented in a derived class, executes when a Start +// command is sent to the service by the SCM or when the operating system +// starts (for a service that starts automatically). Specifies actions to +// take when the service starts. Be sure to periodically call +// CServiceBase::SetServiceStatus() with SERVICE_START_PENDING if the +// procedure is going to take long time. You may also consider spawning a +// new thread in OnStart to perform time-consuming initialization tasks. +// +// PARAMETERS: +// * dwArgc - number of command line arguments +// * lpszArgv - array of command line arguments +// +void CServiceBase::OnStart(DWORD dwArgc, PWSTR *pszArgv) +{ +} + + +// +// FUNCTION: CServiceBase::Stop() +// +// PURPOSE: The function stops the service. It calls the OnStop virtual +// function in which you can specify the actions to take when the service +// stops. If an error occurs, the error will be logged in the Application +// event log, and the service will be restored to the original state. +// +void CServiceBase::Stop() +{ + DWORD dwOriginalState = m_status.dwCurrentState; + try + { + // Tell SCM that the service is stopping. + SetServiceStatus(SERVICE_STOP_PENDING); + + // Perform service-specific stop operations. + OnStop(); + + // Tell SCM that the service is stopped. + SetServiceStatus(SERVICE_STOPPED); + } + catch (DWORD dwError) + { + // Log the error. + WriteErrorLogEntry(L"Service Stop", dwError); + + // Set the orginal service status. + SetServiceStatus(dwOriginalState); + } + catch (...) + { + // Log the error. + WriteEventLogEntry(L"Service failed to stop.", TRACE_LEVEL_ERROR); + + // Set the orginal service status. + SetServiceStatus(dwOriginalState); + } +} + + +// +// FUNCTION: CServiceBase::OnStop() +// +// PURPOSE: When implemented in a derived class, executes when a Stop +// command is sent to the service by the SCM. Specifies actions to take +// when a service stops running. Be sure to periodically call +// CServiceBase::SetServiceStatus() with SERVICE_STOP_PENDING if the +// procedure is going to take long time. +// +void CServiceBase::OnStop() +{ +} + + +// +// FUNCTION: CServiceBase::Pause() +// +// PURPOSE: The function pauses the service if the service supports pause +// and continue. It calls the OnPause virtual function in which you can +// specify the actions to take when the service pauses. If an error occurs, +// the error will be logged in the Application event log, and the service +// will become running. +// +void CServiceBase::Pause() +{ + try + { + // Tell SCM that the service is pausing. + SetServiceStatus(SERVICE_PAUSE_PENDING); + + // Perform service-specific pause operations. + OnPause(); + + // Tell SCM that the service is paused. + SetServiceStatus(SERVICE_PAUSED); + } + catch (DWORD dwError) + { + // Log the error. + WriteErrorLogEntry(L"Service Pause", dwError); + + // Tell SCM that the service is still running. + SetServiceStatus(SERVICE_RUNNING); + } + catch (...) + { + // Log the error. + WriteEventLogEntry(L"Service failed to pause.", TRACE_LEVEL_ERROR); + + // Tell SCM that the service is still running. + SetServiceStatus(SERVICE_RUNNING); + } +} + + +// +// FUNCTION: CServiceBase::OnPause() +// +// PURPOSE: When implemented in a derived class, executes when a Pause +// command is sent to the service by the SCM. Specifies actions to take +// when a service pauses. +// +void CServiceBase::OnPause() +{ +} + + +// +// FUNCTION: CServiceBase::Continue() +// +// PURPOSE: The function resumes normal functioning after being paused if +// the service supports pause and continue. It calls the OnContinue virtual +// function in which you can specify the actions to take when the service +// continues. If an error occurs, the error will be logged in the +// Application event log, and the service will still be paused. +// +void CServiceBase::Continue() +{ + try + { + // Tell SCM that the service is resuming. + SetServiceStatus(SERVICE_CONTINUE_PENDING); + + // Perform service-specific continue operations. + OnContinue(); + + // Tell SCM that the service is running. + SetServiceStatus(SERVICE_RUNNING); + } + catch (DWORD dwError) + { + // Log the error. + WriteErrorLogEntry(L"Service Continue", dwError); + + // Tell SCM that the service is still paused. + SetServiceStatus(SERVICE_PAUSED); + } + catch (...) + { + // Log the error. + WriteEventLogEntry(L"Service failed to resume.", TRACE_LEVEL_ERROR); + + // Tell SCM that the service is still paused. + SetServiceStatus(SERVICE_PAUSED); + } +} + + +// +// FUNCTION: CServiceBase::OnContinue() +// +// PURPOSE: When implemented in a derived class, OnContinue runs when a +// Continue command is sent to the service by the SCM. Specifies actions to +// take when a service resumes normal functioning after being paused. +// +void CServiceBase::OnContinue() +{ +} + + +// +// FUNCTION: CServiceBase::Shutdown() +// +// PURPOSE: The function executes when the system is shutting down. It +// calls the OnShutdown virtual function in which you can specify what +// should occur immediately prior to the system shutting down. If an error +// occurs, the error will be logged in the Application event log. +// +void CServiceBase::Shutdown() +{ + try + { + // Perform service-specific shutdown operations. + OnShutdown(); + + // Tell SCM that the service is stopped. + SetServiceStatus(SERVICE_STOPPED); + } + catch (DWORD dwError) + { + // Log the error. + WriteErrorLogEntry(L"Service Shutdown", dwError); + } + catch (...) + { + // Log the error. + WriteEventLogEntry(L"Service failed to shut down.", TRACE_LEVEL_ERROR); + } +} + + +// +// FUNCTION: CServiceBase::OnShutdown() +// +// PURPOSE: When implemented in a derived class, executes when the system +// is shutting down. Specifies what should occur immediately prior to the +// system shutting down. +// +void CServiceBase::OnShutdown() +{ +} + +#pragma endregion + + +#pragma region Helper Functions + +// +// FUNCTION: CServiceBase::SetServiceStatus(DWORD, DWORD, DWORD) +// +// PURPOSE: The function sets the service status and reports the status to +// the SCM. +// +// PARAMETERS: +// * dwCurrentState - the state of the service +// * dwWin32ExitCode - error code to report +// * dwWaitHint - estimated time for pending operation, in milliseconds +// +void CServiceBase::SetServiceStatus( + _In_ DWORD dwCurrentState, + _In_ DWORD dwWin32ExitCode, + _In_ DWORD dwWaitHint) +{ + static DWORD dwCheckPoint = 1; + + // Fill in the SERVICE_STATUS structure of the service. + + m_status.dwCurrentState = dwCurrentState; + m_status.dwWin32ExitCode = dwWin32ExitCode; + m_status.dwWaitHint = dwWaitHint; + + m_status.dwCheckPoint = + ((dwCurrentState == SERVICE_RUNNING) || + (dwCurrentState == SERVICE_STOPPED)) ? + 0 : dwCheckPoint++; + + // Report the status of the service to the SCM. + ::SetServiceStatus(m_statusHandle, &m_status); +} + + +// +// FUNCTION: CServiceBase::WriteEventLogEntry(PWSTR, WORD) +// +// PURPOSE: Log an event. +// +// PARAMETERS: +// * pszMessage - string message to be logged. +// * wType - the type of event to be logged. The parameter can be one of +// the following values. +// +// EVENTLOG_SUCCESS +// EVENTLOG_AUDIT_FAILURE +// EVENTLOG_AUDIT_SUCCESS +// EVENTLOG_ERROR_TYPE +// EVENTLOG_INFORMATION_TYPE +// EVENTLOG_WARNING_TYPE +// +void CServiceBase::WriteEventLogEntry( + _In_ PWSTR pszMessage, + _In_ BYTE bLevel) +{ + if (m_etwRegHandle != NULL) + { + EventWriteString(m_etwRegHandle, bLevel, 0, pszMessage); + } +} + +// +// FUNCTION: CServiceBase::WriteErrorLogEntry(PWSTR, DWORD) +// +// PURPOSE: Log an event. +// +// PARAMETERS: +// * pszFunction - the function that gives the error +// * dwError - the error code +// +void CServiceBase::WriteErrorLogEntry( + _In_ PWSTR pszFunction, + _In_ DWORD dwError) +{ + wchar_t szMessage[260]; + StringCchPrintf(szMessage, ARRAYSIZE(szMessage), + L"%s failed w/err 0x%08lx", pszFunction, dwError); + WriteEventLogEntry(szMessage, TRACE_LEVEL_ERROR); +} + +#pragma endregion
\ No newline at end of file |
