Jump to content

_Service_UDF v4 : Build your own service with autoit code


arcker
 Share

Recommended Posts

  • 4 weeks later...

I try to use HotKeySet, is this not posible as service or is somthing wrong?

 

;------------------------------------
;Code striped, all the rest is orgial
;------------------------------------

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)

HotKeySet("+!l", "HotKeyPressed") ; Shift-Alt-l this and HotKeyPressed is the only code I made

;~  $count += 1
    _Sleep(1000)
;~  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

;------------------------------------
;Code striped, all the rest is orgial
;------------------------------------

Func HotKeyPressed()

      Local $iPID = Run("notepad.exe", "", @SW_SHOWMAXIMIZED)

EndFunc   ;==>HotKeyPressed

 

Link to comment
Share on other sites

  • 4 months later...

Hi.

Ive tried to get this to work with a script i currently have.

I compiled the examle and ran it from command line. Nothing happend so i tried a few diffrent commands and tried to get it to work. Suddenly i had 2 diffrent services. One of them i could remove by just switching -i to -u

But now i have another service that i cannot remove. Is there another way to "manually" remove the service?

Link to comment
Share on other sites

@Tjalve You can use the SC command line tool program to remove a service (Requires Admin Privs)
 

sc delete

DESCRIPTION:
        Deletes a service entry from the registry.
        If the service is running, or another process has an
        open handle to the service, the service is simply marked
        for deletion.
USAGE:
        sc <server> delete [service name]

 

edit: Keep it mind, you need to provide the Service Name, not the Display Name (in case they are different).  For example:
 

SERVICE_NAME: wuauserv
DISPLAY_NAME: Windows Update

 

Edited by spudw2k
Link to comment
Share on other sites

  • 3 months later...

Hi people. I read all about this Windows Service with Autoit, but nothing shows clearly how to run a program / command to the active user session.

In other case, Windows call "UI0Detect.exe" to show a message. I create this service with the parameter $SERVICE_INTERACTIVE_PROCESS.

I try use this code and i can call a program (in this case, calc.exe) but the process starts with the son of the service, not in the user session.

Try to this code called "CreateCodeAsUser", unsuccessfully.

Can anyone help more? Thanks

Edited by mcarmello
Link to comment
Share on other sites

  • 11 months later...

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 ? )

 

Link to comment
Share on other sites

4 minutes ago, MattHiggs said:

And duct tape is silver...

is Gray, the A/C one is silver but none of this is gonna be read by @WeMartiansAreFriendly ( gone since 2011 ), now, what you mean by that ?

Edited by argumentum

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

5 minutes ago, argumentum said:

is Gray, the A/C one is silver but none of this is gonna be read by @WeMartiansAreFriendly ( gone since 2011 ), now, what you mean by that ?

Its a pun.  Saw a t-shirt with that written on it.  It not only is true because it is silver colored, but it also implies "if you won't be quite (silence is golden), we can always go with the second best (silver) option and restrain you with duct tape and make you be quiet (duct tape is silver)."  Thought it was the funniest t-shirt ever.

SILENCE_foil.jpg

Edited by MattHiggs
Link to comment
Share on other sites

  • 1 month later...

I've been trying to use ServiceExample_v4.au3 to help convert a simple console .exe application into a background service. All the exe does is report the system's status to a remote monitoring server.

I can get the service to install and run no problem but the exe does not run. It does not show in the task manager. Netstat does not show it making the network connection.

Below is my modified version of ServiceExample

All I did was add a loop in the section mentioned like this. It code works great on its own.

 

Quote

    While 1
        Sleep(100)
        If Not ProcessExists("myagent.exe") Then
            Run("C:\Users\username\Desktop\agent\myagent.exe -c C:\Users\username\Desktop\agent\config.txt")
        EndIf
    WEnd

 

Can anyone point me in the right direction please?

 

 

#NoTrayIcon
#RequireAdmin
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Compile_Both=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
Opt("mustdeclarevars",1)
;~ #AutoIt3Wrapper_Version=beta
;~ Opt("MustDeclareVars", 1) ; just for self control  FPRIVATE "TYPE=PICT;ALT=smile.gif" dont to forget declare vars
Dim $MainLog = @ScriptDir & "\test_service.log"
;~ FileDelete($MainLog)
;~ If $bServiceRunning Then Exit
;~ logprint("program started" & $cmdlineraw)

