source-engine/utils/vmpi/vmpi_service/service_helpers.cpp

182 lines
4.4 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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;
}