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;
|
|
}
|
|
|
|
|