windows-nt/Source/XPSP1/NT/printscan/wia/common/stirt/svcinfo.cpp
2020-09-26 16:20:57 +08:00

691 lines
14 KiB
C++

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name :
svcinfo.cpp
Abstract:
This module contains the common code for the sti services which involves the
Service Controller dispatch functions.
Author:
Vlad Sadovsky (vlads) 22-Sep-1997
Environment:
User Mode - Win32
Revision History:
22-Sep-1997 VladS created
--*/
//
// Include Headers
//
#include "cplusinc.h"
#include "sticomm.h"
#include <svcinfo.h>
BOOL g_fIgnoreSC = TRUE;
SVC_INFO::SVC_INFO(
IN LPCTSTR lpszServiceName,
IN TCHAR * lpszModuleName,
IN PFN_SERVICE_SPECIFIC_INITIALIZE pfnInitialize,
IN PFN_SERVICE_SPECIFIC_CLEANUP pfnCleanup,
IN PFN_SERVICE_SPECIFIC_PNPPWRHANDLER pfnPnpPower
)
/*++
Desrcription:
Contructor for SVC_INFO class.
This constructs a new service info object for the service specified.
Arguments:
lpszServiceName
name of the service to be created.
lpszModuleName
name of the module for loading string resources.
pfnInitialize
pointer to function to be called for initialization of
service specific data
pfnCleanup
pointer to function to be called for cleanup of service
specific data
--*/
{
ASSERT( pfnInitialize != NULL && pfnCleanup != NULL && pfnPnpPower!=NULL);
m_sServiceName.Copy(lpszServiceName) ;
m_sModuleName.Copy(lpszModuleName);
//
// Initialize the service status structure.
//
m_svcStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS;
m_svcStatus.dwCurrentState = SERVICE_STOPPED;
m_svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_PAUSE_CONTINUE
| SERVICE_ACCEPT_SHUTDOWN;
m_svcStatus.dwWin32ExitCode = NO_ERROR;
m_svcStatus.dwServiceSpecificExitCode = NO_ERROR;
m_svcStatus.dwCheckPoint = 0;
m_svcStatus.dwWaitHint = 0;
//
// Initialize Call back functions
//
m_pfnInitialize = pfnInitialize;
m_pfnCleanup = pfnCleanup;
m_pfnPnpPower = pfnPnpPower;
m_dwSignature = SIGNATURE_SVC;
m_hShutdownEvent= NULL;
return;
} // SVC_INFO::SVC_INFO()
SVC_INFO::~SVC_INFO( VOID)
/*++
Description:
Cleanup the SvcInfo object. If the service is not already
terminated, it terminates the service before cleanup.
Arguments:
None
Returns:
None
--*/
{
if ( m_hShutdownEvent != NULL) {
::CloseHandle( m_hShutdownEvent);
}
m_dwSignature = SIGNATURE_SVC_FREE;
} // SVC_INFO::~SVC_INFO()
DWORD
SVC_INFO::StartServiceOperation(
IN PFN_SERVICE_CTRL_HANDLER pfnCtrlHandler
)
/*++
Description:
Starts the operation of service instantiated in the given
Service Info Object.
Arguments:
pfnCtrlHandler
pointer to a callback function for handling dispatch of
service controller requests. A separate function is required
since Service Controller call back function does not send
context information.
Returns:
NO_ERROR on success and Win32 error code if any failure.
--*/
{
DWORD err;
DWORD cbBuffer;
BOOL fInitCalled = FALSE;
if ( !IsValid()) {
//
// Not successfully initialized.
//
return ( ERROR_INVALID_FUNCTION);
}
if ( !g_fIgnoreSC ) {
m_hsvcStatus = RegisterServiceCtrlHandler(
QueryServiceName(),
pfnCtrlHandler
);
//
// Register the Control Handler routine.
//
if( m_hsvcStatus == NULL_SERVICE_STATUS_HANDLE ) {
err = GetLastError();
goto Cleanup;
}
} else {
m_hsvcStatus = NULL_SERVICE_STATUS_HANDLE;
}
//
// Update the service status.
//
err = UpdateServiceStatus( SERVICE_START_PENDING,
NO_ERROR,
1,
SERVICE_START_WAIT_HINT );
if( err != NO_ERROR ) {
goto Cleanup;
}
//
// Initialize the service common components
//
#ifdef BUGBUG
if ( !InitializeNTSecurity()) {
err = GetLastError();
goto Cleanup;
}
#endif
//
// Initialize the various service specific components.
//
err = ( *m_pfnInitialize)( this);
fInitCalled = TRUE;
if( err != NO_ERROR ) {
goto Cleanup;
}
//
// Create shutdown event.
//
m_hShutdownEvent = CreateEvent( NULL, // lpsaSecurity
TRUE, // fManualReset
FALSE, // fInitialState
NULL ); // lpszEventName
if( m_hShutdownEvent == NULL )
{
err = GetLastError();
goto Cleanup;
}
//
// Update the service status.
//
err = UpdateServiceStatus( SERVICE_RUNNING,
NO_ERROR,
0,
0 );
if( err != NO_ERROR ) {
goto Cleanup;
}
//
// Wait for the shutdown event.
//
err = WaitForSingleObject( m_hShutdownEvent,
INFINITE );
if ( err != WAIT_OBJECT_0) {
//
// Error. Unable to wait for single object.
//
}
//
// Stop time. Tell the Service Controller that we're stopping,
// then terminate the various service components.
//
UpdateServiceStatus( SERVICE_STOP_PENDING,
0,
1,
SERVICE_STOP_WAIT_HINT );
//
// Destroy the shutdown event.
//
if( m_hShutdownEvent != NULL ) {
if ( ! CloseHandle( m_hShutdownEvent ) ) {
err = GetLastError();
}
m_hShutdownEvent = NULL;
}
//
// Update the service status.
//
//
// Log successful start
err = UpdateServiceStatus( SERVICE_RUNNING,
NO_ERROR,
0,
0 );
if( err != NO_ERROR )
{
goto Cleanup;
}
return TRUE;
Cleanup:
if ( fInitCalled) {
//
// Cleanup partially initialized modules
//
DWORD err1 = ( *m_pfnCleanup)( this);
if ( err1 != NO_ERROR) {
//
// Compound errors possible
//
if ( err != NO_ERROR) {
}
}
}
//
// If we managed to actually connect to the Service Controller,
// then tell it that we're stopped.
//
if ( m_hsvcStatus != NULL_SERVICE_STATUS_HANDLE )
{
UpdateServiceStatus( SERVICE_STOPPED,
err,
0,
0 );
}
return ( err);
} // SVC_INFO::StartServiceOperation()
DWORD
SVC_INFO::UpdateServiceStatus(
IN DWORD dwState,
IN DWORD dwWin32ExitCode,
IN DWORD dwCheckPoint,
IN DWORD dwWaitHint )
/*++
Description:
Updates the local copy status of service controller status
and reports it to the service controller.
Arguments:
dwState - New service state.
dwWin32ExitCode - Service exit code.
dwCheckPoint - Check point for lengthy state transitions.
dwWaitHint - Wait hint for lengthy state transitions.
Returns:
NO_ERROR on success and returns Win32 error if failure.
On success the status is reported to service controller.
--*/
{
m_svcStatus.dwCurrentState = dwState;
m_svcStatus.dwWin32ExitCode = dwWin32ExitCode;
m_svcStatus.dwCheckPoint = dwCheckPoint;
m_svcStatus.dwWaitHint = dwWaitHint;
if ( !g_fIgnoreSC ) {
return ReportServiceStatus();
} else {
return ( NO_ERROR);
}
} // SVC_INFO::UpdateServiceStatus()
DWORD
SVC_INFO::ReportServiceStatus( VOID)
/*++
Description:
Wraps the call to SetServiceStatus() function.
Prints the service status data if need be
Arguments:
None
Returns:
NO_ERROR if successful. other Win32 error code on failure.
If successfull the new status has been reported to the service
controller.
--*/
{
DWORD err = NO_ERROR;
if ( !g_fIgnoreSC ) {
if( !SetServiceStatus( m_hsvcStatus, &m_svcStatus ) ) {
err = GetLastError();
}
} else {
err = NO_ERROR;
}
return err;
} // SVC_INFO::ReportServiceStatus()
VOID
SVC_INFO::ServiceCtrlHandler ( IN DWORD dwOpCode)
/*++
Description:
This function received control requests from the service controller.
It runs in the context of service controller's dispatcher thread and
performs the requested function.
( Note: Avoid time consuming operations in this function.)
Arguments:
dwOpCode
indicates the requested operation. This should be
one of the SERVICE_CONTROL_* manifests.
Returns:
None. If successful, then the state of the service might be changed.
Note:
if an operation ( especially SERVICE_CONTROL_STOP) is very lengthy,
then this routine should report a STOP_PENDING status and create
a worker thread to do the dirty work. The worker thread would then
perform the necessary work and for reporting timely wait hints and
final SERVICE_STOPPED status.
--*/
{
//
// Interpret the opcode.
//
switch( dwOpCode )
{
case SERVICE_CONTROL_INTERROGATE :
InterrogateService();
break;
case SERVICE_CONTROL_STOP :
StopService();
break;
case SERVICE_CONTROL_PAUSE :
PauseService();
break;
case SERVICE_CONTROL_CONTINUE :
ContinueService();
break;
case SERVICE_CONTROL_SHUTDOWN :
ShutdownService();
break;
default :
ASSERTSZ(FALSE,TEXT("Unrecognized Service Opcode"));
break;
}
//
// Report the current service status back to the Service
// Controller. The workers called to implement the OpCodes
// should set the m_svcStatus.dwCurrentState field if
// the service status changed.
//
ReportServiceStatus();
} // SVC_INFO::ServiceCtrlHandler()
VOID
SVC_INFO::InterrogateService( VOID )
/*++
Description:
This function interrogates with the service status.
Actually, nothing needs to be done here; the
status is always updated after a service control.
We have this function here to provide useful
debug info.
--*/
{
return;
} // SVC_INFO::InterrogateService()
VOID
SVC_INFO::StopService( VOID )
/*++
Description:
Stops the service. If the stop cannot be performed in a
timely manner, a worker thread needs to be created to do the
original cleanup work.
Returns:
None. If successful, then the service will be stopped.
The final action of this function is signal the handle for
shutdown event. This will release the main thread which does
necessary cleanup work.
--*/
{
m_svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
m_svcStatus.dwCheckPoint = 0;
SetEvent( m_hShutdownEvent);
return;
} // SVC_INFO::StopService()
VOID
SVC_INFO::PauseService( VOID )
/*++
Description:
This function pauses the service. When the service is paused,
no new user sessions are to be accepted, but existing connections
are not effected.
This function must update the SERVICE_STATUS::dwCurrentState
field before returning.
Returns:
None. If successful the service is paused.
--*/
{
m_svcStatus.dwCurrentState = SERVICE_PAUSED;
return;
} // SVC_INFO::PauseService()
VOID
SVC_INFO::ContinueService( VOID )
/*++
Description:
This function restarts ( continues) a paused service. This
will return the service to the running state.
This function must update the m_svcStatus.dwCurrentState
field to running mode before returning.
Returns:
None. If successful then the service is running.
--*/
{
m_svcStatus.dwCurrentState = SERVICE_RUNNING;
return;
} // SVC_INFO::ContinueService()
VOID
SVC_INFO::ShutdownService( VOID )
/*++
Description:
This function performs the shutdown on a service.
This is called during system shutdown.
This function is time constrained. The service controller gives a
maximum of 20 seconds for shutdown for all active services.
Only timely operations should be performed in this function.
Returns:
None. If successful, the service is shutdown.
--*/
{
DWORD dwCurrentState;
//
// Verify state of the service
//
dwCurrentState = QueryCurrentServiceState();
if ((dwCurrentState !=SERVICE_PAUSED) &&
(dwCurrentState !=SERVICE_RUNNING) ) {
ASSERT( FALSE);
return;
}
m_svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
m_svcStatus.dwCheckPoint = 0;
SetEvent( m_hShutdownEvent);
//
// Stop time. Tell the Service Controller that we're stopping,
// then terminate the various service components.
//
UpdateServiceStatus( SERVICE_STOP_PENDING,
0,
1,
SERVICE_STOP_WAIT_HINT );
DWORD err = ( *m_pfnCleanup)( this);
UpdateServiceStatus( SERVICE_STOPPED,
err,
0,
0 );
return;
} // SVC_INFO::ShutdownService()
//
// IUnknown methods. Used only for reference counting
//
STDMETHODIMP
SVC_INFO::QueryInterface( REFIID riid, LPVOID * ppvObj)
{
return E_FAIL;
}
STDMETHODIMP_(ULONG)
SVC_INFO::AddRef( void)
{
::InterlockedIncrement(&m_cRef);
return m_cRef;
}
STDMETHODIMP_(ULONG)
SVC_INFO::Release( void)
{
LONG cNew;
if(!(cNew = ::InterlockedDecrement(&m_cRef))) {
delete this;
}
return cNew;
}
/************************ End of File ***********************/