#include <Winapi.au3> ;just for constants
#include "services.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
    While 1
        Sleep(100)
        If Not ProcessExists("myagent.exe") Then
            Run("C:\Users\username\Desktop\agent\myagent.exe -c C:\Users\username\Desktop\agent\config.txt")
        EndIf
    WEnd






#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()
    #RequireAdmin
    Local $bDebug = True
;~  If $bDebug Then ConsoleWrite("InstallService(): Installing service, please wait")
    If $cmdline[0] > 1 Then

        $sServiceName = $cmdline[2]
    EndIf
    If $bDebug Then ConsoleWrite("InstallService("&$sServiceName &"): Installing service, please wait")
    _Service_Create($sServiceName, "Au3Service " & $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_DEMAND_START, $SERVICE_ERROR_SEVERE, '"' & @ScriptFullPath & '"')
    If @error Then

        If $bDebug Then ConsoleWrite("InstallService(): Problem installing service, Error number is " & @error & @CRLF & " message : " & _WinAPI_GetLastErrorMessage())
    Else
        If $bDebug Then ConsoleWrite("InstallService(): Installation of service successful")
    EndIf
    Exit
EndFunc   ;==>InstallService
Func RemoveService()
    _Service_Stop($sServiceName)
    _Service_Delete($sServiceName)
    If Not @error Then
;~      If $bDebug Then logprint("RemoveService(): service removed successfully" & @CRLF)
    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

 

 

Link to comment
Share on other sites

Hello! At first thanks Arker for great lib. At this night i make some rework for v4, may be someone test it.

Maked updates:

1. Added usage simplicity and transparency, now you can just put your service payload in example in function _Service_payload() ,

service loops, clean resources and other moved to library

2. Logging function moved to library

3. Add comments for uncommented functions in library

4. Lib code refactored

P.S. It's beta ) use it at your own risk )

 

 

 

 

Services.au3

ServicesConstants.au3

ServiceExample_v4.au3

Link to comment
Share on other sites

Thanks so much for the hard work syn5555.

Your example installs and works but with one small problem. When you stop the service after a few minutes an application crash  message pops up.

I suspect it has something to do with the main function not knowing the service was sent a stop command but I'm not sure.

Link to comment
Share on other sites

  • 1 month later...

RoscoeT Thanks, i find this bug too, then i try it with real payload, not just sleep func. 

I try to find time and fix it. 

I hope you do not try to start some app.exe in service payload ? You still cant do this from payload. Remember from here you cannot start functions that interact with desktop, because this is service and it work then nobody is logged in.

Edited by syn5555
Link to comment
Share on other sites

On 8.9.2017 at 3:09 PM, syn5555 said:

RoscoeT Thanks, i find this bug too, then i try it with real payload, not just sleep func. 

I try to find time and fix it. 

I hope you do not try to start some app.exe in service payload ? You still cant do this from payload. Remember from here you cannot start functions that interact with desktop, because this is service and it work then nobody is logged in.

Could you please provide new fixed Script and provide Sample ?

Link to comment
Share on other sites

  • 3 months later...
On 9/12/2017 at 3:01 PM, tb-killa said:

I try to find time and fix it. 

tested the OP UDF in AutoIt v3.2.12.1, v3.3.6.1, v3.3.8.1 running fine in WinXP ( where the script shows to hang ).
It does hang in v3.3.14.2 and 3.3.15.0 (beta). So is not a problem with the UDF. @RoscoeT, I did not do any more testing other than this, as it solves the problem of the compiled script.

I'm sharing this finding because I was coding a service, testing, and noticed a problem, found a simple solution and sharing for the next poor soul :) 

In any other case, use the latest release, as is overall better.

Edited by argumentum
added testing of v3.3.15.0 results

Follow the link to my code contribution ( and other things too ).
FAQ - Please Read Before Posting.
autoit_scripter_blue_userbar.png

Link to comment
Share on other sites

  • 4 months later...
On 10/02/2015 at 8:02 PM, Zinthose said:

Just an FYI:
I added the ability to add the description in the "_Service_Create" function.  I just added a new optional param "$sDescription = Default" and plopped this bit of code in the function.

;## Set Description
        If $sDescription <> Default Then
            Local $serviceDescription = DllStructCreate("ptr")
            Local $caDescription = DllStructCreate("char[260]")
            DllStructSetData($caDescription, 1, $sDescription)
            DllStructSetData($serviceDescription, 1, DllStructGetPtr($caDescription))
            DllCall($hAdvapi32_DLL, "int", "ChangeServiceConfig2", "long", $avSC[0], "long", 1, "long", DllStructGetPtr($serviceDescription))
        EndIf
        CloseServiceHandle($avSC[0]) ;<-- Line that already exists in function

