1020 lines
29 KiB
C
1020 lines
29 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
services.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Routines to deal with the Windows NT service controller
|
||
|
and service entries in the registry,
|
||
|
|
||
|
Externally exposed routines:
|
||
|
|
||
|
MyCreateService
|
||
|
MyChangeServiceStart
|
||
|
MyChangeServiceConfig
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Ted Miller (tedm) 5-Apr-1995
|
||
|
adapted from legacy\dll\sc.c
|
||
|
|
||
|
Revision History:
|
||
|
Dan Elliott (dane) 14-Aug-2000 Added WaitForScmInitialization().
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "setupp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//
|
||
|
// Constants used in logging specific to this module.
|
||
|
//
|
||
|
PCWSTR szOpenSCManager = L"OpenSCManager";
|
||
|
PCWSTR szCreateService = L"CreateService";
|
||
|
PCWSTR szChangeServiceConfig = L"ChangeServiceConfig";
|
||
|
PCWSTR szOpenService = L"OpenService";
|
||
|
PCWSTR szStartService = L"StartService";
|
||
|
PCWSTR szEnumDependentService= L"EnumDependentService";
|
||
|
|
||
|
PCWSTR szServicesKeyPath = L"SYSTEM\\CurrentControlSet\\Services";
|
||
|
PCWSTR szDependOnService = L"DependOnService";
|
||
|
PCWSTR szServicesToRename = L"ServicesToRename";
|
||
|
|
||
|
BOOL
|
||
|
pSetupWaitForScmInitialization()
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Wait for services.exe to signal that the Services Control Manager is
|
||
|
running and autostart services have been started.
|
||
|
|
||
|
Arguments:
|
||
|
None.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Boolean indicating whether the the SCM was started successfully.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
HANDLE hEventHandle;
|
||
|
DWORD WaitStatus;
|
||
|
|
||
|
hEventHandle = OpenEvent( SYNCHRONIZE, FALSE, SC_AUTOSTART_EVENT_NAME );
|
||
|
if( hEventHandle != NULL ) {
|
||
|
|
||
|
SetupDebugPrint1(L"SETUP: Waiting on event %ls \n", SC_AUTOSTART_EVENT_NAME );
|
||
|
WaitStatus = WaitForSingleObject( hEventHandle, INFINITE );
|
||
|
if( WaitStatus != WAIT_FAILED ) {
|
||
|
if( WaitStatus == WAIT_OBJECT_0 ) {
|
||
|
SetupDebugPrint1(L"SETUP: Wait on event %ls completed successfully \n", SC_AUTOSTART_EVENT_NAME );
|
||
|
} else {
|
||
|
SetupDebugPrint2(L"SETUP: Wait on event %ls failed. WaitStatus = %d \n", SC_AUTOSTART_EVENT_NAME, WaitStatus );
|
||
|
}
|
||
|
} else {
|
||
|
DWORD Error;
|
||
|
|
||
|
Error = GetLastError();
|
||
|
SetupDebugPrint2(L"SETUP: Wait on event %ls failed. Error = %d \n", SC_AUTOSTART_EVENT_NAME, Error );
|
||
|
}
|
||
|
CloseHandle( hEventHandle );
|
||
|
}
|
||
|
else {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return (WAIT_OBJECT_0 == WaitStatus);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
MyCreateService(
|
||
|
IN PCWSTR ServiceName,
|
||
|
IN PCWSTR DisplayName, OPTIONAL
|
||
|
IN DWORD ServiceType,
|
||
|
IN DWORD StartType,
|
||
|
IN DWORD ErrorControl,
|
||
|
IN PCWSTR BinaryPathName,
|
||
|
IN PCWSTR LoadOrderGroup, OPTIONAL
|
||
|
IN PWCHAR DependencyList,
|
||
|
IN PCWSTR ServiceStartName, OPTIONAL
|
||
|
IN PCWSTR Password OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Stub for calling CreateService. If CreateService fails with
|
||
|
the error code indicating that the service already exists, this routine
|
||
|
calls the routine for ChangeServiceConfig to ensure that the
|
||
|
parameters passed in are reflected in the services database.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ServiceName - Name of service
|
||
|
|
||
|
DisplayName - Localizable name of Service or ""
|
||
|
|
||
|
ServiceType - Service type, e.g. SERVICE_KERNEL_DRIVER
|
||
|
|
||
|
StartType - Service Start value, e.g. SERVICE_BOOT_START
|
||
|
|
||
|
ErrorControl - Error control value, e.g. SERVICE_ERROR_NORMAL
|
||
|
|
||
|
BinaryPathName - Full Path of the binary image containing service
|
||
|
|
||
|
LoadOrderGroup - Group name for load ordering or ""
|
||
|
|
||
|
Dependencies - MultiSz list of dependencies for this service. Any dependency
|
||
|
component having + as the first character is a group dependency.
|
||
|
The others are service dependencies.
|
||
|
|
||
|
ServiceStartName - Service Start name (account name in which this service is run).
|
||
|
|
||
|
Password - Password used for starting the service.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Boolean value indicating outcome.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
SC_HANDLE hSC;
|
||
|
SC_HANDLE hSCService;
|
||
|
DWORD dwTag,dw;
|
||
|
BOOL b;
|
||
|
|
||
|
//
|
||
|
// Open a handle to the service controller manager
|
||
|
//
|
||
|
hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
||
|
if(hSC == NULL) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_CREATESVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szOpenSCManager,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Process the optional "" parameters passed in and make them NULL.
|
||
|
//
|
||
|
if(DisplayName && !DisplayName[0]) {
|
||
|
DisplayName = NULL;
|
||
|
}
|
||
|
if(LoadOrderGroup && !LoadOrderGroup[0]) {
|
||
|
LoadOrderGroup = NULL;
|
||
|
}
|
||
|
if(ServiceStartName && !ServiceStartName[0]) {
|
||
|
ServiceStartName = NULL;
|
||
|
}
|
||
|
if(Password && !Password[0]) {
|
||
|
Password = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create the service.
|
||
|
//
|
||
|
|
||
|
hSCService = CreateService(
|
||
|
hSC,
|
||
|
ServiceName,
|
||
|
DisplayName,
|
||
|
0,
|
||
|
ServiceType,
|
||
|
StartType,
|
||
|
ErrorControl,
|
||
|
BinaryPathName,
|
||
|
LoadOrderGroup,
|
||
|
LoadOrderGroup ? &dwTag : NULL,
|
||
|
DependencyList,
|
||
|
ServiceStartName,
|
||
|
Password
|
||
|
);
|
||
|
//
|
||
|
// If we were unable to create the service, check if the service already
|
||
|
// exists in which case all we need to do is change the configuration
|
||
|
// parameters in the service.
|
||
|
//
|
||
|
if(hSCService) {
|
||
|
//
|
||
|
// Note that we won't do anything with the tag.
|
||
|
//
|
||
|
CloseServiceHandle(hSCService);
|
||
|
b = TRUE;
|
||
|
} else {
|
||
|
if((dw = GetLastError()) == ERROR_SERVICE_EXISTS) {
|
||
|
|
||
|
b = MyChangeServiceConfig(
|
||
|
ServiceName,
|
||
|
ServiceType,
|
||
|
StartType,
|
||
|
ErrorControl,
|
||
|
BinaryPathName,
|
||
|
LoadOrderGroup,
|
||
|
DependencyList,
|
||
|
ServiceStartName,
|
||
|
Password,
|
||
|
DisplayName
|
||
|
);
|
||
|
} else {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_CREATESVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szCreateService,
|
||
|
dw,
|
||
|
NULL,NULL);
|
||
|
b = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CloseServiceHandle(hSC);
|
||
|
return(b);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MyChangeServiceConfig(
|
||
|
IN PCWSTR ServiceName,
|
||
|
IN DWORD ServiceType,
|
||
|
IN DWORD StartType,
|
||
|
IN DWORD ErrorControl,
|
||
|
IN PCWSTR BinaryPathName, OPTIONAL
|
||
|
IN PCWSTR LoadOrderGroup, OPTIONAL
|
||
|
IN PWCHAR DependencyList,
|
||
|
IN PCWSTR ServiceStartName, OPTIONAL
|
||
|
IN PCWSTR Password, OPTIONAL
|
||
|
IN PCWSTR DisplayName OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Wrapper for ChangeServiceConfig.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ServiceName - Name of service
|
||
|
|
||
|
ServiceType - Service type, e.g. SERVICE_KERNEL_DRIVER
|
||
|
|
||
|
StartType - Service Start value, e.g. SERVICE_BOOT_START
|
||
|
|
||
|
ErrorControl - Error control value, e.g. SERVICE_ERROR_NORMAL
|
||
|
|
||
|
BinaryPathName - Full Path of the binary image containing service
|
||
|
|
||
|
LoadOrderGroup - Group name for load ordering
|
||
|
|
||
|
DependencyList - Multisz string having dependencies. Any dependency
|
||
|
component having + as the first character is a
|
||
|
group dependency. The others are service dependencies.
|
||
|
|
||
|
ServiceStartName - Service Start name (account name in which this
|
||
|
service is run).
|
||
|
|
||
|
Password - Password used for starting the service.
|
||
|
|
||
|
DisplayName - Localizable name of Service.
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Boolean value indicating outcome.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
SC_LOCK sclLock;
|
||
|
SC_HANDLE hSC;
|
||
|
SC_HANDLE hSCService;
|
||
|
DWORD dw;
|
||
|
BOOL b;
|
||
|
|
||
|
//
|
||
|
// Open a handle to the service controller manager
|
||
|
//
|
||
|
hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
||
|
if(hSC == NULL) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_CHANGESVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szOpenSCManager,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Try to lock the database, if possible. If we are not able to lock
|
||
|
// the database we will still modify the services entry. This is because
|
||
|
// we are just modifying a single service and chances are very low that
|
||
|
// anybody else is manipulating the same entry at the same time.
|
||
|
//
|
||
|
SetupDebugPrint1(L"MyChangeServiceConfig: LockingServiceDatabase for service %s", ServiceName);
|
||
|
sclLock = LockServiceDatabase(hSC);
|
||
|
|
||
|
//
|
||
|
// Process optional parameters
|
||
|
//
|
||
|
if(BinaryPathName && !BinaryPathName[0]) {
|
||
|
BinaryPathName = NULL;
|
||
|
}
|
||
|
if(LoadOrderGroup && !LoadOrderGroup[0]) {
|
||
|
LoadOrderGroup = NULL;
|
||
|
}
|
||
|
if(ServiceStartName && !ServiceStartName[0]) {
|
||
|
ServiceStartName = NULL;
|
||
|
}
|
||
|
if(Password && !Password[0]) {
|
||
|
Password = NULL;
|
||
|
}
|
||
|
if(DisplayName && !DisplayName[0]) {
|
||
|
DisplayName = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Open the service with SERVICE_CHANGE_CONFIG access
|
||
|
//
|
||
|
if(hSCService = OpenService(hSC,ServiceName,SERVICE_CHANGE_CONFIG)) {
|
||
|
|
||
|
b = ChangeServiceConfig(
|
||
|
hSCService,
|
||
|
ServiceType,
|
||
|
StartType,
|
||
|
ErrorControl,
|
||
|
BinaryPathName,
|
||
|
LoadOrderGroup,
|
||
|
NULL,
|
||
|
DependencyList,
|
||
|
ServiceStartName,
|
||
|
Password,
|
||
|
DisplayName
|
||
|
);
|
||
|
|
||
|
if(!b) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_CHANGESVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szChangeServiceConfig,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
}
|
||
|
CloseServiceHandle(hSCService);
|
||
|
} else {
|
||
|
b = FALSE;
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_CHANGESVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szOpenService,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Unlock the database if locked and then close the service controller
|
||
|
// handle
|
||
|
//
|
||
|
if(sclLock) {
|
||
|
UnlockServiceDatabase(sclLock);
|
||
|
SetupDebugPrint1(L"MyChangeServiceConfig: Unlocked ServiceDatabase for service %s", ServiceName);
|
||
|
}
|
||
|
|
||
|
CloseServiceHandle(hSC);
|
||
|
return(b);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
MyChangeServiceStart(
|
||
|
IN PCWSTR ServiceName,
|
||
|
IN DWORD StartType
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Routine to change the start value of a service. This turns
|
||
|
around and calls the stub to ChangeServiceConfig.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ServiceName - Name of service
|
||
|
|
||
|
StartType - Service Start value, e.g. SERVICE_BOOT_START
|
||
|
|
||
|
Return value:
|
||
|
|
||
|
Boolean value indicating outcome.
|
||
|
|
||
|
--*/
|
||
|
{
|
||
|
BOOL b;
|
||
|
|
||
|
b = MyChangeServiceConfig(
|
||
|
ServiceName,
|
||
|
SERVICE_NO_CHANGE,
|
||
|
StartType,
|
||
|
SERVICE_NO_CHANGE,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
return(b);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
SetupStartService(
|
||
|
IN PCWSTR ServiceName,
|
||
|
IN BOOLEAN Wait // if TRUE, try to wait until it is started.
|
||
|
)
|
||
|
{
|
||
|
SC_HANDLE hSC,hSCService;
|
||
|
BOOL b;
|
||
|
DWORD d;
|
||
|
DWORD dwDesiredAccess;
|
||
|
|
||
|
b = FALSE;
|
||
|
//
|
||
|
// Open a handle to the service controller manager
|
||
|
//
|
||
|
hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
||
|
if(hSC == NULL) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_STARTSVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szOpenSCManager,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
if (Wait) {
|
||
|
dwDesiredAccess = SERVICE_START | SERVICE_QUERY_STATUS;
|
||
|
} else {
|
||
|
dwDesiredAccess = SERVICE_START;
|
||
|
}
|
||
|
if(hSCService = OpenService(hSC,ServiceName,dwDesiredAccess)) {
|
||
|
SetupDebugPrint1(L"SetupStartService: Sending StartService to <%ws>\n", ServiceName);
|
||
|
b = StartService(hSCService,0,NULL);
|
||
|
SetupDebugPrint1(L"SetupStartService: Sent StartService to <%ws>\n", ServiceName);
|
||
|
if(!b && ((d = GetLastError()) == ERROR_SERVICE_ALREADY_RUNNING)) {
|
||
|
//
|
||
|
// Service is already running.
|
||
|
//
|
||
|
b = TRUE;
|
||
|
}
|
||
|
if(!b) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_STARTSVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szStartService,
|
||
|
d,
|
||
|
ServiceName,
|
||
|
NULL,NULL);
|
||
|
}
|
||
|
if (b && Wait) {
|
||
|
#define SLEEP_TIME 4000
|
||
|
#define LOOP_COUNT 30
|
||
|
SERVICE_STATUS ssStatus;
|
||
|
DWORD loopCount = 0;
|
||
|
//SetupDebugPrint(L" )) Looping waiting for start\n");
|
||
|
do {
|
||
|
b = QueryServiceStatus( hSCService, &ssStatus);
|
||
|
if ( !b ) {
|
||
|
//SetupDebugPrint(L"FAILED %d\n", GetLastError());
|
||
|
break;
|
||
|
}
|
||
|
if (ssStatus.dwCurrentState == SERVICE_START_PENDING) {
|
||
|
//SetupDebugPrint(L"PENDING\n");
|
||
|
if ( loopCount++ == LOOP_COUNT ) {
|
||
|
//SetupDebugPrint2(L"SYSSETUP: STILL PENDING after %d times: <%ws> service\n", loopCount, ServiceName);
|
||
|
break;
|
||
|
}
|
||
|
Sleep( SLEEP_TIME );
|
||
|
} else {
|
||
|
//SetupDebugPrint3(L"SYSSETUP: WAITED %d times: <%ws> service, status %d\n", loopCount, ServiceName, ssStatus.dwCurrentState);
|
||
|
break;
|
||
|
}
|
||
|
} while ( TRUE );
|
||
|
}
|
||
|
CloseServiceHandle(hSCService);
|
||
|
} else {
|
||
|
b = FALSE;
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_STARTSVC_FAIL,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szOpenService,
|
||
|
GetLastError(),
|
||
|
ServiceName,
|
||
|
NULL,NULL);
|
||
|
}
|
||
|
|
||
|
CloseServiceHandle(hSC);
|
||
|
|
||
|
return(b);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
FixServiceDependency(
|
||
|
IN PCWSTR ServiceName,
|
||
|
IN PCWSTR OldDependencyName,
|
||
|
IN PCWSTR NewDependencyName
|
||
|
)
|
||
|
{
|
||
|
ULONG Error;
|
||
|
HKEY hKey;
|
||
|
WCHAR ServicePath[ MAX_PATH + 1 ];
|
||
|
PBYTE OldValueData;
|
||
|
PBYTE NewValueData;
|
||
|
ULONG OldValueSize;
|
||
|
ULONG NewValueSize;
|
||
|
DWORD Type;
|
||
|
PBYTE p,q;
|
||
|
BOOL ChangeDependencyList;
|
||
|
|
||
|
//
|
||
|
// Open the key that describes the service
|
||
|
//
|
||
|
|
||
|
lstrcpy( ServicePath, szServicesKeyPath );
|
||
|
pSetupConcatenatePaths(ServicePath,ServiceName,sizeof( ServicePath )/sizeof( WCHAR ),NULL);
|
||
|
|
||
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
ServicePath,
|
||
|
0,
|
||
|
KEY_READ | KEY_WRITE,
|
||
|
&hKey );
|
||
|
|
||
|
if( Error != ERROR_SUCCESS ) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_FIX_SERVICE_FAILED,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szRegOpenKeyEx,
|
||
|
Error,
|
||
|
ServicePath,
|
||
|
NULL,NULL);
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer for the old value data
|
||
|
//
|
||
|
|
||
|
OldValueSize = 0;
|
||
|
Error = RegQueryValueEx(hKey,
|
||
|
szDependOnService,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
NULL,
|
||
|
&OldValueSize);
|
||
|
if( ( Error != ERROR_SUCCESS ) && ( Error != ERROR_MORE_DATA ) ) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_FIX_SERVICE_FAILED,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szRegQueryValueEx,
|
||
|
Error,
|
||
|
szDependOnService,
|
||
|
NULL,NULL);
|
||
|
RegCloseKey( hKey );
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
OldValueData = MyMalloc( OldValueSize );
|
||
|
if( OldValueData == NULL ) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_FIX_SERVICE_FAILED,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_OUTOFMEMORY,
|
||
|
NULL,NULL);
|
||
|
RegCloseKey( hKey );
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Read the value entry that lists the dependencies
|
||
|
//
|
||
|
|
||
|
Error = RegQueryValueEx(hKey,
|
||
|
szDependOnService,
|
||
|
NULL,
|
||
|
&Type,
|
||
|
OldValueData,
|
||
|
&OldValueSize);
|
||
|
if( Error != ERROR_SUCCESS ) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_FIX_SERVICE_FAILED,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szRegQueryValueEx,
|
||
|
Error,
|
||
|
szDependOnService,
|
||
|
NULL,NULL);
|
||
|
MyFree( OldValueData );
|
||
|
RegCloseKey( hKey );
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Find out if the OldValueData, explicitly list OldDependencyName.
|
||
|
// If not, then the service depends on another service that depends
|
||
|
// on OlDependencyName, and in this case there is no need to change
|
||
|
// the dependency list.
|
||
|
//
|
||
|
p = OldValueData;
|
||
|
ChangeDependencyList = FALSE;
|
||
|
while( (ULONG)(p - OldValueData) < OldValueSize ) {
|
||
|
if( ( lstrcmpi( (PWSTR)p, OldDependencyName ) == 0 ) ) {
|
||
|
ChangeDependencyList = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
p += (lstrlen( (PWSTR)p ) + 1)*sizeof(WCHAR);
|
||
|
}
|
||
|
if( !ChangeDependencyList ) {
|
||
|
MyFree( OldValueData );
|
||
|
RegCloseKey( hKey );
|
||
|
//
|
||
|
// Let the caller think that the dependency list was fixed
|
||
|
//
|
||
|
return( TRUE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate a buffer for the new value data
|
||
|
//
|
||
|
NewValueSize = OldValueSize -
|
||
|
( lstrlen( OldDependencyName ) - lstrlen( NewDependencyName ) )*sizeof(WCHAR);
|
||
|
|
||
|
NewValueData = MyMalloc( NewValueSize );
|
||
|
if( NewValueData == NULL ) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_FIX_SERVICE_FAILED,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_OUTOFMEMORY,
|
||
|
NULL,NULL);
|
||
|
MyFree( OldValueData );
|
||
|
RegCloseKey( hKey );
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Replace the old dependency name with the new one
|
||
|
//
|
||
|
p = OldValueData;
|
||
|
q = NewValueData;
|
||
|
|
||
|
lstrcpy( (PWSTR)q, NewDependencyName );
|
||
|
q += (lstrlen( (PWSTR)q ) + 1)*sizeof(WCHAR);
|
||
|
while( (ULONG)(p - OldValueData) < OldValueSize ) {
|
||
|
if( ( lstrcmpi( (PWSTR)p, OldDependencyName ) != 0 ) &&
|
||
|
( lstrcmpi( (PWSTR)p, NewDependencyName ) != 0 )
|
||
|
) {
|
||
|
lstrcpy( (PWSTR)q, (PWSTR)p );
|
||
|
q += (lstrlen( (PWSTR)q ) + 1)*sizeof(WCHAR);
|
||
|
}
|
||
|
p += (lstrlen( (PWSTR)p ) + 1)*sizeof(WCHAR);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Save the value entry with the new dependency name
|
||
|
//
|
||
|
Error = RegSetValueEx( hKey,
|
||
|
szDependOnService,
|
||
|
0,
|
||
|
REG_MULTI_SZ,
|
||
|
NewValueData,
|
||
|
(DWORD)(q-NewValueData) // NewValueSize
|
||
|
);
|
||
|
|
||
|
if( Error != ERROR_SUCCESS ) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_FIX_SERVICE_FAILED,
|
||
|
ServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szRegSetValueEx,
|
||
|
Error,
|
||
|
szDependOnService,
|
||
|
NULL,NULL);
|
||
|
MyFree( OldValueData );
|
||
|
MyFree( NewValueData );
|
||
|
RegCloseKey( hKey );
|
||
|
return( FALSE );
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Free the allocated buffers
|
||
|
//
|
||
|
|
||
|
MyFree( OldValueData );
|
||
|
MyFree( NewValueData );
|
||
|
|
||
|
//
|
||
|
// Close the key
|
||
|
//
|
||
|
RegCloseKey( hKey );
|
||
|
return( TRUE );
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
UpdateServicesDependencies(
|
||
|
IN HINF InfHandle
|
||
|
)
|
||
|
{
|
||
|
INFCONTEXT InfContext;
|
||
|
PCWSTR OldServiceName,NewServiceName;
|
||
|
BOOL b;
|
||
|
SC_HANDLE hSC, hSCService;
|
||
|
LPENUM_SERVICE_STATUS DependentsList;
|
||
|
DWORD BytesNeeded;
|
||
|
DWORD ServicesReturned;
|
||
|
HKEY hKey;
|
||
|
ULONG Error;
|
||
|
ULONG i;
|
||
|
|
||
|
//
|
||
|
// Iterate the [ServicesToRename] section in the inf.
|
||
|
// Each line is the name of a dependecy service that needs to be renamed.
|
||
|
//
|
||
|
if(SetupFindFirstLine(InfHandle,szServicesToRename,NULL,&InfContext)) {
|
||
|
b = TRUE;
|
||
|
} else {
|
||
|
SetuplogError( LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_NO_SECTION,
|
||
|
szServicesToRename,NULL,NULL);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Open a handle to the service controller manager
|
||
|
//
|
||
|
hSC = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
|
||
|
if(hSC == NULL) {
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szOpenSCManager,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
do {
|
||
|
//
|
||
|
// Fetch the name of a service that got renamed
|
||
|
//
|
||
|
if((OldServiceName = pSetupGetField(&InfContext,0))
|
||
|
&& (NewServiceName = pSetupGetField(&InfContext,1))) {
|
||
|
|
||
|
//
|
||
|
// Create a dummy service that has the same name as the old service
|
||
|
// This is necessarey so that we can get a handle to this service,
|
||
|
// and pass it to EnumDependentServices to find out the services that
|
||
|
// depend on this one.
|
||
|
//
|
||
|
|
||
|
if( !MyCreateService( OldServiceName,
|
||
|
NULL,
|
||
|
SERVICE_WIN32_OWN_PROCESS,
|
||
|
SERVICE_DISABLED,
|
||
|
SERVICE_ERROR_NORMAL,
|
||
|
L"%SystemRoot%\\System32\\dummy.exe",
|
||
|
NULL,
|
||
|
L"",
|
||
|
NULL,
|
||
|
NULL ) ) {
|
||
|
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_CANT_CREATE_DUMMY_SERVICE,
|
||
|
OldServiceName,
|
||
|
NULL,NULL);
|
||
|
|
||
|
b = FALSE;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Open the service that was just created
|
||
|
//
|
||
|
|
||
|
hSCService = OpenService(hSC,OldServiceName,SERVICE_ENUMERATE_DEPENDENTS | DELETE);
|
||
|
if( hSCService == NULL) {
|
||
|
Error = GetLastError();
|
||
|
SetupDebugPrint2( L"SYSSETUP: Unable to open service = %ls. Error = %d \n", OldServiceName, Error );
|
||
|
SetuplogError( LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_PARAM_RETURNED_WINERR,
|
||
|
szOpenService,
|
||
|
Error,
|
||
|
OldServiceName,
|
||
|
NULL,NULL);
|
||
|
//
|
||
|
// Force deletion of the service cretated
|
||
|
//
|
||
|
b = FALSE;
|
||
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
szServicesKeyPath,
|
||
|
0,
|
||
|
MAXIMUM_ALLOWED,
|
||
|
&hKey );
|
||
|
if( Error == ERROR_SUCCESS ) {
|
||
|
pSetupRegistryDelnode( hKey, OldServiceName );
|
||
|
RegCloseKey( hKey );
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Determine all services that depend on the service that was renamed
|
||
|
//
|
||
|
|
||
|
BytesNeeded = 0;
|
||
|
ServicesReturned = 0;
|
||
|
DependentsList = NULL;
|
||
|
if( !EnumDependentServices( hSCService,
|
||
|
SERVICE_ACTIVE | SERVICE_INACTIVE,
|
||
|
DependentsList,
|
||
|
0,
|
||
|
&BytesNeeded,
|
||
|
&ServicesReturned ) &&
|
||
|
( Error = GetLastError()) != ERROR_MORE_DATA ) {
|
||
|
|
||
|
SetuplogError( LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_PARAM_FAILED,
|
||
|
OldServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szEnumDependentService,
|
||
|
Error,
|
||
|
NULL,NULL);
|
||
|
|
||
|
b = FALSE;
|
||
|
goto delete_dummy_service;
|
||
|
}
|
||
|
|
||
|
DependentsList = MyMalloc( BytesNeeded );
|
||
|
if( DependentsList == NULL ) {
|
||
|
|
||
|
SetuplogError(
|
||
|
LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_PARAM_FAILED,
|
||
|
OldServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_OUTOFMEMORY,
|
||
|
NULL,NULL);
|
||
|
|
||
|
b = FALSE;
|
||
|
goto delete_dummy_service;
|
||
|
}
|
||
|
|
||
|
if( !EnumDependentServices( hSCService,
|
||
|
SERVICE_ACTIVE | SERVICE_INACTIVE,
|
||
|
DependentsList,
|
||
|
BytesNeeded,
|
||
|
&BytesNeeded,
|
||
|
&ServicesReturned ) ) {
|
||
|
|
||
|
SetuplogError( LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_PARAM_FAILED,
|
||
|
OldServiceName, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_X_RETURNED_WINERR,
|
||
|
szEnumDependentService,
|
||
|
GetLastError(),
|
||
|
NULL,NULL);
|
||
|
|
||
|
MyFree( DependentsList );
|
||
|
b = FALSE;
|
||
|
goto delete_dummy_service;
|
||
|
}
|
||
|
|
||
|
for( i = 0; i < ServicesReturned; i++ ) {
|
||
|
//
|
||
|
// Fix the dependency for this service
|
||
|
//
|
||
|
b = b && FixServiceDependency( DependentsList[i].lpServiceName,
|
||
|
OldServiceName,
|
||
|
NewServiceName );
|
||
|
}
|
||
|
MyFree( DependentsList );
|
||
|
|
||
|
delete_dummy_service:
|
||
|
|
||
|
if( !DeleteService(hSCService) &&
|
||
|
((Error = GetLastError()) != ERROR_SERVICE_MARKED_FOR_DELETE)
|
||
|
) {
|
||
|
SetupDebugPrint2( L"SYSSETUP: Unable to delete service %ls. Error = %d \n", OldServiceName, Error );
|
||
|
#if 0
|
||
|
//
|
||
|
// Force deletion of the dummy service
|
||
|
//
|
||
|
Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
|
||
|
szServicesKeyPath,
|
||
|
0,
|
||
|
MAXIMUM_ALLOWED,
|
||
|
&hKey );
|
||
|
if( Error == ERROR_SUCCESS ) {
|
||
|
pSetupRegistryDelnode( hKey, OldServiceName );
|
||
|
RegCloseKey( hKey );
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
CloseServiceHandle(hSCService);
|
||
|
|
||
|
|
||
|
} else {
|
||
|
SetuplogError( LogSevWarning,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_UPDATE_SERVICES_FAILED, NULL,
|
||
|
SETUPLOG_USE_MESSAGEID,
|
||
|
MSG_LOG_NO_SECTION,
|
||
|
szServicesToRename,NULL,NULL);
|
||
|
}
|
||
|
|
||
|
} while(SetupFindNextLine(&InfContext,&InfContext));
|
||
|
|
||
|
CloseServiceHandle(hSC);
|
||
|
return(b);
|
||
|
}
|