/*++

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);
}