Jump to content

_Service_UDF v4 : Build your own service with autoit code


arcker
 Share

Recommended Posts

5 hours ago, Skysnake said:

@Blois can you run the examples as is? If that works, is the problem in your own code? 

My service installation code:

include <Services_1.au3>

    If @OSArch = "X64" Then
        $path = "c:\Program Files (x86)\teste"
        DirCreate($path)
    Else
        $path = "c:\Program Files\teste"
        DirCreate($path)
    EndIf


Global $retorno = _Service_Create("Agente.Teste", _
        "Agente - Teste", _
        $SERVICE_WIN32_OWN_PROCESS, _
        $SERVICE_AUTO_START, _
        $SERVICE_ERROR_IGNORE, _
        $path & "\Agente.Teste.exe")
        
MsgBox(0, "$retorno",  $retorno)
MsgBox(0, "@error", @error)

My Code Agente.Teste.exe

#include <Misc.au3>

#NoTrayIcon
_Singleton("Agente.Teste.exe") ;Única instância na máquina

Global $path

If @OSArch = "X64" Then
    $path = "c:\Program Files (x86)\teste"
    DirCreate($path)
Else
    $path = "c:\Program Files\teste"
    DirCreate($path)
EndIf

While 1
    If Not ProcessExists("Teste.exe") Then
        Run($path & "\Teste.exe")
    EndIf
    Sleep(30000)
WEnd

It is?

Tks.

Blois

Edited by Blois
Link to comment
Share on other sites

  • 1 year later...

I get ton of errors when i try to create service with this:

#include "Services.au3"
$sServiceName = StringTrimRight (@ScriptName,4) ;returns filename only no extension
$sDisplayName= StringTrimRight (@ScriptName,4) ;returns filename only no extension
$iServiceType = $SERVICE_WIN32_OWN_PROCESS
$iStartType = $SERVICE_AUTO_START
$iErrorControl = $SERVICE_ERROR_IGNORE
$sBinaryPath = @ScriptFullPath
$sLoadOrderGroup = Default
$fTagId = Default
$vDependencies = Default
$sServiceUser = Default
$sPassword = Default
$sComputerName = ""
_Service_Create($sServiceName, $sDisplayName, $iServiceType, $iStartType, $iErrorControl, $sBinaryPath, $sLoadOrderGroup = Default, $fTagId = Default, $vDependencies = Default, $sServiceUser = Default, $sPassword = Default, $sComputerName = "")

error: logprint(): undefined function.
error: _Main(): undefined function.
$pArgs: possibly used before declaration.
And many man more.

What am i missing ?

 

Link to comment
Share on other sites

  • 3 years later...
Link to comment
Share on other sites

@arcker

HELP needed !

I am running your ServiceExample_v4.au3. But after 2 to 10 min the service stops, and I do not know why !

Here is your script a bit modified:

#NoTrayIcon
#RequireAdmin
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Run_After=copy "%out%" "\\myserver\c$\Batch\autoit"
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
Opt("mustdeclarevars", 1)
;~  https://www.autoitscript.com/forum/topic/80201-_service_udf-v4-build-your-own-service-with-autoit-code/
;~ #AutoIt3Wrapper_Version=beta
;~ Opt("MustDeclareVars", 1) ; just for self control  FPRIVATE "TYPE=PICT;ALT=smile.gif" dont to forget declare vars
Global $MainLog = @ScriptDir & "\test_service.log"
Global $sDescription = 'test'
Global Const $sServiceName = 'a_test'
;~ FileDelete($MainLog)
;~ If $bServiceRunning Then Exit
;~ logprint("program started" & $cmdlineraw)

#include <Winapi.au3> ;just For constants
#include "services.au3"
#include <File.au3>

;~ #include <Timers.au3> ; i used it for timers func
;~ If $bAU3ServiceDebug Then logprint("script started")
If $cmdline[0] > 0 Then
    Switch $cmdline[1]
        Case "install", "-i", "/i"
;~          msgbox(0,"","toto")
            InstallService()
        Case "remove", "-u", "/u", "uninstall"
            RemoveService()

        Case Else
            ConsoleWrite(" - - - Help - - - " & @CRLF)
            ConsoleWrite("params : " & @CRLF)
            ConsoleWrite(" -i : install service" & @CRLF)
            ConsoleWrite(" -u : remove service" & @CRLF)
            ConsoleWrite(" - - - - - - - - " & @CRLF)
            Exit
            ;start service.
    EndSwitch
Else
    _Service_init($sServiceName)
    Exit
EndIf

Func _main($iArg, $sArgs)
;~ Sleep(1000)
;~ $bMainStopped = False
    If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
;~  if $bAU3ServiceDebug then logprint("Erreur sending running status, exiting")
        _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0)
        Exit
    EndIf
    $bServiceRunning = True ; REQUIRED

    #cs
    Dim $tcpon = true
    If $tcpon Then
        TCPStartup()
        Dim $tcpConn = TCPConnect("127.0.0.1",3585)
        TCPSend($tcpConn,"Hello " & @AutoItPID)
    EndIf
    #ce
    While $bServiceRunning ; REQUIRED  ( dont change variable name ) ; there are several ways to find that service have to be stoped - $Running flag in loop is the first method
        #Region --> insert your running code here
;~ local $count = 0
;~  if $count < 5 then
;~  logprint("main count" & $count & @crlf)
;~  If $tcpon Then TCPSend($tcpConn, "main count" & $count & @crlf)
;~  if $count < 5 then logprint("main count" & $count & @crlf)

;~  $count += 1
        _Sleep(10000)
        _FileWriteLog(@ScriptDir & '\log.log', 'hello')
;~  if $count = 4 then
;~  while 1
;~      if not $bServiceRunning then
;~          logprint("stop loop 4")
;~          ExitLoop
;~      EndIf
;~  WEnd
;~  endif
        #EndRegion --> insert your running code here
    WEnd
    _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000)
;~ logprint("seems service stopping")

;~ Sleep(2000)
;~ $bMainStopped = True

;~ If $tcpon Then TCPCloseSocket($tcpConn)
;~ If $tcpon Then TCPShutdown()
    DllCallbackFree($tServiceMain)
    DllCallbackFree($tServiceCtrl)

    _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0)
    DllClose($hAdvapi32_DLL)
    DllClose($hKernel32_DLL)

;~ _service_cleanup()
;~ exit
;~ return
EndFunc   ;==>_main

;~ If $bDebug Then logprint("script started")
#cs
If $cmdline[0] > 0 Then
    Switch $cmdline[1]
        Case "install", "-i", "/i"
;~          msgbox(0,"","toto")
            InstallService()
        Case "remove", "-u", "/u", "uninstall"
            RemoveService()

        Case Else
            ConsoleWrite(" - - - Help - - - " & @CRLF)
            ConsoleWrite("params : " & @CRLF)
            ConsoleWrite(" -i : install service" & @CRLF)
            ConsoleWrite(" -u : remove service" & @CRLF)
            ConsoleWrite(" - - - - - - - - " & @CRLF)
            Exit
            ;start service.
    EndSwitch
Else
    _Service_init($sServiceName)
    Exit
EndIf
#ce
Func _Sleep($delay)

;~ logprint("Pause " & $delay / 1000 & " seconds...")

;~ Local $dll = DllOpen("kernel32.dll")
    Local $result = DllCall($hKernel32_DLL, "none", "Sleep", "dword", $delay)
;~ DllClose($dll)

EndFunc   ;==>_Sleep

; some loging func
;~ Func logprint($text, $nolog = 0)
;~  If $nolog Then
;~      MsgBox(0, "MyService", $text, 1)
;~  Else
;~      If Not FileExists($MainLog) Then FileWriteLine($MainLog, "Log created: " & @YEAR & "/" & @MON & "/" & @MDAY & " " & @HOUR & ":" & @MIN & ":" & @SEC)
;~      FileWriteLine($MainLog, @YEAR & @MON & @MDAY & " " & @HOUR & @MIN & @SEC & " [" & @AutoItPID & "] >> " & $text)
;~  EndIf
;~  Return 0
;~ ConsoleWrite($text & @CRLF)
;~ EndFunc   ;==>logprint

Func InstallService()
    _Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_START, $SERVICE_ERROR_NORMAL, '"' & @ScriptFullPath & '"')
    If @error Then
        ConsoleWrite('Problem installing service, Error number is ' & @error & @CRLF & ' message : ' & _WinAPI_GetLastErrorMessage())
    Else
        RunWait(@ComSpec & ' /c ' & 'sc description ' & $sServiceName & ' "' & $sDescription & '"')
        ConsoleWrite('Installation of service successful' & @CRLF & 'Program will exit')
    EndIf
    Exit
EndFunc   ;==>InstallService
Func RemoveService()
    _Service_Stop($sServiceName)
    _Service_Delete($sServiceName)
    If Not @error Then
        ConsoleWrite('Uninstallation of service successful' & @CRLF & 'Program will exit')
    EndIf
    Exit
EndFunc   ;==>RemoveService

Func _exit()
;~  if $bDebug  then logprint("Exiting")
    ; Clean opened dll
;~  DllClose($hKernel32_DLL)
;~  DllClose($hAdvapi32_DLL)
    _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0) ;
;~ _service_cleanup("END")

