ChangeServiceConfig2

Just starting out? Need help? Post your questions and find answers here.
TeddyLM
Enthusiast
Enthusiast
Posts: 133
Joined: Wed Apr 30, 2003 2:04 pm
Location: Germany (French expat)

ChangeServiceConfig2

Post by TeddyLM »

Hi there,

i try to use ChangeServiceConfig2 to change the settings of a service to restart on crash.
Although i run it with higher privilege (on Win7 64bit) and have the permission to change directly in the registry, the function keeps returning 'Access denied'.
Any idea what i'm doing wrong?
Thanks for the help.

Code: Select all

Enumeration     ;SC_ACTION_TYPE 
    #SC_ACTION_NONE         ;0 - no action.
    #SC_ACTION_RESTART      ;1 - restart the service.
    #SC_ACTION_REBOOT       ;2 - reboot the computer.
    #SC_ACTION_RUN_COMMAND  ;3 - run a command.
EndEnumeration

Enumeration 1    ;dwInfoLevel = Configuration information to be changed
    #SERVICE_CONFIG_DESCRIPTION                 ;1 - The lpInfo parameter is a pointer To a SERVICE_DESCRIPTION Structure.
    #SERVICE_CONFIG_FAILURE_ACTIONS             ;2 - The lpInfo parameter is a pointer To a SERVICE_FAILURE_ACTIONS Structure.
    #SERVICE_CONFIG_DELAYED_AUTO_START_INFO     ;3 - The lpInfo parameter is a pointer To a SERVICE_DELAYED_AUTO_START_INFO Structure. (XP not supported)
    #SERVICE_CONFIG_FAILURE_ACTIONS_FLAG        ;4 - The lpInfo parameter is a pointer To a SERVICE_FAILURE_ACTIONS_FLAG Structure. (XP not supported)
    #SERVICE_CONFIG_SERVICE_SID_INFO            ;5 - The lpInfo parameter is a pointer To a SERVICE_SID_INFO Structure.
    #SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO    ;6 - The lpInfo parameter is a pointer To a SERVICE_REQUIRED_PRIVILEGES_INFO Structure. (XP not supported)
    #SERVICE_CONFIG_PRESHUTDOWN_INFO            ;7 - The lpInfo parameter is a pointer To a SERVICE_PRESHUTDOWN_INFO Structure. (XP not supported)
    #SERVICE_CONFIG_TRIGGER_INFO                ;8 - The lpInfo parameter is a pointer To a SERVICE_TRIGGER_INFO Structure. (XP not supported) 
    #SERVICE_CONFIG_PREFERRED_NODE              ;9 - The lpInfo parameter is a pointer To a SERVICE_PREFERRED_NODE_INFO Structure. (XP not supported)
EndEnumeration

Structure SC_ACTION
    type.l                      ;SC_ACTION_TYPE
    delay.l                     ;(in milliseconds)
EndStructure