Works great for me.  ^u^

 

I would like to use ChangeServiceConfig2 function to set recovery properties but it doesn't work. Here is my code :

Func _ChangeServiceConfig2($sServiceName, $sComputerName = "")
    Local $hSC, $hService, $rdll
    $hSC = OpenSCManager($sComputerName, $SC_MANAGER_CONNECT)
    $hService = OpenService($hSC, $sServiceName, $SERVICE_CHANGE_CONFIG)

    ;~ typedef struct _SERVICE_FAILURE_ACTIONS {
    ;~   DWORD     dwResetPeriod;
    ;~   LPTSTR    lpRebootMsg;
    ;~   LPTSTR    lpCommand;
    ;~   DWORD     cActions;
    ;~   SC_ACTION *lpsaActions;
    ;~  } SERVICE_FAILURE_ACTIONS, *LPSERVICE_FAILURE_ACTIONS;

    ;~  typedef struct _SC_ACTION {
    ;~   SC_ACTION_TYPE Type;
    ;~   DWORD          Delay;
    ;~ } SC_ACTION, *LPSC_ACTION;

    Local $SC_ACTION_NONE = 0
    Local $SC_ACTION_REBOOT = 2
    Local $SC_ACTION_RESTART = 1
    Local $SC_ACTION_RUN_COMMAND = 3
    Local $SERVICE_CONFIG_FAILURE_ACTIONS = 2

    Local $sc_action = DllStructCreate("int Type; DWORD Delay")
    DllStructSetData($sc_action, "Type", $SC_ACTION_RESTART)
    DllStructSetData($sc_action, "Delay", 1000)

    Local Const $sTagSC_ACTION = "int;dword"
    Local $iNumberOfArrayElement = 1

    Local $tArraySC_ACTION = DllStructCreate($sTagSC_ACTION)
    DllStructSetData($tArraySC_ACTION, 1, $SC_ACTION_RESTART)
    DllStructSetData($tArraySC_ACTION, 2, 10000)
    Local $PtrSC_ACTION_Array = DllStructGetPtr($tArraySC_ACTION)

    Local $serviceFailureActions = DllStructCreate("DWORD dwResetPeriod;ptr lpRebootMsg;ptr lpCommand;DWORD cActions;ptr lpsaActions")
    DllStructSetData($serviceFailureActions, "dwResetPeriod", "INFINITE")

    Local $lpRebootMsg = DllStructCreate("wstr")
    DllStructSetData($lpRebootMsg, 1, "")

    DllStructSetData($serviceFailureActions, "lpRebootMsg", DllStructGetPtr($lpRebootMsg))
    DllStructSetData($serviceFailureActions, "lpCommand", Null)
    DllStructSetData($serviceFailureActions, "cActions", $iNumberOfArrayElement)
    DllStructSetData($serviceFailureActions, "lpsaActions", $PtrSC_ACTION_Array)

    Local $dwInfoLevel = $SERVICE_CONFIG_FAILURE_ACTIONS
    Local $lpInfo = DllStructGetPtr($serviceFailureActions)
    $rdll = DllCall($hAdvapi32_DLL, "BOOLEAN", "ChangeServiceConfig2", _
                                                    "HANDLE", $hService, _
                                                    "DWORD", $dwInfoLevel, _
                                                    "ptr", $lpInfo) ; pointeur vers la structure SERVICE_FAILURE_ACTIONS


    CloseServiceHandle($hService)
    CloseServiceHandle($hSC)

    If @error Then
        Return 0
    Else
        Return $rdll[0]
    EndIf

EndFunc

 

I suppose my problem coming from the "lpsaActions" variable. It should be a pointer to array of Service_Failure_Actions structures.

Any idea ?

Thanks

Edited by tatane
Link to comment
Share on other sites

  • 2 months later...

From what I can see, no.  The CreateService functions don't seem to support it as an initial Start Type either, from what I understand.

You can either use the sc command line tool to change it after the service is created, or use one of the ChangeServiceConfig2 functions in Advapi32.dll.

Link to comment
Share on other sites

  • 3 weeks later...
On 7/30/2018 at 5:48 AM, spudw2k said:

From what I can see, no.  The CreateService functions don't seem to support it as an initial Start Type either, from what I understand.

You can either use the sc command line tool to change it after the service is created, or use one of the ChangeServiceConfig2 functions in Advapi32.dll.

Will it be included in V5, as it is being prepared?

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...