;~ _Service_Cleanup("END")
EndFunc   ;==>_exit
#cs
    ...from MSDN:
    The ServiceMain function should perform the following tasks:

    Initialize all global variables.
    Call the RegisterServiceCtrlHandler function immediately to register a Handler function to handle control requests for the service. The return value of RegisterServiceCtrlHandler is a service status handle that will be used in calls to notify the SCM of the service status.
    Perform initialization. If the execution time of the initialization code is expected to be very short (less than one second), initialization can be performed directly in ServiceMain.
    If the initialization time is expected to be longer than one second, call the SetServiceStatus function, specifying the SERVICE_START_PENDING service state and a wait hint in the SERVICE_STATUS structure.

    If your service's initialization code performs tasks that are expected to take longer than the initial wait hint value, your code must call the SetServiceStatus function periodically (possibly with a revised wait hint) to indicate that progress is being made. Be sure to call SetServiceStatus only if the initialization is making progress. Otherwise, the Service Control Manager can wait for your service to enter the SERVICE_RUNNING state assuming that your service is making progress and block other services from starting. Do not call SetServiceStatus from a separate thread unless you are sure the thread performing the initialization is truly making progress.

    When initialization is complete, call SetServiceStatus to set the service state to SERVICE_RUNNING.
    Perform the service tasks, or, if there are no pending tasks, return control to the caller. Any change in the service state warrants a call to SetServiceStatus to report new status information.
    If an error occurs while the service is initializing or running, the service should call SetServiceStatus to set the service state to SERVICE_STOP_PENDING if cleanup will be lengthy. After cleanup is complete, call SetServiceStatus to set the service state to SERVICE_STOPPED from the last thread to terminate. Be sure to set the dwServiceSpecificExitCode and dwWin32ExitCode members of the SERVICE_STATUS structure to identify the error.
#ce

; emulating your program init() function
;~ Func main_init()
;~  $hGUI = GUICreate("Timers Using CallBack Function(s)")
;~ GUISetState($hGUI,@SW_HIDE) ; unneeded - timers run exelent without guisetstate.
;~  $MainLog = @ScriptDir & "\test_service.log"
;~  $sServiceName = "Autoit_Service"
;~  $Running = 1
;~  if $bDebug  then logprint("main_init. Stop event=" & $service_stop_event)
;~ EndFunc   ;==>main_init
; stop timer function. its said SCM that service is in the process of $SERVICE_STOP_PENDING
;~ Func myStopTimer($hWnd, $Msg, $iIDTimer, $dwTime)
;~  if $bDebug  then logprint("timer = " & $counter)
;~  _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, $counter)
;~  $counter += -100
;~ EndFunc   ;==>myStopTimer

Func StopTimer()
;~  if $bDebug  then logprint("timer = " & $counter)
    _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, $iServiceCounter)
    $iServiceCounter += -100
EndFunc   ;==>StopTimer
; emulate your program main function with while loop (may be gui loop & so on)
Func _Stopping()
    _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 3000)
EndFunc   ;==>_Stopping

and Services.au3:

;created By arcker, for autoit community
#include-once
;#include "Log.au3"
#include "WinAPI.au3"
#include "ServicesConstants.au3"
;~ Dim $bMainStopped = False
;~ Dim $gServiceStateRunning = False
Dim $bAU3ServiceDebug = false
Dim $hAdvapi32_DLL = DllOpen("Advapi32.dll")
Dim $hKernel32_DLL = DllOpen("kernel32.dll")
;~ Dim $gdwCheckPoint = 1
;~ Dim $sServiceName = "Autoit_Service"
Dim  $bServiceRunning = False, $iServiceCounter = 1
; const

; Globals for Au3@service routines
Dim $tServiceName,$tServiceCtrl,$tServiceMain;,$service_debug_mode = False
Dim $tService_Status = DllStructCreate("dword dwServiceType;" & _
        "dword dwCurrentState;dword dwControlsAccepted;dword dwWin32ExitCode;" & _
        "dword dwServiceSpecificExitCode;dword dwCheckPoint;dword dwWaitHint")
Dim $hService_Status_handle
;~ Dim Const $NTSL_LOOP_WAIT = -1
;~ Dim $service_type
;~ Dim $service_stop_event
;~ Dim $NTSL_ERROR_SERVICE_STATUS = 2
;~ Dim Const $WAIT_OBJECT_0 = 0x0