Structure SERVICE_FAILURE_ACTIONS
    dwResetPeriod.l             ;The time after which to reset the failure count to zero if there are no failures, in seconds. Specify INFINITE to indicate that this value should never be reset.
    lpRebootMsg.l               ;The message to be broadcast before rebooting in response to the SC_ACTION_REBOOT service controller action (#NULL = message is unchanged, "" = no message is broadcast)
    lpCommand.l                 ;The command line of the process for the CreateProcess function to execute in response to the SC_ACTION_RUN_COMMAND service controller action
    cActions.l                  ;Number of elements in the lpsaActions array
    *lpsaActions                ;Pointer to an array of SC_ACTION structures
EndStructure

Prototype.l ProtoChange(hService.l, dwInfoLevel.l, sfa.l)

;===================================
Procedure.s GetLastError() 
    Msg$ = ""
    error.l = GetLastError_() 
    If error        
        *Buffer = AllocateMemory(255)
        If *Buffer
            FormatMessage_ (#FORMAT_MESSAGE_FROM_SYSTEM, #Null, error, 0, *Buffer, 255, #Null) 
            Msg$ = PeekS(*Buffer) 
            FreeMemory(*Buffer) 
        EndIf
    EndIf    
    ProcedureReturn Msg$
EndProcedure
;===================================
Computername$ = ""
Servicename$ = "MozillaMaintenance"                     ;<-- enter an existing service here
LibNr.i = OpenLibrary(#PB_Any,"advapi32.dll")
If LibNr
    CompilerIf #PB_Compiler_Unicode 
        ChangeServiceConfig2.ProtoChange = GetFunction(LibNr, "ChangeServiceConfig2W")
    CompilerElse
        ChangeServiceConfig2.ProtoChange = GetFunction(LibNr, "ChangeServiceConfig2A")
    CompilerEndIf
    ;
    hSCObject.i = OpenSCManager_(Computername$, 0, #SC_MANAGER_ALL_ACCESS)
    If hSCObject
        hService.i = OpenService_(hSCObject, Servicename$, #SERVICE_ALL_ACCESS)    
        If hService
            ;
            Dim sca.SC_ACTION(3)
            sca(0)\type = #SC_ACTION_RESTART
            sca(0)\delay = 2000
            sca(1)\type = #SC_ACTION_NONE
            sca(1)\delay = 0
            sca(2)\type = #SC_ACTION_NONE
            sca(2)\delay = 0
            ;
            sfa.SERVICE_FAILURE_ACTIONS
            sfa\dwResetPeriod = #INFINITE
            sfa\lpRebootMsg = #Null
            sfa\lpCommand = 0
            sfa\cActions = 3
            sfa\lpsaActions = sca()
            ;
            If ChangeServiceConfig2(hService, #SERVICE_CONFIG_FAILURE_ACTIONS, sfa)
                Debug "OK"
            Else
                Debug "Unable to change the configuration (" + GetLastError() + ")"
            EndIf    
            ;
            CloseServiceHandle_(hService)
        Else
            Debug "Unable to open the service (" + GetLastError() + ")"
        EndIf    
        CloseServiceHandle_(hSCObject)
    Else
        Debug "Unable to call the service manager (" + GetLastError() + ")"
    EndIf
    CloseLibrary(LibNr) 
EndIf
Last edited by TeddyLM on Thu Jun 06, 2013 9:24 am, edited 2 times in total.
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: ChangeServiceConfig2

Post by luis »

MSDN wrote: If the service controller handles the SC_ACTION_RESTART action, hService must have the SERVICE_START access right.
Try

Code: Select all

hService.l = OpenService_(hSCObject, Servicename$, #SERVICE_CHANGE_CONFIG | #SERVICE_START)
"Have you tried turning it off and on again ?"
TeddyLM
Enthusiast
Enthusiast
Posts: 133
Joined: Wed Apr 30, 2003 2:04 pm
Location: Germany (French expat)

Re: ChangeServiceConfig2

Post by TeddyLM »

Hi luis
shame on me.
I realised that i called OpenService with an Access right for the Service Control Manager (#SC_MANAGER_ALL_ACCESS = $F003F) and not for the Service (#SERVICE_ALL_ACCESS = $F01FF).
The answer was in front of me all the time ! :oops:

Thanks for the suggestion.
TeddyLM
Enthusiast
Enthusiast
Posts: 133
Joined: Wed Apr 30, 2003 2:04 pm
Location: Germany (French expat)

Re: ChangeServiceConfig2

Post by TeddyLM »

I corrected the code.
It now works for me (tested on Win7 64 bit).
PureGuy
Enthusiast
Enthusiast
Posts: 102
Joined: Mon Aug 30, 2010 11:51 am

Re: ChangeServiceConfig2

Post by PureGuy »

TeddyLM you use long for handles: LibNr.l, hSCObject.l, hService.l
If you compile your code as native x64 you will get problems, better change them to .i.
TeddyLM
Enthusiast
Enthusiast
Posts: 133
Joined: Wed Apr 30, 2003 2:04 pm
Location: Germany (French expat)

Re: ChangeServiceConfig2

Post by TeddyLM »

You are right, it is better that way, although i'm not sure it would be problematic.

Microsoft writes:
...
• 64-bit versions of Windows use 32-bit handles for interoperability. When sharing a handle between 32-bit and 64-bit applications, only the lower 32 bits are significant, so it is safe to truncate the handle (when passing it from 64-bit to 32-bit) or sign-extend the handle (when passing it from 32-bit to 64-bit). Handles that can be shared include handles to user objects such as windows (HWND), handles to GDI objects such as pens and brushes (HBRUSH and HPEN), and handles to named objects such as mutexes, semaphores, and file handles.
...
User avatar
luis
Addict
Addict
Posts: 3895
Joined: Wed Aug 31, 2005 11:09 pm
Location: Italy

Re: ChangeServiceConfig2

Post by luis »

Often it's not a problem with handles but you never know when you'll meet the exception, so better drop the habit to use .l unless really needed (for example inside API structures).

Moreover I believe #PB_Any can return values larger than 32 bits on x64

IMHO .l should be banned and used only when needed, this way it will be kind of an implicit comment too: "see ? this is .l for a reason, it's not any integer ... it really needs to be this size !"
"Have you tried turning it off and on again ?"
Post Reply