You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.4 KiB
181 lines
4.4 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "stdafx.h" |
|
#include "service_helpers.h" |
|
|
|
|
|
static CRITICAL_SECTION g_CtrlHandlerMutex; |
|
|
|
static void (*g_pInternalServiceFn)( void *pParam ) = NULL; |
|
static void *g_pInternalServiceParam = NULL; |
|
|
|
static volatile bool g_bShouldExit = false; |
|
|
|
|
|
SERVICE_STATUS MyServiceStatus; |
|
SERVICE_STATUS_HANDLE MyServiceStatusHandle = NULL; |
|
|
|
|
|
void WINAPI MyServiceCtrlHandler( DWORD Opcode ) |
|
{ |
|
DWORD status; |
|
|
|
switch(Opcode) |
|
{ |
|
case SERVICE_CONTROL_STOP: |
|
// Do whatever it takes to stop here. |
|
ServiceHelpers_ExitEarly(); |
|
|
|
MyServiceStatus.dwWin32ExitCode = 0; |
|
MyServiceStatus.dwCurrentState = SERVICE_STOPPED; |
|
|
|
if ( !SetServiceStatus( MyServiceStatusHandle, &MyServiceStatus) ) |
|
{ |
|
status = GetLastError(); |
|
Msg( "[MY_SERVICE] SetServiceStatus error %ld\n", status ); |
|
} |
|
|
|
Msg( "[MY_SERVICE] Leaving MyService \n" ); |
|
return; |
|
|
|
case SERVICE_CONTROL_INTERROGATE: |
|
// Fall through to send current status. |
|
break; |
|
|
|
default: |
|
Msg("[MY_SERVICE] Unrecognized opcode %ld\n", Opcode ); |
|
} |
|
|
|
// Send current status. |
|
if ( !SetServiceStatus( MyServiceStatusHandle, &MyServiceStatus ) ) |
|
{ |
|
status = GetLastError(); |
|
Msg( "[MY_SERVICE] SetServiceStatus error %ld\n", status ); |
|
} |
|
} |
|
|
|
|
|
void WINAPI MyServiceStart( DWORD argc, LPTSTR *argv ) |
|
{ |
|
DWORD status; |
|
|
|
MyServiceStatus.dwServiceType = SERVICE_WIN32; |
|
MyServiceStatus.dwCurrentState = SERVICE_START_PENDING; |
|
MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; |
|
MyServiceStatus.dwWin32ExitCode = 0; |
|
MyServiceStatus.dwServiceSpecificExitCode = 0; |
|
MyServiceStatus.dwCheckPoint = 0; |
|
MyServiceStatus.dwWaitHint = 0; |
|
|
|
MyServiceStatusHandle = RegisterServiceCtrlHandler( "MyService", MyServiceCtrlHandler ); |
|
if ( MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0 ) |
|
{ |
|
Msg("[MY_SERVICE] RegisterServiceCtrlHandler failed %d\n", GetLastError() ); |
|
return; |
|
} |
|
|
|
// Initialization complete - report running status. |
|
MyServiceStatus.dwCurrentState = SERVICE_RUNNING; |
|
|
|
if ( !SetServiceStatus( MyServiceStatusHandle, &MyServiceStatus ) ) |
|
{ |
|
status = GetLastError(); |
|
Msg( "[MY_SERVICE] SetServiceStatus error %ld\n", status ); |
|
} |
|
|
|
|
|
// Run the app's main in-thread loop. |
|
g_pInternalServiceFn( g_pInternalServiceParam ); |
|
|
|
|
|
// Tell the SCM that we're stopped. |
|
MyServiceStatus.dwCurrentState = SERVICE_STOPPED; |
|
MyServiceStatus.dwWin32ExitCode = NO_ERROR; |
|
MyServiceStatus.dwServiceSpecificExitCode = 0; |
|
SetServiceStatus( MyServiceStatusHandle, &MyServiceStatus ); |
|
|
|
|
|
// This is where the service does its work. |
|
Msg( "[MY_SERVICE] Returning the Main Thread \n" ); |
|
} |
|
|
|
|
|
void ServiceHelpers_Init() |
|
{ |
|
InitializeCriticalSection( &g_CtrlHandlerMutex ); |
|
} |
|
|
|
|
|
bool ServiceHelpers_StartService( const char *pServiceName, void (*pFn)( void *pParam ), void *pParam ) |
|
{ |
|
// Ok, just run the service. |
|
const SERVICE_TABLE_ENTRY DispatchTable[2] = |
|
{ |
|
{ (char*)pServiceName, MyServiceStart }, |
|
{ NULL, NULL } |
|
}; |
|
|
|
g_pInternalServiceFn = pFn; |
|
g_pInternalServiceParam = pParam; |
|
|
|
if ( StartServiceCtrlDispatcher( DispatchTable ) ) |
|
{ |
|
return true; |
|
} |
|
else |
|
{ |
|
Msg( "StartServiceCtrlDispatcher error = '%s'\n", GetLastErrorString() ); |
|
return false; |
|
} |
|
} |
|
|
|
|
|
void ServiceHelpers_ExitEarly() |
|
{ |
|
EnterCriticalSection( &g_CtrlHandlerMutex ); |
|
g_bShouldExit = true; |
|
LeaveCriticalSection( &g_CtrlHandlerMutex ); |
|
} |
|
|
|
|
|
bool ServiceHelpers_ShouldExit() |
|
{ |
|
EnterCriticalSection( &g_CtrlHandlerMutex ); |
|
bool bRet = g_bShouldExit; |
|
LeaveCriticalSection( &g_CtrlHandlerMutex ); |
|
|
|
return bRet; |
|
} |
|
|
|
|
|
char* GetLastErrorString() |
|
{ |
|
static char err[2048]; |
|
|
|
LPVOID lpMsgBuf; |
|
FormatMessage( |
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | |
|
FORMAT_MESSAGE_FROM_SYSTEM | |
|
FORMAT_MESSAGE_IGNORE_INSERTS, |
|
NULL, |
|
GetLastError(), |
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language |
|
(LPTSTR) &lpMsgBuf, |
|
0, |
|
NULL |
|
); |
|
|
|
strncpy( err, (char*)lpMsgBuf, sizeof( err ) ); |
|
LocalFree( lpMsgBuf ); |
|
|
|
err[ sizeof( err ) - 1 ] = 0; |
|
|
|
return err; |
|
} |
|
|
|
|
|
|