; #INDEX# ==========================================================================================================================================================
; Title .........: Services
; AutoIt Version : 3.2.10++
; Language ......: English
; Description ...: Windows service management for AutoIt, with AutoIt-as-service functionality.
; Authors .......: Engine, Arcker
; ...............: Shminkyboy, udgeen
; ==================================================================================================================================================================



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_Create
; Description ...: Creates a service.
; Syntax.........: _Service_Create($sServiceName, $sDisplayName, $iServiceType, $iStartType, $iErrorControl, $sBinaryPath _
;                  [, $sLoadOrderGroup, $fTagId, $vDependencies, $sServiceUser, $sPassword, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sDisplayName - The display name to be used by user interface programs to identify the service. The maximum string length is 256 characters.
;                                  The service control manager database preserves the case of the characters,
;                                  but service name comparisons are always case insensitive.
;                                  Forward-slash (/) and back-slash (\) are invalid service name characters.
;                  $iServiceType - The type of service. Specify one of the following service types:
;                                  $SERVICE_KERNEL_DRIVER - Driver service.
;                                  $SERVICE_FILE_SYSTEM_DRIVER - File system driver service.
;                                  $SERVICE_WIN32_OWN_PROCESS - Service that runs in its own process.
;                                  $SERVICE_WIN32_SHARE_PROCESS - Service that shares a process with other services.
;                                  If you specify either $SERVICE_WIN32_OWN_PROCESS or $SERVICE_WIN32_SHARE_PROCESS,
;                                  and the service is running in the context of the LocalSystem account, you can also specify the following type:
;                                  $SERVICE_INTERACTIVE_PROCESS - The service can interact with the desktop.
;                  $iStartType - The service start options. Specify one of the following start types:
;                                $SERVICE_BOOT_START - A device driver started by the system loader. This value is valid only for driver services.
;                                $SERVICE_SYSTEM_START - A device driver started by the IoInitSystem function. This value is valid only for driver services.
;                                $SERVICE_AUTO_START - A service started automatically by the service control manager during system startup.
;                                $SERVICE_DEMAND_START - A service started by the service control manager when a process calls the StartService function.
;                                $SERVICE_DISABLED - A service that cannot be started.
;                  $iErrorControl - The severity of the error, and action taken, if this service fails to start. Specify one of the following values:
;                                   $SERVICE_ERROR_IGNORE - The startup program ignores the error and continues the startup operation.
;                                   $SERVICE_ERROR_NORMAL - The startup program logs the error in the event log but continues the startup operation.
;                                   $SERVICE_ERROR_SEVERE - The startup program logs the error in the event log.
;                                                           If the last-known-good configuration is being started, the startup operation continues.
;                                                           Otherwise, the system is restarted with the last-known-good configuration.
;                                   $SERVICE_ERROR_CRITICAL - The startup program logs the error in the event log, if possible.
;                                                             If the last-known-good configuration is being started, the startup operation fails.
;                                                             Otherwise, the system is restarted with the last-known good configuration.
;                  $sBinaryPath - The fully-qualified path to the service binary file. If the path contains a space,
;                                 it must be quoted so that it is correctly interpreted.
;                                 For example, "d:\\my share\\myservice.exe" should be specified as "\"d:\\my share\\myservice.exe\"".
;                                 The path can also include arguments for an auto-start service. For example, "d:\\myshare\\myservice.exe arg1 arg2".
;                                 These arguments are passed to the service entry point (typically the main function).
;                  $sLoadOrderGroup - [Optional] The name of the load ordering group of which this service is a member.
;                                     Specify "Default" or an empty string if the service does not belong to a group.
;                  $fTagId - [Optional] Specify "True" if you desire a tag value that is unique in the group specified in the $sLoadOrderGroup parameter.
;                            Specify "False" or "Default" if you do not desire a tag value.
;                            The tag value is stored in @extended macro.
;                            You can use a tag for ordering service startup within a load ordering group by specifying a tag order vector in the
;                            GroupOrderList value of the following registry key:
;                            HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control
;                            Tags are only evaluated for driver services that have $SERVICE_BOOT_START or $SERVICE_SYSTEM_START start types.
;                  $vDependencies - [Optional] An array of services or load ordering groups that the system must start before this service can be started.
;                                   (Dependency on a group means that this service can run if at least one member of the group is running after an attempt to
;                                   start all members of the group.) Specify "Default" or an empty string if the service has no dependencies.
;                                   You must prefix group names with a plus sign ("+") so that they can be distinguished from a service name,
;                                   because services and service groups share the same name space.
;                  $sServiceUser - [Optional] The name of the account under which the service should run.
;                                  If the service type is $SERVICE_WIN32_OWN_PROCESS, use an account name in the form DomainName\UserName.
;                                  The service process will be logged on as this user. If the account belongs to the built-in domain,
;                                  you can specify .\UserName . A shared process can run as any user.
;                                  If the service type is $SERVICE_KERNEL_DRIVER or $SERVICE_FILE_SYSTEM_DRIVER,
;                                  the name is the driver object name that the system uses to load the device driver.
;                                  Specify "Default" if the driver is to use a default object name created by the I/O system.
;                  $sPassword - [Optional] The password to the account name specified by the $sServiceUser parameter.
;                               Specify "Default" or an empty string if the account has no password or if the service runs in the LocalService, NetworkService,
;                               or LocalSystem account. Passwords are ignored for driver services.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: Administrative rights on the target computer.
; Return values .: Success - 1
;                  Failure - 0
;                            Sets @error
; Author ........: engine
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_Create($sServiceName, _
        $sDisplayName, _
        $iServiceType, _
        $iStartType, _
        $iErrorControl, _
        $sBinaryPath, _
        $sLoadOrderGroup = Default, _
        $fTagId = Default, _
        $vDependencies = Default, _
        $sServiceUser = Default, _
        $sPassword = Default, _
        $sComputerName = "")
    Local $tLoadOrderGroup, $tTagId, $tDepend, $tServiceUser, $tPassword, $hSC, $avSC, $iSC
    $tLoadOrderGroup = DllStructCreate("wchar[" & Number($sLoadOrderGroup <> Default) * (StringLen($sLoadOrderGroup) + 1) & "]")
    DllStructSetData($tLoadOrderGroup, 1, $sLoadOrderGroup)
    $tTagId = DllStructCreate("dword[" & Number($fTagId) & "]")
    If IsArray($vDependencies) Then
        Local $iDepend, $tagDepend
        $iDepend = UBound($vDependencies) - 1
        For $i = 0 To $iDepend
            $tagDepend &= "wchar[" & StringLen($vDependencies[$i]) + 1 & "];"
        Next
        $tDepend = DllStructCreate(StringTrimRight($tagDepend, 1))
        For $i = 0 To $iDepend
            DllStructSetData($tDepend, $i + 1, $vDependencies[$i])
        Next
    Else
        $tDepend = DllStructCreate("wchar[" & Number($vDependencies <> Default) * (StringLen($vDependencies) + 1) & "]")
        DllStructSetData($tDepend, 1, $vDependencies)
    EndIf
    $tServiceUser = DllStructCreate("wchar[" & Number($sServiceUser <> Default) * (StringLen($sServiceUser) + 1) & "]")
    DllStructSetData($tServiceUser, 1, $sServiceUser)
    $tPassword = DllStructCreate("wchar[" & Number($sPassword <> Default) * (StringLen($sPassword) + 1) & "]")
    DllStructSetData($tPassword, 1, $sPassword)
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CREATE_SERVICE)
    $avSC = DllCall($hAdvapi32_DLL, "ptr", "CreateServiceW", _
            "ptr", $hSC, _
            "wstr", $sServiceName, _
            "wstr", $sDisplayName, _
            "dword", $SERVICE_ALL_ACCESS, _
            "dword", $iServiceType, _
            "dword", $iStartType, _
            "dword", $iErrorControl, _
            "wstr", $sBinaryPath, _
            "ptr", DllStructGetPtr($tLoadOrderGroup), _
            "ptr", DllStructGetPtr($tTagId), _
            "ptr", DllStructGetPtr($tDepend), _
            "ptr", DllStructGetPtr($tServiceUser), _
            "ptr", DllStructGetPtr($tPassword))
    If $avSC[0] = 0 Then
        $iSC = _WinAPI_GetLastError()
    Else
        CloseServiceHandle($avSC[0])
    EndIf
    CloseServiceHandle($hSC)
    Return SetError($iSC, DllStructGetData($tTagId, 1), Number($avSC[0] <> 0))
EndFunc   ;==>_Service_Create



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_Delete
; Description ...: Deletes a service.
; Syntax.........: _Service_Delete($sServiceName [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: Administrative rights on the target computer.
; Return values .: Success - 1
;                  Failure - 0
;                            Sets @error
; Author ........: engine
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_Delete($sServiceName, $sComputerName = "")
    Local $hSC, $hService, $avDS, $iDS
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $DELETE)
    $avDS = DllCall($hAdvapi32_DLL, "int", "DeleteService", _
            "ptr", $hService)
    If $avDS[0] = 0 Then $iDS = _WinAPI_GetLastError()
    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)
    Return SetError($iDS, 0, $avDS[0])
EndFunc   ;==>_Service_Delete



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_Exists
; Description ...: Checks if a service exists.
; Syntax.........: _Service_Exists($sServiceName [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: None.
; Return values .: Success - 1
;                  Failure - 0
; Author ........: engine
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_Exists($sServiceName, $sComputerName = "")
    Local $hSC, $hService
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $SERVICE_INTERROGATE)
    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)
    Return Number($hService <> 0)
EndFunc   ;==>_Service_Exists



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_QueryType
; Description ...: Retrieves a service's type.
; Syntax.........: _Service_QueryType($sServiceName [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: None.
; Return values .: Success - Returns the type of service. Can be one of the following values:
;                            $SERVICE_KERNEL_DRIVER - The service is a device driver.
;                            $SERVICE_FILE_SYSTEM_DRIVER - The service is a file system driver.
;                            $SERVICE_WIN32_OWN_PROCESS - The service runs in its own process.
;                            $SERVICE_WIN32_SHARE_PROCESS - The service shares a process with other services.
;                            BitOR($SERVICE_WIN32_OWN_PROCESS, $SERVICE_INTERACTIVE_PROCESS) - The service runs in its own process
;                                                                                              and can interact with the desktop.
;                            BitOR($SERVICE_WIN32_SHARE_PROCESS, $SERVICE_INTERACTIVE_PROCESS) - The service shares a process with other services
;                                                                                                and can interact with the desktop.
;                  Failure - 0
;                            Sets @error
; Author ........: engine
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_QueryType($sServiceName, $sComputerName = "")
    Local $hSC, $hService, $avQA, $tQB, $avQB, $iQE, $tQC
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $SERVICE_QUERY_CONFIG)

    ; Determine needed size of the struct in bytes
    $avQA = QueryServiceConfig($hService, 0, 0)

    ; Get Service data
    $tQB = DllStructCreate("ubyte[" & $avQA[4] & "]")
    $avQB = QueryServiceConfig($hService, DllStructGetPtr($tQB), DllStructGetSize($tQB))

    ; Get last error and close service handle
    If $avQB[0] = 0 Then $iQE = _WinAPI_GetLastError()
    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)

    ; Decode the ubyte structure
    $tQC = DllStructCreate("dword[3];uint_ptr[2];dword;uint_ptr[3]", $avQB[2])

    Return SetError($iQE, 0, DllStructGetData($tQC, 1, 1))
EndFunc   ;==>_Service_QueryType



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_Start
; Description ...: Starts a service.
; Syntax.........: _Service_Start($sServiceName [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: Administrative rights on the target computer.
; Return values .: Success - 1
;                  Failure - 0
;                            Sets @error
; Author ........: engine
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_Start($sServiceName, $sComputerName = "")
    Local $hSC, $hService, $avSS, $iSS
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $SERVICE_START)
    $avSS = DllCall($hAdvapi32_DLL, "int", "StartServiceW", _
            "ptr", $hService, _
            "dword", 0, _
            "ptr", 0)
    If $avSS[0] = 0 Then $iSS = _WinAPI_GetLastError()
    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)
    Return SetError($iSS, 0, $avSS[0])
EndFunc   ;==>_Service_Start



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_Stop
; Description ...: Stops a service.
; Syntax.........: _Service_Stop($sServiceName [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: Administrative rights on the target computer.
; Return values .: Success - 1
;                  Failure - 0
;                            Sets @error
; Author ........: engine
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_Stop($sServiceName, $sComputerName = "")
    Local $hSC, $hService, $iCSS, $iCSSE
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $SERVICE_STOP)
    $iCSS = ControlService($hService, $SERVICE_CONTROL_STOP)
    If $iCSS = 0 Then $iCSSE = _WinAPI_GetLastError()
    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)
    Return SetError($iCSSE, 0, $iCSS)
EndFunc   ;==>_Service_Stop



Func CloseServiceHandle($hSCObject)
    Local $avCSH = DllCall($hAdvapi32_DLL, "int", "CloseServiceHandle", _
            "ptr", $hSCObject)
    If @error Then Return SetError(@error, 0, 0)
    Return $avCSH[0]
EndFunc   ;==>CloseServiceHandle



Func ControlService($hService, $iControl)
    Local $avCS = DllCall($hAdvapi32_DLL, "int", "ControlService", _
            "ptr", $hService, _
            "dword", $iControl, _
            "ptr*", 0)
    If @error Then Return SetError(@error, 0, 0)
    Return $avCS[0]
EndFunc   ;==>ControlService



Func OpenSCManager($sComputerName, $iAccess)
    Local $avOSCM = DllCall($hAdvapi32_DLL, "ptr", "OpenSCManagerW", _
            "wstr", $sComputerName, _
            "wstr", $SERVICES_ACTIVE_DATABASE, _
            "dword", $iAccess)
    If @error Then Return SetError(@error, 0, 0)
    Return $avOSCM[0]
EndFunc   ;==>OpenSCManager



Func OpenService($hSC, $sServiceName, $iAccess)
    Local $avOS = DllCall($hAdvapi32_DLL, "ptr", "OpenServiceW", _
            "ptr", $hSC, _
            "wstr", $sServiceName, _
            "dword", $iAccess)
    If @error Then Return SetError(@error, 0, 0)
    Return $avOS[0]
EndFunc   ;==>OpenService



Func QueryServiceConfig($hService, $pServiceConfig, $iBufSize)
    Local $avQSC = DllCall($hAdvapi32_DLL, "int", "QueryServiceConfigW", _
            "ptr", $hService, _
            "ptr", $pServiceConfig, _
            "dword", $iBufSize, _
            "dword*", 0)
    Return $avQSC
EndFunc   ;==>QueryServiceConfig



;~ Au3@Service routines by 'Arcker'. Modified by ShminkyBoy to include support for interactive services

Func _Service_Init($sServiceName)
;~  If $bAU3ServiceDebug Then logprint("_Service_Init(" & $sServiceName & ")")
;~  $service_type = _Service_QueryType($sServiceName)
    $tServiceCtrl = DllCallbackRegister("_Service_Ctrl", "dword", "dword;dword;ptr;ptr") ; handlerex function
;~  $tServiceCtrl = DllCallbackRegister("_Service_Ctrl", "none", "dword") ; handler ( simple )
    $tServiceMain = DllCallbackRegister("_Service_ServiceMain", "none", "dword;ptr")
;~  $tServiceMain = DllCallbackRegister("_Main", "none", "dword;ptr")
;~  Local $tdispatchTable = DllStructCreate("ptr[2];ptr[2]")
;~  $tServiceName = DllStructCreate("char["&StringLen($sServiceName)&"]")
;~  DllStructSetData($tServiceName, 1, $sServiceName)
;~  DllStructSetData($tdispatchTable, 1, DllStructGetPtr($tServiceName), 1)
;~  DllStructSetData($tdispatchTable, 1, DllCallbackGetPtr($tServiceMain), 2)



    ;v4 :
    Local $tagSERVICE_TABLE_ENTRY = "STRUCT;ptr lpServiceName;ptr lpServiceProc;ENDSTRUCT"
;~  logprint($tSERVICE_TABLE_ENTRY & ";" & $tSERVICE_TABLE_ENTRY)
    Local $tdispatchTable = DllStructCreate($tagSERVICE_TABLE_ENTRY & ";" & $tagSERVICE_TABLE_ENTRY)
;~  If @error Then
;~  logprint("erreur de structure " & @error & @crlf)
;~  Exit
;~  EndIf
    $tServiceName = DllStructCreate("char["&StringLen($sServiceName)&"]")
;~  DllStructSetData($tServiceName, 1, $sServiceName)
    DllStructSetData($tdispatchTable, 1, DllStructGetPtr($tServiceName))
    DllStructSetData($tdispatchTable, 2, DllCallbackGetPtr($tServiceMain))

    ;**********
;~  DllStructSetData($tdispatchTable, 2, 0, 1) ; v4 not needed since NULL
;~  DllStructSetData($tdispatchTable, 2, 0, 2) ; v4 not needed since NULL
    ; here when we call this, the _service_ctrl callback is reported to the SCM
    DllCall($hAdvapi32_DLL, "int", "StartServiceCtrlDispatcher", "ptr", DllStructGetPtr($tdispatchTable))
    ;cleanup a little
    $tServiceName =0
    $tdispatchTable = 0
    ; cleanup callback resources
;~  DllCallbackFree($tServiceMain)
;~  DllCallbackFree($tServiceCtrl)
EndFunc   ;==>_Service_init



Func _Service_ServiceMain($iArg, $pArgs)
;~  Local $ret = DllCall($hAdvapi32_DLL, "ptr", "RegisterServiceCtrlHandlerExW", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl), "ptr", 0) ;register service
;~  If @error Or ($ret[0] = 0) Then Exit
;~  $hService_Status_handle = $ret[0]
;~  If Not $hService_Status_handle Then
;~      _Service_Cleanup()
;~      Return
;~  EndIf

