765 lines
19 KiB
C++
765 lines
19 KiB
C++
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
service.cpp
|
|
|
|
Abstract:
|
|
|
|
This file provides access to the service control
|
|
manager for starting, stopping, adding, and removing
|
|
services.
|
|
|
|
Environment:
|
|
|
|
WIN32 User Mode
|
|
|
|
Author:
|
|
|
|
Vlad Sadovsky (vlads) 17-Apr-1998
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Precompiled header
|
|
//
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// Include
|
|
//
|
|
|
|
#include "sti_ci.h"
|
|
#include "device.h"
|
|
|
|
#include <regstr.h>
|
|
|
|
#include <sti.h>
|
|
#include <stiregi.h>
|
|
#include <stilib.h>
|
|
#include <stidebug.h>
|
|
#include <stiapi.h>
|
|
#include <stisvc.h>
|
|
|
|
#include <eventlog.h>
|
|
|
|
//
|
|
// Extern
|
|
//
|
|
|
|
extern HINSTANCE g_hDllInstance;
|
|
|
|
|
|
//
|
|
// Prototype
|
|
//
|
|
|
|
DWORD
|
|
SetServiceSecurity(
|
|
LPTSTR AccountName
|
|
);
|
|
|
|
DLLEXPORT
|
|
VOID
|
|
CALLBACK
|
|
InstallWiaService(
|
|
HWND hwnd,
|
|
HINSTANCE hinst,
|
|
LPTSTR lpszCmdLine,
|
|
int nCmdShow
|
|
);
|
|
|
|
//
|
|
// Function
|
|
//
|
|
|
|
DWORD
|
|
WINAPI
|
|
StiServiceInstall(
|
|
BOOL UseLocalSystem,
|
|
BOOL DemandStart,
|
|
LPTSTR lpszUserName,
|
|
LPTSTR lpszUserPassword
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Service installation function.
|
|
Calls SCM to install STI service, which is running in user security context
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
DWORD dwError = NOERROR;
|
|
|
|
SC_HANDLE hSCM = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
SERVICE_DESCRIPTION ServiceDescroption;
|
|
TCHAR szServiceDesc[MAX_PATH];
|
|
TCHAR szServiceName[MAX_PATH];
|
|
|
|
|
|
__try {
|
|
|
|
hSCM = ::OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (!hSCM) {
|
|
dwError = GetLastError();
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// If service already exists change startup type, else CreateService.
|
|
// NOTE: The service should already be installed - if it isn't, we're
|
|
// patching it here because it MUST be installed in order to use WIA.
|
|
//
|
|
|
|
hService = OpenService(
|
|
hSCM,
|
|
STI_SERVICE_NAME,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
if (hService) {
|
|
|
|
//
|
|
// Change the service config parameters. Note: we're only changing StartType
|
|
//
|
|
|
|
if (!ChangeServiceConfig(hService, // handle to WIA service
|
|
SERVICE_NO_CHANGE, // Don't change ServiceType
|
|
DemandStart ? SERVICE_DEMAND_START : SERVICE_AUTO_START, // Change StartType
|
|
SERVICE_NO_CHANGE, // Don't change ErrorControl
|
|
NULL, // Don't change BinaryPathName
|
|
NULL, // Don't change LoadOrderGroup
|
|
NULL, // Don't change TagId
|
|
NULL, // Don't change Dependencies
|
|
NULL, // Don't change ServiceStartName
|
|
NULL, // Don't change Password
|
|
NULL)) { // Don't change DisplayName
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceInstall: ChangeServiceConfig() failed. Err=0x%x.\r\n"), dwError));
|
|
__leave;
|
|
} // if (!ChangeServiceConfig(...))
|
|
|
|
} else {
|
|
//
|
|
// If use local system - set security
|
|
//
|
|
|
|
if (!UseLocalSystem) {
|
|
#ifdef LATER
|
|
dwError = SetServiceSecurity( lpszUserName );
|
|
if (dwError) {
|
|
dwError = ERROR_SERVICE_LOGON_FAILED ;
|
|
__leave;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Load service name.
|
|
//
|
|
|
|
if(0 == LoadString(g_hDllInstance, WiaServiceName, szServiceName, MAX_PATH)){
|
|
dwError = GetLastError();
|
|
__leave;
|
|
} // if(0 != LoadString(g_hDllInstance, WiaServiceName, szServiceName, MAX_PATH))
|
|
|
|
hService = CreateService(
|
|
hSCM,
|
|
STI_SERVICE_NAME,
|
|
szServiceName,
|
|
SERVICE_ALL_ACCESS,
|
|
STI_SVC_SERVICE_TYPE,
|
|
DemandStart ? SERVICE_DEMAND_START : SERVICE_AUTO_START,
|
|
SERVICE_ERROR_NORMAL,
|
|
STI_IMAGE_NAME_SVCHOST,
|
|
NULL,
|
|
NULL,
|
|
STI_SVC_DEPENDENCIES, //STI_SERVICE_DEPENDENCY,
|
|
UseLocalSystem ? NULL : lpszUserName,
|
|
UseLocalSystem ? NULL : lpszUserPassword
|
|
);
|
|
|
|
if (!hService) {
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceInstall: CreateService() failed. Err=0x%x.\r\n"), dwError));
|
|
__leave;
|
|
}
|
|
|
|
//
|
|
// Load service description.
|
|
//
|
|
|
|
if(0 != LoadString(g_hDllInstance, WiaServiceDescription, szServiceDesc, MAX_PATH)){
|
|
|
|
//
|
|
// Change service description.
|
|
//
|
|
|
|
ServiceDescroption.lpDescription = (LPTSTR)szServiceDesc;
|
|
ChangeServiceConfig2(hService,
|
|
SERVICE_CONFIG_DESCRIPTION,
|
|
(LPVOID)&ServiceDescroption);
|
|
} // if(0 != LoadString(g_hDllInstance, WiaServiceDescription, szServiceDesc, MAX_PATH))
|
|
}
|
|
|
|
//
|
|
// Add registry settings for event logging
|
|
//
|
|
|
|
RegisterStiEventSources();
|
|
|
|
//
|
|
// Start service if AUTO_START.
|
|
//
|
|
|
|
if(FALSE == DemandStart){
|
|
if(!StartService(hService,0,(LPCTSTR *)NULL)){
|
|
dwError = GetLastError();
|
|
} // if(!StartService(hService,0,(LPCTSTR *)NULL))
|
|
} // if(FALSE == DemandStart)
|
|
}
|
|
__finally {
|
|
//
|
|
// Close service handle.
|
|
//
|
|
|
|
if (NULL != hService) {
|
|
CloseServiceHandle(hService);
|
|
} // if(NULL != hService)
|
|
|
|
if(NULL != hSCM){
|
|
CloseServiceHandle( hSCM );
|
|
} // if(NULL != hSCM)
|
|
}
|
|
|
|
return dwError;
|
|
|
|
} //StiServiceInstall
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
StiServiceRemove(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Service removal function. This function calls SCM to remove the STI service.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
Return code. Return zero for success
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwError = NOERROR;
|
|
|
|
SC_HANDLE hSCM = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
SERVICE_STATUS ServiceStatus;
|
|
UINT uiRetry = 10;
|
|
|
|
HKEY hkRun;
|
|
|
|
__try {
|
|
|
|
hSCM = ::OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
|
|
|
if (!hSCM) {
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceRemove: OpenSCManager() failed. Err=0x%x.\r\n"), dwError));
|
|
__leave;
|
|
}
|
|
|
|
hService = OpenService(
|
|
hSCM,
|
|
STI_SERVICE_NAME,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
if (!hService) {
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceRemove: OpenService() failed. Err=0x%x.\r\n"), dwError));
|
|
__leave;
|
|
}
|
|
|
|
|
|
//
|
|
// Stop service first
|
|
//
|
|
|
|
if (ControlService( hService, SERVICE_CONTROL_STOP, &ServiceStatus )) {
|
|
|
|
//
|
|
// Wait a little
|
|
//
|
|
|
|
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
|
|
while( QueryServiceStatus( hService, &ServiceStatus ) &&
|
|
(SERVICE_STOP_PENDING == ServiceStatus.dwCurrentState)) {
|
|
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
|
|
if (!uiRetry--) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceRemove: Unable to stop service. Err=0x%x.\r\n"), dwError));
|
|
if(ServiceStatus.dwCurrentState != ERROR_SERVICE_NOT_ACTIVE) {
|
|
__leave;
|
|
} // if(ServiceStatus.dwCurrentState != ERROR_SERVICE_NOT_ACTIVE)
|
|
} // if (ServiceStatus.dwCurrentState != SERVICE_STOPPED)
|
|
|
|
} else { // if (ControlService( hService, SERVICE_CONTROL_STOP, &ServiceStatus ))
|
|
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceRemove: ControlService() failed. Err=0x%x.\r\n"), dwError));
|
|
|
|
//
|
|
// If service hasn't been started yet, just ignore.
|
|
//
|
|
|
|
if(ERROR_SERVICE_NOT_ACTIVE != dwError){
|
|
__leave;
|
|
}
|
|
}
|
|
|
|
if (!DeleteService( hService )) {
|
|
dwError = GetLastError();
|
|
DebugTrace(TRACE_ERROR,(("StiServiceRemove: DeleteService() failed. Err=0x%x.\r\n"), dwError));
|
|
__leave;
|
|
} else {
|
|
dwError = NOERROR;
|
|
}
|
|
}
|
|
__finally {
|
|
if(NULL != hService){
|
|
CloseServiceHandle( hService );
|
|
}
|
|
if(NULL != hSCM){
|
|
CloseServiceHandle( hSCM );
|
|
}
|
|
} // __finally
|
|
|
|
//
|
|
// Leftovers from Win9x - remove STI monitor from Run section
|
|
//
|
|
if (RegOpenKey(HKEY_LOCAL_MACHINE, REGSTR_PATH_RUN, &hkRun) == NO_ERROR) {
|
|
|
|
RegDeleteValue (hkRun, REGSTR_VAL_MONITOR);
|
|
RegCloseKey(hkRun);
|
|
}
|
|
|
|
return dwError;
|
|
|
|
} // StiServiceRemove
|
|
|
|
|
|
BOOL
|
|
SetServiceDependency(
|
|
LPTSTR ServiceName,
|
|
LPTSTR DependentServiceName
|
|
)
|
|
{
|
|
BOOL rVal = FALSE;
|
|
SC_HANDLE hSvcMgr = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
|
|
hSvcMgr = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS
|
|
);
|
|
if (!hSvcMgr) {
|
|
goto exit;
|
|
}
|
|
|
|
hService = OpenService(
|
|
hSvcMgr,
|
|
ServiceName,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (!hService) {
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if (!ChangeServiceConfig(
|
|
hService, // handle to service
|
|
SERVICE_NO_CHANGE, // type of service
|
|
SERVICE_NO_CHANGE, // when to start service
|
|
SERVICE_NO_CHANGE, // severity if service fails to start
|
|
NULL, // pointer to service binary file name
|
|
NULL, // pointer to load ordering group name
|
|
NULL, // pointer to variable to get tag identifier
|
|
DependentServiceName, // pointer to array of dependency names
|
|
NULL, // pointer to account name of service
|
|
NULL, // pointer to password for service account
|
|
NULL // pointer to display name
|
|
)) {
|
|
goto exit;
|
|
}
|
|
|
|
rVal = TRUE;
|
|
|
|
exit:
|
|
if(NULL != hService){
|
|
CloseServiceHandle( hService );
|
|
}
|
|
if(NULL != hSvcMgr){
|
|
CloseServiceHandle( hSvcMgr );
|
|
}
|
|
|
|
return rVal;
|
|
}
|
|
|
|
|
|
BOOL
|
|
SetServiceStart(
|
|
LPTSTR ServiceName,
|
|
DWORD StartType
|
|
)
|
|
{
|
|
BOOL rVal = FALSE;
|
|
SC_HANDLE hSvcMgr = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
|
|
|
|
hSvcMgr = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS
|
|
);
|
|
if (!hSvcMgr) {
|
|
goto exit;
|
|
}
|
|
|
|
hService = OpenService(
|
|
hSvcMgr,
|
|
ServiceName,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (!hService) {
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if (!ChangeServiceConfig(
|
|
hService, // handle to service
|
|
SERVICE_NO_CHANGE, // type of service
|
|
StartType, // when to start service
|
|
SERVICE_NO_CHANGE, // severity if service fails to start
|
|
NULL, // pointer to service binary file name
|
|
NULL, // pointer to load ordering group name
|
|
NULL, // pointer to variable to get tag identifier
|
|
NULL, // pointer to array of dependency names
|
|
NULL, // pointer to account name of service
|
|
NULL, // pointer to password for service account
|
|
NULL // pointer to display name
|
|
))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
rVal = TRUE;
|
|
|
|
exit:
|
|
if(NULL != hService){
|
|
CloseServiceHandle( hService );
|
|
}
|
|
if(NULL != hSvcMgr){
|
|
CloseServiceHandle( hSvcMgr );
|
|
}
|
|
|
|
return rVal;
|
|
}
|
|
|
|
BOOL
|
|
StartWiaService(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL rVal = FALSE;
|
|
SC_HANDLE hSvcMgr = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
SERVICE_STATUS ServiceStatus;
|
|
UINT uiRetry = 40; // start time is much larger than stop time.
|
|
// Setting 40 sec just to be safe.
|
|
|
|
|
|
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,(("StartWiaService: Enter... \r\n")));
|
|
|
|
//
|
|
// Open Service Control Manager.
|
|
//
|
|
|
|
hSvcMgr = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS
|
|
);
|
|
if (!hSvcMgr) {
|
|
DebugTrace(TRACE_ERROR,(("StartWiaService: ERROR!! OpenSCManager failed. Err=0x%x\n"), GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open WIA service.
|
|
//
|
|
|
|
hService = OpenService(
|
|
hSvcMgr,
|
|
STI_SERVICE_NAME,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (!hService) {
|
|
DebugTrace(TRACE_ERROR,(("StartWiaService: ERROR!! OpenService failed, re-creating Service Entry (Err=0x%x)\n"), GetLastError()));
|
|
|
|
//
|
|
// Attempt to re-install service
|
|
//
|
|
|
|
InstallWiaService(NULL,
|
|
NULL,
|
|
NULL,
|
|
0);
|
|
Sleep(3000);
|
|
|
|
//
|
|
// Try to open it again
|
|
//
|
|
hService = OpenService(
|
|
hSvcMgr,
|
|
STI_SERVICE_NAME,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (!hService) {
|
|
DebugTrace(TRACE_ERROR,(("StartWiaService: ERROR!! OpenService failed for the second time. Err=0x%x\n"), GetLastError()));
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
rVal = StartService(hService,
|
|
0,
|
|
(LPCTSTR *)NULL);
|
|
if(!rVal){
|
|
DebugTrace(TRACE_STATUS,(("StartWiaService: ERROR!! StartService failed. Err=0x%x\n"), GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Wait for WIA service to really start.
|
|
//
|
|
|
|
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
|
|
while( QueryServiceStatus( hService, &ServiceStatus ) &&
|
|
(SERVICE_START_PENDING == ServiceStatus.dwCurrentState)) {
|
|
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
|
|
if (!uiRetry--) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ServiceStatus.dwCurrentState != SERVICE_RUNNING) {
|
|
DebugTrace(TRACE_ERROR,(("StartWiaService: ERROR!! Hit timeout to start service. Err=0x%x\n"), GetLastError()));
|
|
}
|
|
|
|
|
|
exit:
|
|
if(NULL != hService){
|
|
CloseServiceHandle( hService );
|
|
}
|
|
if(NULL != hSvcMgr){
|
|
CloseServiceHandle( hSvcMgr );
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,(("StartWiaService: Leaving... Ret=0x%x\n"), rVal));
|
|
return rVal;
|
|
}
|
|
|
|
|
|
BOOL
|
|
StopWiaService(
|
|
VOID
|
|
)
|
|
{
|
|
BOOL rVal = FALSE;
|
|
SC_HANDLE hSvcMgr = NULL;
|
|
SC_HANDLE hService = NULL;
|
|
SERVICE_STATUS ServiceStatus;
|
|
UINT uiRetry = 10;
|
|
|
|
DebugTrace(TRACE_PROC_ENTER,(("StopWiaService: Enter... \r\n")));
|
|
|
|
//
|
|
// Open Service Control Manager.
|
|
//
|
|
|
|
hSvcMgr = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS
|
|
);
|
|
if (!hSvcMgr) {
|
|
DebugTrace(TRACE_ERROR,(("StopWiaService: ERROR!! OpenSCManager failed. Err=0x%x\n"), GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Open WIA service.
|
|
//
|
|
|
|
hService = OpenService(
|
|
hSvcMgr,
|
|
STI_SERVICE_NAME,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (!hService) {
|
|
DebugTrace(TRACE_ERROR,(("StopWiaService: ERROR!! OpenService failed. Err=0x%x\n"), GetLastError()));
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// Stop WIA service.
|
|
//
|
|
|
|
rVal = ControlService(hService,
|
|
SERVICE_CONTROL_STOP,
|
|
&ServiceStatus);
|
|
if(!rVal){
|
|
DebugTrace(TRACE_ERROR,(("StopWiaService: ERROR!! ControlService failed. Err=0x%x\n"), GetLastError()));
|
|
} else {
|
|
|
|
//
|
|
// Wait for WIA service really stops.
|
|
//
|
|
|
|
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
|
|
|
|
ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
|
|
|
|
while( QueryServiceStatus( hService, &ServiceStatus ) &&
|
|
(SERVICE_STOP_PENDING == ServiceStatus.dwCurrentState)) {
|
|
Sleep( STI_STOP_FOR_REMOVE_TIMEOUT );
|
|
if (!uiRetry--) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ServiceStatus.dwCurrentState != SERVICE_STOPPED) {
|
|
DebugTrace(TRACE_ERROR,(("StopWiaService: ERROR!! Hit timeout to stop service. Err=0x%x\n"), GetLastError()));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if(NULL != hService){
|
|
CloseServiceHandle( hService );
|
|
}
|
|
if(NULL != hSvcMgr){
|
|
CloseServiceHandle( hSvcMgr );
|
|
}
|
|
|
|
DebugTrace(TRACE_PROC_LEAVE,(("StopWiaService: Leaving... Ret=0x%x\n"), rVal));
|
|
return rVal;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
BOOL
|
|
SetServiceAccount(
|
|
LPTSTR ServiceName,
|
|
PSECURITY_INFO SecurityInfo
|
|
)
|
|
{
|
|
BOOL rVal = FALSE;
|
|
SC_HANDLE hSvcMgr;
|
|
SC_HANDLE hService;
|
|
|
|
|
|
hSvcMgr = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
SC_MANAGER_ALL_ACCESS
|
|
);
|
|
if (!hSvcMgr) {
|
|
goto exit;
|
|
}
|
|
|
|
hService = OpenService(
|
|
hSvcMgr,
|
|
ServiceName,
|
|
SERVICE_ALL_ACCESS
|
|
);
|
|
|
|
if (!hService) {
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if (!ChangeServiceConfig(
|
|
hService, // handle to service
|
|
SERVICE_NO_CHANGE, // type of service
|
|
SERVICE_NO_CHANGE, // when to start service
|
|
SERVICE_NO_CHANGE, // severity if service fails to start
|
|
NULL, // pointer to service binary file name
|
|
NULL, // pointer to load ordering group name
|
|
NULL, // pointer to variable to get tag identifier
|
|
NULL, // pointer to array of dependency names
|
|
SecurityInfo->AccountName, // pointer to account name of service
|
|
SecurityInfo->Password, // pointer to password for service account
|
|
NULL // pointer to display name
|
|
)) {
|
|
goto exit;
|
|
}
|
|
|
|
rVal = TRUE;
|
|
|
|
exit:
|
|
CloseServiceHandle( hService );
|
|
CloseServiceHandle( hSvcMgr );
|
|
|
|
return rVal;
|
|
}
|
|
|
|
*/
|