|
|
/*======================================================================================//
| //
|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====//
|