;~  DllStructSetData($tService_Status, "dwServiceType", $service_type)
;~  DllStructSetData($tService_Status, "dwServiceSpecificExitCode", 0)

    ; report the status to the service control manager.
;~  If Not (_Service_ReportStatus($SERVICE_START_PENDING, $NO_ERROR, 3000)) Then
;~      _Service_Cleanup()
;~      Return
;~  EndIf
;~  _Service_Startup($iArg, $pArgs)
;~  _Main()
;~  if $bAU3ServiceDebug then logprint("RegisterServiceCtrlHandlerEx")

    Local $ret = DllCall($hAdvapi32_DLL, "ptr", "RegisterServiceCtrlHandlerEx", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl),"ptr",0) ;register service
;~  Local $ret = DllCall($hAdvapi32_DLL, "handle", "RegisterServiceCtrlHandler", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl)) ;register service
    If $ret[0] = 0 Then
;~      if $bAU3ServiceDebug then logprint("Error in registering service" & _WinAPI_GetLastError())
        _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0)
;~      Return
        Exit
    EndIf
    $hService_Status_handle = $ret[0]
    If Not $hService_Status_handle Then
        _Service_Cleanup()
        Return
    EndIf

    ;goto cleanup;
    DllStructSetData($tService_Status, "dwServiceType", _Service_QueryType($sServiceName))
    DllStructSetData($tService_Status, "dwServiceSpecificExitCode", 0);

    ; report the status to the service control manager.
    If Not _Service_ReportStatus($SERVICE_START_PENDING, $NO_ERROR, 0) Then
        ;goto cleanup;
        _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0)
;~      if $bAU3ServiceDebug then logprint("***** & error reporting Service_ReportStatus *******" & @CRLF)
        _Service_Cleanup()
        Return
    EndIf
;~  $service_stop_event = _WinAPI_CreateEvent(0, True, False, "") <= wonder if necessary, disabled in V3
#cs
    If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
        if $bAU3ServiceDebug then logprint("Erreur sending running status, exiting")
        _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError(), 0)
        Return
    EndIf


#ce $bServiceRunning = True ; REQUIRED
;~  If $bAU3ServiceDebug Then logprint("main start")
    _Main($iArg, $pArgs)
    #region -- service stopping
    ;~  _service_cleanup()
;~  _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000);

;~  If $bAU3ServiceDebug Then logprint("main stopped. Cleanup.")
    #endregion -- service stopping
    #region - STOP STOP STOP Service Stopped, don't change it or you will have stoping status
;~  _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0) ; That all! Our AutoIt Service stops just there! 0 timeout meens "Now"
;~ Exit ;Bug here. In race conditions it's not executed.
;~  ProcessClose(@AutoItPID) <= disabled in V3, seems to works well.
;~  sleep(1000)
;~  Return
    #endregion - Service Stopped, don't change it or you will have stoping status
EndFunc   ;==>_Service_ServiceMain



Func _Service_Cleanup()
    If $hService_Status_handle Then _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0)
EndFunc   ;==>_Service_Cleanup



;/*------------------------------[ service_ctrl ]------------------------------
; *  Called by the SCM whenever ControlService() is called for this service
; *
; *  Parameters:
; *     ctrlCode - type of control requested
; *
; *  Return value:
; *     none
; *----------------------------------------------------------------------------*/
Func _Service_Ctrl($dwControl, $dwEventType, $lpEventData, $lpContext) ;handler ex
;~ Func _Service_Ctrl($dwControl)
    ;#forceref $dwEventType, $lpEventData, $lpContext
;~  Sleep(1000)
;~  Local $return = $NO_ERROR
;~  WriteLog("_Service_Ctrl entered")
;~  If $bAU3ServiceDebug Then logprint("** SCM command received => " & $dwControl)
    Switch $dwControl
        Case $SERVICE_CONTROL_STOP,$SERVICE_ACCEPT_SHUTDOWN ; new in v4, stop when system shutdown ( better mmm ? )
;~          If $bAU3ServiceDebug Then logprint("Received stop command for service")
            ;stop the service.
            ;
            ;SERVICE_STOP_PENDING should be reported before
            ;setting the Stop Event - hServerStopEvent - in
            ;service_stop().  This avoids a race condition
            ;which may result in a 1053 - The Service did not respond...
            ;error.
;~          DllStructSetData($tService_Status, "dwCurrentState", $SERVICE_STOP_PENDING)
;~          _Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 0)
            $bServiceRunning = False
;~          _Service_SetStopEvent()
;~          While $bMainStopped = False
;~              If $bAU3ServiceDebug Then logprint("Main is still active")
;~              Sleep(1000)
;~          WEnd
;~          If $bAU3ServiceDebug Then logprint("Main is still active")
;~          _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0)
;~          Exit
;~          _Service_ReportStatus(DllStructGetData($tService_Status,"dwCurrentState"), _WinAPI_GetLastError(), 0)
;~          _Service_SetStopEvent()
            ; call _Service_Cleanup() from _Svc_Main() immediately before exiting
            Return $NO_ERROR
        Case $SERVICE_CONTROL_PAUSE
            DllStructSetData($tService_Status, "dwCurrentState", $SERVICE_PAUSED)
        Case $SERVICE_CONTROL_CONTINUE
            DllStructSetData($tService_Status, "dwCurrentState", $SERVICE_RUNNING)
        Case $SERVICE_CONTROL_INTERROGATE
            Return $NO_ERROR
;~          _Service_ReportStatus(DllStructGetData($tService_Status, "dwCurrentState"), $NO_ERROR, 0)
            ; report the service status
        Case $SERVICE_CONTROL_SESSIONCHANGE
            ; Extracting SessionID & cbSize
;~          Local $WTSSESSION_NOTIFICATION  = DllStructCreate("dword cbsize; dword dwSessionId", $lpEventData)
;~          Local $cbSize = DllStructGetData($WTSSESSION_NOTIFICATION, "cbSize")
;~          Local $dwSessionId = DllStructGetData($WTSSESSION_NOTIFICATION, "dwSessionId")
;~          WriteLog("cbSize = " & $cbSize & " ,dwSessionId = " & $dwSessionId)

            ;Trapping events
;~          Switch $dwEventType
;~              Case $WTS_CONSOLE_CONNECT
;~                  WriteLog("Console session connected", 0, 2)
;~              Case $WTS_CONSOLE_DISCONNECT
;~                  WriteLog("Console session disconnected", 0, 2)
;~              Case $WTS_REMOTE_CONNECT
;~                  WriteLog("Remote session connected", 0, 2)
;~              Case $WTS_REMOTE_DISCONNECT
;~                  WriteLog("Remote session disconnected", 0, 2)
;~              Case $WTS_SESSION_LOGON
;~                  WriteLog("Session logged on", 0, 2)
;~              Case $WTS_SESSION_LOGOFF
;~                  WriteLog("Session logged off", 0, 2)
;~              Case $WTS_SESSION_LOCK
;~                  WriteLog("Session locked", 0, 2)
;~              Case $WTS_SESSION_UNLOCK
;~                  WriteLog("Session unlocked", 0, 2)
;~              Case $WTS_SESSION_REMOTE_CONTROL
;~                  WriteLog("Session remote control", 0, 2)
;~          EndSwitch
        Case 128 To 255 ; custom messages
            ; handle custom messages
        Case Else
            ; invalid or unhandled control code
