322 lines
12 KiB
C++
322 lines
12 KiB
C++
|
/*======================================================================================//
|
||
|
| //
|
||
|
|Copyright (c) 1998, 1999 Sequent Computer Systems, Incorporated. All rights reserved. //
|
||
|
| //
|
||
|
|Description: //
|
||
|
| //
|
||
|
|---------------------------------------------------------------------------------------//
|
||
|
; This file contains main(), ServiceMain(), and Service Start, Stop, and Control. //
|
||
|
|---------------------------------------------------------------------------------------//
|
||
|
| //
|
||
|
|Created: //
|
||
|
| //
|
||
|
| Jarl McDonald 07-98 //
|
||
|
| //
|
||
|
|Revision History: //
|
||
|
| //
|
||
|
|=======================================================================================*/
|
||
|
#include "ProcConSvc.h"
|
||
|
#include <shellapi.h>
|
||
|
|
||
|
//--------------------------------------------------------------------------------//
|
||
|
// Globals //
|
||
|
//--------------------------------------------------------------------------------//
|
||
|
BOOL svcStop = FALSE; // shows if stop has been issued
|
||
|
BOOL notService = FALSE; // TRUE if we're running as a console app
|
||
|
SERVICE_STATUS_HANDLE ssHandle; // service control handler
|
||
|
SERVICE_STATUS ssStatus; // current service status
|
||
|
PCULONG32 ssErrCode = 0; // error code for status reporting
|
||
|
|
||
|
CProcCon *cPCptr = NULL; // Pointer to give service rtns access
|
||
|
|
||
|
static void
|
||
|
Usage( void )
|
||
|
{
|
||
|
DWORD numWritten;
|
||
|
DWORD numToWrite;
|
||
|
HANDLE StdOut;
|
||
|
|
||
|
StdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||
|
numToWrite = _tcslen(PROCCON_SERVICE_USAGE);
|
||
|
if (! WriteConsole(StdOut,
|
||
|
PROCCON_SERVICE_USAGE,
|
||
|
numToWrite,
|
||
|
&numWritten,
|
||
|
0)) {
|
||
|
WriteFile(StdOut,
|
||
|
PROCCON_SERVICE_USAGE,
|
||
|
numToWrite * sizeof(TCHAR),
|
||
|
&numWritten,
|
||
|
NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// main function -- initiate requested action: install, remove, run as console app, run as service
|
||
|
//
|
||
|
// Input: none -- args retrieved via GetCommandLine
|
||
|
// Returns: no return value
|
||
|
//
|
||
|
void _cdecl main( void )
|
||
|
{
|
||
|
// Load our strings so we have proper reporting, etc.
|
||
|
PCLoadStrings();
|
||
|
|
||
|
int argc;
|
||
|
TCHAR *cmdLine = GetCommandLineW();
|
||
|
TCHAR **argv = CommandLineToArgvW( cmdLine, &argc );
|
||
|
if (!argv) {
|
||
|
Usage();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// See if a command line command was given -- only true if a switch (- or /)...
|
||
|
if ( argc > 1 && (argv[1][0] == '-' || argv[1][0] == '/') ) {
|
||
|
if ( !_tcsicmp( TEXT("install"), argv[1] + 1 ) ) PCInstallService( argc - 2, &argv[2] );
|
||
|
else if ( !_tcsicmp( TEXT("remove"), argv[1] + 1 ) ) PCRemoveService( argc - 2, &argv[2] );
|
||
|
else if ( !_tcsicmp( TEXT("reinstall"), argv[1] + 1 ) ) {
|
||
|
PCRemoveService( argc - 2, &argv[2] );
|
||
|
PCInstallService( argc - 2, &argv[2] );
|
||
|
}
|
||
|
#ifdef _DEBUG
|
||
|
else if ( !_tcsicmp( TEXT("noservice"), argv[1] + 1 ) ) PCConsoleService( argc - 2, &argv[2] );
|
||
|
#endif
|
||
|
else Usage();
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// No command line -- we are to run as a service...
|
||
|
|
||
|
// Then kick things off...
|
||
|
static SERVICE_TABLE_ENTRY dispTbl[] = {
|
||
|
{ const_cast <TCHAR *> (PROCCON_SVC_NAME), (LPSERVICE_MAIN_FUNCTION) PCServiceMain },
|
||
|
{ NULL, NULL }
|
||
|
};
|
||
|
|
||
|
if ( !StartServiceCtrlDispatcher( dispTbl ) ) {
|
||
|
ssErrCode = GetLastError();
|
||
|
PCLogMessage( PC_SERVICE_DISPATCH_ERROR, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME,
|
||
|
sizeof(ssErrCode), &ssErrCode );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// PCServiceMain -- our main service routine -- will start processing
|
||
|
//
|
||
|
// Input: argc, argv (now as PCULONG32 and TCHAR).
|
||
|
// Returns: no return value
|
||
|
//
|
||
|
void WINAPI PCServiceMain( PCULONG32 Argc, LPTSTR *Argv ) {
|
||
|
|
||
|
// register our service control handler...
|
||
|
ssHandle = RegisterServiceCtrlHandler( PROCCON_SVC_NAME, PCServiceControl );
|
||
|
|
||
|
if ( ssHandle ) {
|
||
|
// Initialize fixed-value status members...
|
||
|
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||
|
ssStatus.dwServiceSpecificExitCode = 0;
|
||
|
|
||
|
// request handling of alignment errors. We know we have som issues on IA64 machines.
|
||
|
SetErrorMode(SEM_NOALIGNMENTFAULTEXCEPT);
|
||
|
|
||
|
// report status to the service control manager and start service...
|
||
|
if ( PCReportStatus( SERVICE_START_PENDING, NO_ERROR, 3000) )
|
||
|
PCStartService( Argc, Argv );
|
||
|
|
||
|
if ( svcStop )
|
||
|
PCLogMessage( PC_SERVICE_STOPPED, EVENTLOG_INFORMATION_TYPE, 1, PROCCON_SVC_DISP_NAME );
|
||
|
|
||
|
// report stopped status to the service control manager...
|
||
|
PCReportStatus( SERVICE_STOPPED, ssErrCode, 0 );
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//=======================================================================================//
|
||
|
// The Process Management app start point
|
||
|
//
|
||
|
// Input: argc, argv (now as PCULONG32 and TCHAR, both ignored)
|
||
|
// Returns: no return value
|
||
|
//
|
||
|
void PCStartService( PCULONG32 Argc, LPTSTR *Argv ) {
|
||
|
|
||
|
// See that we are running under Windows 2000 Datacenter Server only...
|
||
|
#if !defined(_DEBUG) && !defined(IBM_NUMAQ_PC)
|
||
|
if ( !PCTestOSVersion() ) {
|
||
|
PCLogMessage( PC_SERVICE_UNSUPPORTED_WINDOWS_VERSION, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME );
|
||
|
//ssErrCode = ERROR_BAD_ENVIRONMENT; // have to use an NT error to get SCM to put it in the event log nicely
|
||
|
return;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Make sure we are not already running and set up mutual exclusion...
|
||
|
// If the process is started twice in service mode the
|
||
|
// SCM will enforce the single instance rule but we could be burned
|
||
|
// by a debug version.
|
||
|
// It appears to take the system longer to clean up the orphaned event
|
||
|
// then it take SCM to realize the service crashed, is not running, and
|
||
|
// can be started again.
|
||
|
// If we exit we don't report status to SCM and that's not good.
|
||
|
if (!PCSetIsRunning( PROCCON_SVC_EXCLUSION, PROCCON_SVC_DISP_NAME )) {
|
||
|
// ssErrCode = ERROR_ALREADY_EXISTS; // have to use an NT error to get SCM to put it in the event log nicely
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Instantiate ourselves and test for success...
|
||
|
//
|
||
|
CProcCon cPC;
|
||
|
if ( !cPC.ReadyToRun() ) {
|
||
|
PCLogMessage( PC_STARTUP_FAILED, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME );
|
||
|
// ssErrCode = ; // have to use an NT error to get SCM to put it in the event log nicely
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
cPCptr = &cPC; // set global pointer for Service Stop usage
|
||
|
|
||
|
// We are ready to start processing so set service started...
|
||
|
if ( !PCReportStatus( SERVICE_RUNNING, NO_ERROR, 0) ) {
|
||
|
// no likely recovery...
|
||
|
cPC.HardStop(ssErrCode);
|
||
|
cPCptr = NULL; // not necesary
|
||
|
return;
|
||
|
}
|
||
|
else if ( !notService )
|
||
|
PCLogMessage( PC_SERVICE_STARTED, EVENTLOG_INFORMATION_TYPE, 1, PROCCON_SVC_DISP_NAME );
|
||
|
|
||
|
//
|
||
|
// Main service process...
|
||
|
//
|
||
|
cPC.Run();
|
||
|
cPCptr = NULL; // a reminder that the global pointer references a stack variable
|
||
|
}
|
||
|
|
||
|
//=============================================================================================
|
||
|
// function to initiate service stop.
|
||
|
//
|
||
|
// Input: none
|
||
|
// Returns: nothing
|
||
|
// Note: what's done here must not take longer than 3 seconds by NT service rules
|
||
|
//
|
||
|
VOID PCStopService()
|
||
|
{
|
||
|
svcStop = TRUE;
|
||
|
if ( cPCptr )
|
||
|
cPCptr->Stop();
|
||
|
}
|
||
|
|
||
|
//=============================================================================================
|
||
|
// function to handle ControlService for us.
|
||
|
//
|
||
|
// Input: control code
|
||
|
// Returns: nothing
|
||
|
//
|
||
|
void WINAPI PCServiceControl( PCULONG32 dwCtrlCode ) {
|
||
|
// Handle the requested control code.
|
||
|
//
|
||
|
switch(dwCtrlCode)
|
||
|
{
|
||
|
// Stop or shutdown the service...
|
||
|
case SERVICE_CONTROL_STOP:
|
||
|
case SERVICE_CONTROL_SHUTDOWN:
|
||
|
PCReportStatus( SERVICE_STOP_PENDING, NO_ERROR, 0 );
|
||
|
PCStopService();
|
||
|
return;
|
||
|
|
||
|
// Other standard control codes...
|
||
|
case SERVICE_CONTROL_PAUSE:
|
||
|
case SERVICE_CONTROL_CONTINUE:
|
||
|
case SERVICE_CONTROL_INTERROGATE:
|
||
|
break;
|
||
|
|
||
|
// invalid or user control codes...
|
||
|
default:
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
PCReportStatus(ssStatus.dwCurrentState, NO_ERROR, 0);
|
||
|
}
|
||
|
|
||
|
//=============================================================================================
|
||
|
// function to handle service status reporting to NT
|
||
|
//
|
||
|
// Input: current state, exit code, wait hint
|
||
|
// Returns: TRUE if status reported (or not a service), else FALSE
|
||
|
//
|
||
|
//
|
||
|
BOOL PCReportStatus( PCULONG32 dwCurrentState, PCULONG32 dwWin32ExitCode, PCULONG32 dwWaitHint ) {
|
||
|
static PCULONG32 dwCheckPoint = 1;
|
||
|
BOOL fResult = TRUE;
|
||
|
|
||
|
if ( !notService ) {
|
||
|
ssStatus.dwControlsAccepted = dwCurrentState == SERVICE_RUNNING? SERVICE_ACCEPT_STOP : 0;
|
||
|
ssStatus.dwCurrentState = dwCurrentState;
|
||
|
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||
|
ssStatus.dwWaitHint = dwWaitHint;
|
||
|
|
||
|
if ( dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED )
|
||
|
ssStatus.dwCheckPoint = 0;
|
||
|
else
|
||
|
ssStatus.dwCheckPoint = dwCheckPoint++;
|
||
|
|
||
|
|
||
|
// Report the status of the service to the service control manager.
|
||
|
//
|
||
|
if ( !(fResult = SetServiceStatus( ssHandle, &ssStatus )) ) {
|
||
|
ssErrCode = GetLastError();
|
||
|
PCLogMessage( PC_SERVICE_STATUS_ERROR, EVENTLOG_ERROR_TYPE, 1, PROCCON_SVC_DISP_NAME,
|
||
|
sizeof(ssErrCode), &ssErrCode );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
//=============================================================================================
|
||
|
// FUNCTION: PCConsoleService -- run the service as a console application instead.
|
||
|
//
|
||
|
// Input: standard argc, argv
|
||
|
// Returns: no return value
|
||
|
//
|
||
|
void PCConsoleService(int argc, TCHAR **argv) {
|
||
|
|
||
|
notService = TRUE;
|
||
|
|
||
|
SetConsoleCtrlHandler( PCControlHandler, TRUE );
|
||
|
|
||
|
// Set privileges we may need when not a service under LocalSystem...
|
||
|
PCSetPrivilege( SE_DEBUG_NAME, TRUE );
|
||
|
PCSetPrivilege( SE_INC_BASE_PRIORITY_NAME, TRUE );
|
||
|
|
||
|
PCStartService( argc, argv );
|
||
|
}
|
||
|
|
||
|
//=============================================================================================
|
||
|
// function to handle console ctrl-C and break to simulate service stop when in console mode.
|
||
|
//
|
||
|
// Input: control code
|
||
|
// Returns: TRUE if handled, FALSE if not
|
||
|
//
|
||
|
BOOL WINAPI PCControlHandler( PCULONG32 dwCtrlType ) {
|
||
|
switch( dwCtrlType )
|
||
|
{
|
||
|
case CTRL_BREAK_EVENT:
|
||
|
case CTRL_C_EVENT:
|
||
|
PCStopService();
|
||
|
return TRUE;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// End of PCMain.cpp
|
||
|
//============================================================================J McDonald fecit====//
|
||
|
|
||
|
|