;~          $return = $ERROR_CALL_NOT_IMPLEMENTED
    EndSwitch
;~  _Service_ReportStatus(DllStructGetData($tService_Status, "dwCurrentState"), $NO_ERROR, 0)
    Return $NO_ERROR
EndFunc   ;==>_Service_Ctrl



;/*--------------------------[ _Service_ReportStatus ]--------------------------
; *  Sets the current status and reports it to the Service Control Manager
; *
; *  Parameters:
; *     currentState    -  the state of the service
; *     exitCode        -  error code to report
; *     waitHint        -  worst case estimate to next checkpoint
; *
; *  Return value:
; *     true            -  success
; *     false           -  failure
; *----------------------------------------------------------------------------*/
Func _Service_ReportStatus($currentState, $exitCode, $waitHint)
    Static $gdwCheckPoint = 1
;~  If $bAU3ServiceDebug Then logprint("Report Status received with = " & $currentState )
;~  Local $rc = True
;~  If Not $service_debug_mode Then ;when debugging we don't report to the SCM
        If ($currentState = $SERVICE_START_PENDING) Then
            DllStructSetData($tService_Status, "dwControlsAccepted", 0)
        Else
;~          WriteLog("_Service_ReportStatus entered")
;~          DllStructSetData($tService_Status, "dwControlsAccepted", BitOR($SERVICE_ACCEPT_STOP, $SERVICE_ACCEPT_SESSIONCHANGE))
            DllStructSetData($tService_Status, "dwControlsAccepted", BitOR($SERVICE_ACCEPT_STOP, $SERVICE_ACCEPT_SHUTDOWN))
        EndIf

        DllStructSetData($tService_Status, "dwCurrentState", $currentState)
        DllStructSetData($tService_Status, "dwWin32ExitCode", $exitCode)
        DllStructSetData($tService_Status, "dwWaitHint", $waitHint)
        If ($currentState = $SERVICE_RUNNING) Or ($currentState = $SERVICE_STOPPED) Then
            DllStructSetData($tService_Status, "dwCheckPoint", 0)
        Else
            $gdwCheckPoint += 1
;~          If $bAU3ServiceDebug Then logprint("dwCheckPoint => " & $gdwCheckPoint & @crlf)
            DllStructSetData($tService_Status, "dwCheckPoint", $gdwCheckPoint)
        EndIf
        ; report the status of the service to the service control manager.
;~      $rc =
;~  EndIf
    Return _Service_SetServiceStatus($hService_Status_handle, DllStructGetPtr($tService_Status))
EndFunc   ;==>_Service_ReportStatus



Func _Service_SetServiceStatus($hServiceStatus, $lpServiceStatus)
    Local $ret = DllCall($hAdvapi32_DLL, "int", "SetServiceStatus", "handle", $hServiceStatus, "ptr", $lpServiceStatus)
    If $ret[0] = 0 Then
        If $bAU3ServiceDebug Then
;~          logprint("SetServiceStatus Error" & _WinAPI_GetLastError())
        EndIf
    EndIf

    If @error Or Not $ret[0] Then Return 0
    Return $ret[0]
EndFunc   ;==>_Service_SetServiceStatus



;/*------------------------------[ service_start ]------------------------------
; * Starts and runs the service
; *----------------------------------------------------------------------------*/

Func _Service_Startup($argc, $argv)
    ; report the status to the service control manager.
    If Not _Service_ReportStatus($SERVICE_START_PENDING, $NO_ERROR, 3000) Then Return
    ; create the event object. The control handler function signals
    ; this event when it receives the "stop" control code.
;~  $gServiceStateRunning = True
;~  $service_stop_event = _WinAPI_CreateEvent(0, True, False, "")
    ; report the status to the service control manager.
    Return _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0)
EndFunc   ;==>_Service_Startup



;/*------------------------------[ service_stop ]------------------------------
; * Stops the service.
; *
; * NOTE: If this service will take longer than 3 seconds,
; * spawn a thread to execute the stop code and return.
; * Otherwise the SCM will think the service has stopped responding.
; *----------------------------------------------------------------------------*/

Func _Service_SetStopEvent()
;~  $gServiceStateRunning = 0
    $bServiceRunning = 0
;~  If $service_stop_event Then _WinAPI_SetEvent($service_stop_event)
EndFunc   ;==>_Service_SetStopEvent

 

Thanks for your advise:
Running on W11 and Windows Server 2019, same result !

 

C.
 

Link to comment
Share on other sites

On 6/6/2017 at 5:44 PM, dexto said:

In v4 there is a bug in services.au3:

Case $SERVICE_CONTROL_STOP,$SERVICE_ACCEPT_SHUTDOWN ; new in v4, stop when system shutdown ( better mmm ? )

https://msdn.microsoft.com/en-us/library/windows/desktop/ms683241(v=vs.85).aspx

should be:

Case $SERVICE_CONTROL_STOP,$SERVICE_CONTROL_SHUTDOWN ; new in v4, stop when system shutdown ( better mmm ? )

 

This is it!!! I found why it stopped by itself !

Link to comment
Share on other sites

  • 1 month later...

This is a great UDF.  Thanks!

I added a couple of functions to allow me to be able to backup/restore a service configuration and thought I would share back.

Add the following to ServicesConstants.au3:

Global Const $SERVICE_CONFIG_DELAYED_AUTO_START_INFO = 3
Global Const $SERVICE_CONFIG_FAILURE_ACTIONS_FLAG = 4
Global Const $SERVICE_CONFIG_SERVICE_SID_INFO = 5
Global Const $SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO = 6
Global Const $SERVICE_CONFIG_PRESHUTDOWN_INFO = 7
Global Const $SERVICE_CONFIG_TRIGGER_INFO = 8
Global Const $SERVICE_CONFIG_PREFERRED_NODE = 9
Global Const $SERVICE_CONFIG_LAUNCH_PROTECTED = 12
Global Const $SERVICE_CONFIG_ALL[] = [$SERVICE_CONFIG_DELAYED_AUTO_START_INFO, _
                                      $SERVICE_CONFIG_DESCRIPTION, _
                                      $SERVICE_CONFIG_FAILURE_ACTIONS, _
                                      $SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, _
                                      $SERVICE_CONFIG_PREFERRED_NODE, _
                                      $SERVICE_CONFIG_PRESHUTDOWN_INFO, _
                                      $SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, _
                                      $SERVICE_CONFIG_SERVICE_SID_INFO, _
                                      $SERVICE_CONFIG_TRIGGER_INFO, _
                                      $SERVICE_CONFIG_LAUNCH_PROTECTED]

Global Enum $SC_ACTION_TYPE, $SC_ACTION_DELAY

And add the following to Services.au3:

#include <Math.au3>

; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_ChangeConfig2
; Description ...: Sets the optional configuration parameters specified in $aInfo and $aInfoLevels for the specified service.
; Syntax.........: _Service_ChangeConfig($sServiceName, $aInfo, $aInfoLevels [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $aInfo - Array of configuration settings by InfoLevel index.
;                  $aInfoLevel - Array of InfoLevels to change the configuration setttings.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: None.
; Return values .: None.
; Author ........: chinadoug
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_ChangeConfig2($sServiceName, ByRef $aInfo, Const ByRef $aInfoLevels, $sComputerName = "")
    Local $hSC, $hService, $dwInfoLevel
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, BitOR($SERVICE_CHANGE_CONFIG, $SERVICE_START))

    For $dwInfoLevel in $aInfoLevels
        Switch $dwInfoLevel
        Case $SERVICE_CONFIG_DELAYED_AUTO_START_INFO
            ; update delayed auto start information
            Local $fDelayedAutostart = $aInfo[$dwInfoLevel]
            Local $serviceDelayedAutoStartInfo = DllStructCreate("INT fDelayedAutostart")
            Local $lpInfo = DllStructGetPtr($serviceDelayedAutoStartInfo)

            DllStructSetData($serviceDelayedAutoStartInfo, "fDelayedAutostart", $fDelayedAutostart)
        Case $SERVICE_CONFIG_DESCRIPTION
            ; update the service description
            Local $sDescription = $aInfo[$dwInfoLevel]
            Local $serviceDescription = DllStructCreate("PTR lpDescription")
            Local $lpInfo = DllStructGetPtr($serviceDescription)

            Local $lpDescription = DllStructCreate("wchar[" & (StringLen($sDescription)+1) & "]")
            DllStructSetData($lpDescription, 1, $sDescription)
            DllStructSetData($serviceDescription, "lpDescription", DllStructGetPtr($lpDescription))
        Case $SERVICE_CONFIG_FAILURE_ACTIONS
            ; update the failure actions
            Local $aFailureActions = $aInfo[$dwInfoLevel]
            Local $serviceFailureActions = DllStructCreate("DWORD dwResetPeriod;PTR lpRebootMsg;PTR lpCommand;DWORD cActions;PTR lpsaActions")
            Local $lpInfo = DllStructGetPtr($serviceFailureActions)

            Local $dwResetPeriod = $aFailureActions[0]
            DllStructSetData($serviceFailureActions, "dwResetPeriod", $dwResetPeriod)

            ; Notes
            ; if $sRebootMsg = "" then the reboot message will be deleted.
            ; if $sRebootMsg = Null then the reboot message will not be changed.
            Local $sRebootMsg = $aFailureActions[1]
            If Not IsString($sRebootMsg) Then $sRebootMsg = Null
            Local $lpRebootMsg = DllStructCreate("wchar[" & (StringLen($sRebootMsg)+1) & "]")
            DllStructSetData($lpRebootMsg, 1, $sRebootMsg)

            ; Notes
            ; if $sCommand = "" then the command will be deleted.
            ; if $sCommand = Null then the command will not be changed.
            Local $sCommand = $aFailureActions[2]
            If Not IsString($sCommand) Then $sCommand = Null
            Local $lpCommand = DllStructCreate("wchar[" & (StringLen($sCommand)+1) & "]")
            DllStructSetData($lpCommand, 1, $sCommand)

            ; Notes
            ; if $cActions = 0 AND $lpsaActions != Null then the values
            ;     for the reset period and any configured failure actions will be deleted.
            ; if $cActions = 0 AND $lpsaActions = Null then any
            ;     settings for the reset period and failure actions will be ignored.
            Local $cActions = $aFailureActions[3]

            Local $tagSC_ACTION = "INT Type;DWORD Delay"
            Local $itSC_ACTIONSize = DllStructGetSize(DllStructCreate($tagSC_ACTION))
            Local $lpsaActions

            Local $aActions = $aFailureActions[4]
            If IsArray($aActions) Then
                Local $tArraySC_ACTION = DllStructCreate("byte[" & (UBound($aActions) * $itSC_ACTIONSize) & "]")
                For $i = 0 to UBound($aActions)-1
                    Local $aAction = $aActions[$i]
                    Local $tSC_ACTION = DllStructCreate($tagSC_ACTION, DllStructGetPtr($tArraySC_ACTION) + ($i * $itSC_ACTIONSize))
                    DllStructSetData($tSC_ACTION, "Type", $aAction[$SC_ACTION_TYPE])
                    DllStructSetData($tSC_ACTION, "Delay", $aAction[$SC_ACTION_DELAY])
                Next
                $lpsaActions = DllStructGetPtr($tArraySC_ACTION)
            Else
                $lpsaActions = Null
            EndIf

            DllStructSetData($serviceFailureActions, "lpRebootMsg", ($sRebootMsg = Null ? Null : DllStructGetPtr($lpRebootMsg)))
            DllStructSetData($serviceFailureActions, "lpCommand", ($sCommand = Null ? Null : DllStructGetPtr($lpCommand)))
            DllStructSetData($serviceFailureActions, "cActions", $cActions)
            DllStructSetData($serviceFailureActions, "lpsaActions", $lpsaActions)
        Case $SERVICE_CONFIG_FAILURE_ACTIONS_FLAG
            ; update failure actions flag
            Local $fFailureActionsOnNonCrashFailures = $aInfo[$dwInfoLevel]
            Local $serviceFailureActionsFlag = DllStructCreate("INT fFailureActionsOnNonCrashFailures")
            Local $lpInfo = DllStructGetPtr($serviceFailureActionsFlag)

            DllStructSetData($serviceFailureActionsFlag, "fFailureActionsOnNonCrashFailures", $fFailureActionsOnNonCrashFailures)
        Case $SERVICE_CONFIG_PREFERRED_NODE
            ; update preferred node
            Local $aPreferredNodeInfo = $aInfo[$dwInfoLevel]
            Local $servicePreferredNodeInfo = DllStructCreate("USHORT usPreferredNode;BOOLEAN fDelete")
            Local $lpInfo = DllStructGetPtr($serviceFailureActions)

            Local $usPreferredNode = $aPreferredNodeInfo[0]
            Local $fDelete = $aPreferredNodeInfo[1]
            DllStructSetData($servicePreferredNodeInfo, "usPreferredNode", $usPreferredNode)
            DllStructSetData($servicePreferredNodeInfo, "fDelete", $fDelete)
        Case $SERVICE_CONFIG_PRESHUTDOWN_INFO
            ; update preshutdown info
            Local $dwPreshutdownTimeout = $aInfo[$dwInfoLevel]
            Local $servicePreshutdownInfo = DllStructCreate("DWORD dwPreshutdownTimeout")
            Local $lpInfo = DllStructGetPtr($servicePreshutdownInfo)

            DllStructSetData($servicePreshutdownInfo, "dwPreshutdownTimeout", $dwPreshutdownTimeout)
        Case $SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
            ; update required Privileges
            Local $aRequiredPrivileges = $aInfo[$dwInfoLevel]
            Local $iRequiredPrivilegesCount = UBound($aRequiredPrivileges)

            Local $serviceRequiredPrivilegesInfo = DllStructCreate("PTR pmszRequiredPrivileges")
            Local $lpInfo = DllStructGetPtr($serviceRequiredPrivilegesInfo)

            Local $spmszRequiredPrivilegesDefinition = ""
            For $i = 0 to $iRequiredPrivilegesCount-1
                $spmszRequiredPrivilegesDefinition &= "wchar[" & (StringLen($aRequiredPrivileges[$i]) + 1) & "];"
            Next
            $spmszRequiredPrivilegesDefinition &= "wchar"

            Local $pmszRequiredPrivileges = DllStructCreate($spmszRequiredPrivilegesDefinition)

            For $i = 0 to $iRequiredPrivilegesCount-1
                DllStructSetData($pmszRequiredPrivileges, $i+1, $aRequiredPrivileges[$i])
            Next

            DllStructSetData($serviceRequiredPrivilegesInfo, "pmszRequiredPrivileges", DllStructGetPtr($pmszRequiredPrivileges))
        Case $SERVICE_CONFIG_SERVICE_SID_INFO
            ; update SID info
            Local $dwServiceSidType = $aInfo[$dwInfoLevel]
            Local $serviceSidInfo = DllStructCreate("DWORD dwServiceSidType")
            Local $lpInfo = DllStructGetPtr($serviceSidInfo)

            DllStructSetData($serviceSidInfo, "dwServiceSidType", $dwServiceSidType)
        Case $SERVICE_CONFIG_TRIGGER_INFO
            ; update triggers
            Local $aTriggerInfo = $aInfo[$dwInfoLevel]
            Local $serviceTriggerInfo = DllStructCreate("DWORD cTriggers;PTR pTriggers;PTR pReserved")
            Local $lpInfo = DllStructGetPtr($serviceTriggerInfo)

            Local $cTriggers = $aTriggerInfo[0]
            Local $aTriggers = $aTriggerInfo[1]
            Local $pReserved = Null

            Local $tagServiceTriggerItem = "DWORD dwTriggerType;DWORD dwAction;PTR pTriggerSubType;DWORD cDataItems;PTR pDataItems"
            Local $itServiceTriggerItemSize = DllStructGetSize(DllStructCreate($tagServiceTriggerItem))
            Local $tArrayServiceTrigger = DllStructCreate("byte[" & ($cTriggers * $itServiceTriggerItemSize) & "]")
            Local $pTriggers

            If $cTriggers > 0 Then
                ; Find max # of data items assigned to any of the triggers
                ; Note: In order to simplify the code related to array
                ;       handling, the minimum size max will be set to 1
                ;       even if it is 0 in reality.
                Local $cDataItemsMax = 1
                For $i = 0 to $cTriggers-1
                    Local $aTrigger = $aTriggers[$i]
                    Local $cDataItems = $aTrigger[3]
                    $cDataItemsMax = _Max($cDataItemsMax, $cDataItems)
                Next

                ; Declare arrays used for holding various Struct objects.
                ; Note: When DllStructCreate allocates memory for holding a
                ;       Struct object's data, the output of DllStructCreate
                ;       can be assigned to a variable.  If that variable is
                ;       subsequently reassigned, such as during a for..next
                ;       loop, the memory where the previously referenced Struct
                ;       object is stored is released.  This means that any
                ;       pointer to that memory location is pointing to a
                ;       location that is no longer protected from reuse.
                ;       Originally, due to the use of loops to iterate over
                ;       the triggers and trigger data items, memory that
                ;       contained Structs was being freed before the code
                ;       that referenced those memory locations was ready. This
                ;       lead in some cases to that memory being overwritten
                ;       resulting in incorrect information being used.
                Local $tGUID[$cTriggers], $tArrayServiceTriggerSpecificDataItem[$cTriggers], $atDataItemData[$cTriggers][$cDataItemsMax]

                For $i = 0 to $cTriggers-1
                    Local $aTrigger = $aTriggers[$i]
                    Local $dwTriggerType = $aTrigger[0]
                    Local $dwAction = $aTrigger[1]
                    Local $sGUID = $aTrigger[2]
                    Local $cDataItems = $aTrigger[3]
                    Local $aDataItems = $aTrigger[4]

                    $tGUID[$i] = _WinAPI_GUIDFromString($sGUID)
                    Local $pTriggerSubType = DllStructGetPtr($tGUID[$i])

                    Local $tagServiceTriggerSpecificDataItem = "DWORD dwDataType;DWORD cbData;PTR pData"
                    Local $itServiceTriggerSpecificDataItem = DllStructGetSize(DllStructCreate($tagServiceTriggerSpecificDataItem))
                    $tArrayServiceTriggerSpecificDataItem[$i] = DllStructCreate("byte[" & ($cDataItems * $itServiceTriggerSpecificDataItem) & "]")
                    Local $pDataItems

                    If $cDataItems > 0 Then
                        For $j = 0 to $cDataItems-1
                            Local $aDataItem = $aDataItems[$j]
                            Local $dwDataType = $aDataItem[0]
                            Local $cbData = $aDataItem[1]
                            Local $sData = $aDataItem[2]

                            Switch $dwDataType
                            Case 1 ; SERVICE_TRIGGER_DATA_TYPE_BINARY
                                $atDataItemData[$i][$j] = DllStructCreate("byte["&$cbData&"]")
                                Local $aData = StringSplit($sData, " ")

                                For $k = 1 to $cbData
                                    DllStructSetData($atDataItemData[$i][$j], 1, Dec($aData[$k]), $k)
                                Next
                            Case 2 ; SERVICE_TRIGGER_DATA_TYPE_STRING
                                $atDataItemData[$i][$j] = DllStructCreate("wchar["&($cbData/2)&"];wchar")
                                DllStructSetData($atDataItemData[$i][$j], 1, $sData)
                            Case 3 ; SERVICE_TRIGGER_DATA_TYPE_LEVEL
                                $atDataItemData[$i][$j] = DllStructCreate("byte")
                                DllStructSetData($atDataItemData[$i][$j], 1, $sData)
                            Case 4, 5 ; SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY, SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL
                                $atDataItemData[$i][$j] = DllStructCreate("UINT64")
                                DllStructSetData($atDataItemData[$i][$j], 1, $sData)
                            EndSwitch
                            Local $pData = DllStructGetPtr($atDataItemData[$i][$j])

                            Local $tServiceTriggerSpecificDataItem = DllStructCreate($tagServiceTriggerSpecificDataItem, DllStructGetPtr($tArrayServiceTriggerSpecificDataItem[$i]) + ($j * $itServiceTriggerSpecificDataItem))
                            DllStructSetData($tServiceTriggerSpecificDataItem, "dwDataType", $dwDataType)
                            DllStructSetData($tServiceTriggerSpecificDataItem, "cbData", $cbData)
                            DllStructSetData($tServiceTriggerSpecificDataItem, "pData", $pData)
                        Next
                        $pDataItems = DllStructGetPtr($tArrayServiceTriggerSpecificDataItem[$i])
                    Else
                        $pDataItems = Null
                    EndIf

                    Local $tServiceTriggerItem = DllStructCreate($tagServiceTriggerItem, DllStructGetPtr($tArrayServiceTrigger) + ($i * $itServiceTriggerItemSize))
                    DllStructSetData($tServiceTriggerItem, "dwTriggerType", $dwTriggerType)
                    DllStructSetData($tServiceTriggerItem, "dwAction", $dwAction)
                    DllStructSetData($tServiceTriggerItem, "pTriggerSubType", $pTriggerSubType)
                    DllStructSetData($tServiceTriggerItem, "cDataItems", $cDataItems)
                    DllStructSetData($tServiceTriggerItem, "pDataItems", $pDataItems)
                Next
                $pTriggers = DllStructGetPtr($tArrayServiceTrigger)
            Else
                $pTriggers = Null
            EndIf

            DllStructSetData($serviceTriggerInfo, "cTriggers", $cTriggers)
            DllStructSetData($serviceTriggerInfo, "pTriggers", $pTriggers)
            DllStructSetData($serviceTriggerInfo, "pReserved", $pReserved)
        Case $SERVICE_CONFIG_LAUNCH_PROTECTED
            ; update launch protected info
            ; Note: This seems to be only changable once otherwise an error will occur.
            ; Also, if this is set to anything but 0, no further changes will be possible.
            ; Reverting this setting must be done manually via Regedit by editing
            ; LaunchProtected under the
            ; HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SheltSrv2 key and
            ; setting it to 0 and then rebooting.
            Local $dwLaunchProtected = $aInfo[$dwInfoLevel]
            Local $serviceLaunchProtectedInfo = DllStructCreate("DWORD dwLaunchProtected")
            Local $lpInfo = DllStructGetPtr($serviceLaunchProtectedInfo)

            DllStructSetData($serviceLaunchProtectedInfo, "dwLaunchProtected", $dwLaunchProtected)
        EndSwitch

        ChangeServiceConfig2($hService, $dwInfoLevel, $lpInfo)
    Next

    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)
EndFunc   ;==>_Service_ChangeConfig2



; #FUNCTION# =======================================================================================================================================================
; Name...........: _Service_QueryConfig2
; Description ...: Retrieves the optional configuration parameters of the specified service.
; Syntax.........: _Service_QueryConfig2($sServiceName, $tQC [, $sComputerName])
; Parameters ....: $sServiceName - Name of the service.
;                  $sComputerName - [Optional] The name of the target computer. The local computer is default.
; Requirement(s).: None.
; Return values .: Success - Returns array of configuration settings indexed by InfoLevel.
;                  Failure - 0
;                            Sets @error
; Author ........: chinadoug
; Modified.......:
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......:
; ==================================================================================================================================================================

Func _Service_QueryConfig2($sServiceName, $sComputerName = "")
    Local $hSC, $hService, $avQA, $tQB, $avQB, $iQE, $tQC
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $SERVICE_QUERY_CONFIG)

    Local $aInfoLevels[] = [$SERVICE_CONFIG_DELAYED_AUTO_START_INFO, _
                            $SERVICE_CONFIG_DESCRIPTION, _
                            $SERVICE_CONFIG_FAILURE_ACTIONS, _
                            $SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, _
                            $SERVICE_CONFIG_PREFERRED_NODE, _
                            $SERVICE_CONFIG_PRESHUTDOWN_INFO, _
                            $SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO, _
                            $SERVICE_CONFIG_SERVICE_SID_INFO, _
                            $SERVICE_CONFIG_TRIGGER_INFO, _
                            $SERVICE_CONFIG_LAUNCH_PROTECTED]
    Local $aInfo[13]

    For $i = 0 to UBound($aInfoLevels)-1
        Local $iInfoLevel = $aInfoLevels[$i]

        ; Determine needed size of the struct in bytes
        $avQA = QueryServiceConfig2($hService, $iInfoLevel, 0, 0)

        ; Get Service data
        $tQB = DllStructCreate("ubyte[" & $avQA[5] & "]")
        $avQB = QueryServiceConfig2($hService, $iInfoLevel, DllStructGetPtr($tQB), DllStructGetSize($tQB))
        Local $lpInfo = $avQB[3]

        ; Get last error
        If $avQB[0] = 0 Then $iQE = _WinAPI_GetLastError()

        ; Decode the ubyte structure
        Switch $iInfoLevel
        Case $SERVICE_CONFIG_DELAYED_AUTO_START_INFO
            ; get delayed auto start information
            ; Note: This setting is ignored unless Startup Type is set to Automatic.
            Local $serviceDelayedAutoStartInfo = DllStructCreate("INT fDelayedAutostart", $lpInfo)
            Local $fDelayedAutostart = DllStructGetData($serviceDelayedAutoStartInfo, "fDelayedAutostart")
            $aInfo[$SERVICE_CONFIG_DELAYED_AUTO_START_INFO] = $fDelayedAutostart
        Case $SERVICE_CONFIG_DESCRIPTION
            ; get service description (assumes length is less than or equal to 2048 characters)
            Local $serviceDescription = DllStructCreate("PTR lpDescription", $lpInfo)
            Local $lpDescription = DllStructGetData($serviceDescription, "lpDescription")
            Local $tDescription = DllStructCreate("wchar[2048]", $lpDescription)
            Local $sDescription = DllStructGetData($tDescription, 1)
            $aInfo[$SERVICE_CONFIG_DESCRIPTION] = $sDescription
        Case $SERVICE_CONFIG_FAILURE_ACTIONS
            ; get failure actions
            Local $aFailureActions[5]
            Local $serviceFailureActions = DllStructCreate("DWORD dwResetPeriod;PTR lpRebootMsg;PTR lpCommand;DWORD cActions;PTR lpsaActions", $lpInfo)

            $aFailureActions[0] = DllStructGetData($serviceFailureActions, "dwResetPeriod")

            Local $lpRebootMsg = DllStructGetData($serviceFailureActions, "lpRebootMsg")
            Local $tRebootMsg = DllStructCreate("wchar[2048]", $lpRebootMsg)

            $aFailureActions[1] = DllStructGetData($tRebootMsg, 1)

            Local $lpCommand = DllStructGetData($serviceFailureActions, "lpCommand")
            Local $tCommand = DllStructCreate("wchar[2048]", $lpCommand)

            $aFailureActions[2] = DllStructGetData($tCommand, 1)

            Local $cActions = DllStructGetData($serviceFailureActions, "cActions")
            
            $aFailureActions[3] = $cActions

            Local $lpsaActions = DllStructGetData($serviceFailureActions, "lpsaActions")

            Local $tagSC_ACTION = "INT Type;DWORD Delay"
            Local $itSC_ACTIONSize = DllStructGetSize(DllStructCreate($tagSC_ACTION))

            If $cActions > 0 Then
                Local $aActions[$cActions]

                For $j = 0 to $cActions-1
                    Local $tSC_ACTION = DllStructCreate($tagSC_ACTION, $lpsaActions + ($j * $itSC_ACTIONSize))
                    Local $aAction[2] = [DllStructGetData($tSC_ACTION, "Type"), DllStructGetData($tSC_ACTION, "Delay")]
                    $aActions[$j] = $aAction
                Next
                $aFailureActions[4] = $aActions
            Else
                $aFailureActions[4] = Null
            EndIf

            $aInfo[$SERVICE_CONFIG_FAILURE_ACTIONS] = $aFailureActions
        Case $SERVICE_CONFIG_FAILURE_ACTIONS_FLAG
            ; get failure actions flag
            Local $serviceFailureActionsFlag = DllStructCreate("INT fFailureActionsOnNonCrashFailures", $lpInfo)
            Local $fFailureActionsOnNonCrashFailures = DllStructGetData($serviceFailureActionsFlag, "fFailureActionsOnNonCrashFailures")

            $aInfo[$SERVICE_CONFIG_FAILURE_ACTIONS_FLAG] = $fFailureActionsOnNonCrashFailures
        Case $SERVICE_CONFIG_PREFERRED_NODE
            ; get preferred node
            Local $servicePreferredNodeInfo = DllStructCreate("USHORT usPreferredNode;BOOLEAN fDelete", $lpInfo)
            Local $usPreferredNode = DllStructGetData($servicePreferredNodeInfo, "usPreferredNode")
            Local $fDelete = False
            Local $aPreferredNodeInfo[2] = [$usPreferredNode, $fDelete]

            $aInfo[$SERVICE_CONFIG_PREFERRED_NODE] = $aPreferredNodeInfo
        Case $SERVICE_CONFIG_PRESHUTDOWN_INFO
            ; get preshutdown info
            Local $servicePreshutdownInfo = DllStructCreate("DWORD dwPreshutdownTimeout", $lpInfo)
            Local $dwPreshutdownTimeout = DllStructGetData($servicePreshutdownInfo, "dwPreshutdownTimeout")

            $aInfo[$SERVICE_CONFIG_PRESHUTDOWN_INFO] = $dwPreshutdownTimeout
        Case $SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
            ; get required Privileges
            Local $serviceRequiredPrivilegesInfo = DllStructCreate("PTR pmszRequiredPrivileges", $lpInfo)
            Local $pmszRequiredPrivileges = DllStructGetData($serviceRequiredPrivilegesInfo, "pmszRequiredPrivileges")

            Local $sRequiredPrivileges = ""
            While(True)
                Local $tmszRequiredPrivileges = DllStructCreate("wchar[2048]", $pmszRequiredPrivileges + $iOffset)
                If DllStructGetSize($tmszRequiredPrivileges) = 0 Then ExitLoop

                Local $sRequiredPrivilege = DllStructGetData($tmszRequiredPrivileges, 1)
                If $sRequiredPrivilege == "" Then ExitLoop

                $sRequiredPrivileges &= $sRequiredPrivilege & ";"
                $iOffset += 2 * (StringLen($sRequiredPrivilege) + 1)
            WEnd

            If $sRequiredPrivileges == "" Then
                Local $aRequiredPrivileges = Null
            Else
                $sRequiredPrivileges = StringTrimRight($sRequiredPrivileges,1)
                Local $aRequiredPrivileges = StringSplit($sRequiredPrivileges, ";", $STR_NOCOUNT)
            EndIf
            
            $aInfo[$SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO] = $aRequiredPrivileges
        Case $SERVICE_CONFIG_SERVICE_SID_INFO
            ; get SID info
            Local $serviceSidInfo = DllStructCreate("DWORD dwServiceSidType", $lpInfo)
            Local $dwServiceSidType = DllStructGetData($serviceSidInfo, "dwServiceSidType")

            $aInfo[$SERVICE_CONFIG_SERVICE_SID_INFO] = $dwServiceSidType
        Case $SERVICE_CONFIG_TRIGGER_INFO
            ; get trigger information
            Local $serviceTriggerInfo = DllStructCreate("DWORD cTriggers;PTR pTriggers;PTR pReserved", $lpInfo)

            Local $cTriggers = DllStructGetData($serviceTriggerInfo, "cTriggers")

            Local $pTriggers = DllStructGetData($serviceTriggerInfo, "pTriggers")

            Local $tagServiceTriggerItem = "DWORD dwTriggerType;DWORD dwAction;PTR pTriggerSubType;DWORD cDataItems;PTR pDataItems"
            Local $itServiceTriggerItemSize = DllStructGetSize(DllStructCreate($tagServiceTriggerItem))

            If $cTriggers > 0 Then
                Local $aTriggers[$cTriggers]

                For $j = 0 to $cTriggers-1
                    Local $aTrigger[5]
                    Local $tServiceTriggerItem = DllStructCreate($tagServiceTriggerItem, $pTriggers + ($j * $itServiceTriggerItemSize))
                    Local $dwTriggerType = DllStructGetData($tServiceTriggerItem, "dwTriggerType")
                    Local $dwAction = DllStructGetData($tServiceTriggerItem, "dwAction")
                    Local $pTriggerSubType = DllStructGetData($tServiceTriggerItem, "pTriggerSubType")
                    Local $cDataItems = DllStructGetData($tServiceTriggerItem, "cDataItems")
                    Local $pDataItems = DllStructGetData($tServiceTriggerItem, "pDataItems")

                    $aTrigger[0] = $dwTriggerType
                    $aTrigger[1] = $dwAction

                    Local $tGUID = DllStructCreate("ULONG;USHORT;USHORT;BYTE[8]",$pTriggerSubType)
                    Local $sGUID = _WinAPI_StringFromGUID($tGUID)
                    $aTrigger[2] = $sGUID

                    $aTrigger[3] = $cDataItems

                    Local $tagServiceTriggerSpecificDataItem = "DWORD dwDataType;DWORD cbData;PTR pData"
                    Local $itServiceTriggerSpecificDataItem = DllStructGetSize(DllStructCreate($tagServiceTriggerSpecificDataItem))

                    If $cDataItems > 0 Then
                        Local $aTriggerSpecificDataItems[$cDataItems]
                        
                        For $k = 0 to $cDataItems-1
                            Local $aTriggerSpecificDataItem[3]
                            Local $tServiceTriggerSpecificDataItem = DllStructCreate($tagServiceTriggerSpecificDataItem, $pDataItems + ($k * $itServiceTriggerSpecificDataItem))
                            Local $dwDataType = DllStructGetData($tServiceTriggerSpecificDataItem, "dwDataType")
                            Local $cbData = DllStructGetData($tServiceTriggerSpecificDataItem, "cbData")
                            Local $pData = DllStructGetData($tServiceTriggerSpecificDataItem, "pData")

                            $aTriggerSpecificDataItem[0] = $dwDataType
                            $aTriggerSpecificDataItem[1] = $cbData

                            Switch $dwDataType
                            Case 1 ; SERVICE_TRIGGER_DATA_TYPE_BINARY
                                Local $tData = DllStructCreate("BYTE["&$cbData&"]", $pData)
                                Local $aDataHex[$cbData]
                                For $l = 1 to $cbData
                                    $aDataHex[$l-1] = Hex(DllStructGetData($tData,1,$l), 2)
                                Next
                                Local $sData = _ArrayToString($aDataHex," ")
                            Case 2 ; SERVICE_TRIGGER_DATA_TYPE_STRING
                                Local $tData = DllStructCreate("WCHAR["&($cbData/2)&"]", $pData)
                                Local $sData = DllStructGetData($tData,1)
                            Case 3 ; SERVICE_TRIGGER_DATA_TYPE_LEVEL
                                Local $tData = DllStructCreate("BYTE", $pData)
                                Local $iData = DllStructGetData($tData,1)
                                Local $sData = $iData
                            Case 4, 5 ; SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY, SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL
                                Local $tData = DllStructCreate("UINT64", $pData)
                                Local $iData = DllStructGetData($tData,1)
                                Local $sData = $iData
                            EndSwitch

                            $aTriggerSpecificDataItem[2] = $sData
                            $aTriggerSpecificDataItems[$k] = $aTriggerSpecificDataItem
                        Next
                    Else
                        Local $aTriggerSpecificDataItems = Null
                    EndIf
                    $aTrigger[4] = $aTriggerSpecificDataItems
                    $aTriggers[$j] = $aTrigger
                Next
            Else
                Local $aTriggers = Null
            EndIf

            Local $aTriggerInfo[2] = [$cTriggers, $aTriggers]

            $aInfo[$SERVICE_CONFIG_TRIGGER_INFO] = $aTriggerInfo
        Case $SERVICE_CONFIG_LAUNCH_PROTECTED
            ; get launch protected info
            Local $serviceLaunchProtectedInfo = DllStructCreate("DWORD dwLaunchProtected", $lpInfo)
            Local $dwLaunchProtected = DllStructGetData($serviceLaunchProtectedInfo, "dwLaunchProtected")

            $aInfo[$SERVICE_CONFIG_LAUNCH_PROTECTED] = $dwLaunchProtected
        EndSwitch
    Next

    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)

    Return SetError($iQE, 0, $aInfo)
EndFunc   ;==>_Service_QueryConfig2



Func ChangeServiceConfig2($hService, $dwInfoLevel, $lpInfo)
    Local $avCSC2 = DllCall($hAdvapi32_DLL, "int", "ChangeServiceConfig2W", _
            "ptr", $hService, _
            "dword", $dwInfoLevel, _
            "ptr", $lpInfo)
    If @error Then Return SetError(@error, 0, 0)
    Return $avCSC2[0]
EndFunc   ;==>ChangeServiceConfig2



Func QueryServiceConfig2($hService, $iInfoLevel, $pBuffer, $iBufSize)
    Local $avQSC2 = DllCall($hAdvapi32_DLL, "int", "QueryServiceConfig2W", _
            "ptr", $hService, _
            "dword", $iInfoLevel, _
            "ptr", $pBuffer, _
            "dword", $iBufSize, _
            "dword*", 0)
    Return $avQSC2
EndFunc   ;==>QueryServiceConfig2

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...