Jump to content

Recommended Posts

Posted

Hi Merrik,

The message is clear, you can find some answer on the forum. I'll do some research to see if it's a known problem with service

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Posted

There are probably other solutions that could be used. I thought I would post the one that worked for me, just in case someone else needs an example.

Within Arcker's service example you can insert the following SQL code below (NOTE: using _SQL UDF never worked for me and created a coexistence error, nor did creating a function within the service)

You'll also notice that things can be left out of this script. This script does handle integrated authentication.

Hopefully someone will improve this script.

I hope this helps someone and thanks to Arcker for all of his hard work on this services UDF.

$sServer="MyDB_Server.domain.us\ins1"  ; take note of the fully qualified domain name
                                    $sDatabase="MyDB"
                                    $fAuthMode = True
                                    $sUsername = ""
                                    $sPassword = ""
                                    $sDriver = "{SQL Server}"
                                    Local $sTemp = StringMid($sDriver, 2, StringLen($sDriver) - 2)
                                    Local $sKey = "HKEY_LOCAL_MACHINE\SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers"
                                    Local $sVal = RegRead($sKey, $sTemp)
                                    If @error Or $sVal = "" Then Exit
                                    $oConn = ObjCreate("ADODB.Connection")
                                    If @error Or Not IsObj($oConn) Then COM_Error()

                                    If $fAuthMode = True Then
                                    $oConn.Open("DRIVER=" & $sDriver & ";SERVER=" & $sServer & ";DATABASE=" & $sDatabase & ";UID=" & $sUsername & ";PWD=" & $sPassword & ";")
                                        Else
                                    $oConn.Properties("Integrated Security").Value = "SSPI"
                                    $oConn.Properties("User ID") = $sUsername
                                    $oConn.Properties("Password") = $sPassword
                                    $oConn.Open("DRIVER={SQL Server};SERVER=" & $sServer & ";DATABASE=" & $sDatabase )
                                        EndIf

                                    If @error Then COM_Error()
                                        ;==>_Insert Text into Database
                                    If IsObj($oConn) Then
                                            ; MsgBox(0, "AutoIT-SQL Result", "We have a connection")
                                    $adoSQL = "INSERT INTO  dbo.MyDB VALUES ('" & $comp & "')"
                                     ; $adoSQL = "INSERT INTO dbo.Test VALUES ('Not_Name')"
                                    $oConn.Execute($adoSQL)
                                    EndIf
                                    If @error Then COM_Error()
                                    If Not @error Then Run('EVENTCREATE /T Information /ID 256 /L application /SO "My Service" /D "Successfully updated My database on SQL server"',"",@SW_HIDE) ;"Updated DB successfully"


                                        ;==>_Close Connection
                                    If IsObj($oConn) Then $oConn.Close

                                    If @error Then COM_Error()
                                    If Not @error Then Run('EVENTCREATE /T Information /ID 256 /L application /SO "My Service" /D "Successfully connected to My database on SQL server"',"",@SW_HIDE) ;"Discconected from DB successfully"
Posted

Hi Merrik, after some research, it seems that you have to call coinitialise BEFORE any obj interaction. I don't know if the script will work or not after that

btw thx for the example and the feedbacks.

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Posted

Need a little help here if some one can assist?

im trying to start this

and run it as a service to my application (an agent that collect computer information and sends it over tcp to a server..)

im having problem with putting "$oObj.connect("_Recv", "_Receiving", "_LostConnection", "_TimedOut")" some where in the service script..

if i put it outside, before the while $servicerunning it works only once and if i put it in side the while script it connects/reconnects all the time..

i vill present a good example script as soon as i get home..

(sorry i cannot put it in autoit tag, dosent work for some reason on my work computer.)

also does some one know if i need to set some dependences in the service creation to make the service only start if network is loaded/TCPIP?

//Regards Lasse

Do

If TimerDiff($iBegin) > 60000 Then ; Loop until 6 min have passed

_settings()

_updatedatabase()

$iBegin = TimerInit()

EndIf

If TimerDiff($iBegin1) > 600000 Then ; until 10 sec passed

If $MySQLServer <> "0.0.0.0" Then

_MySQLUpdateSoft()

EndIf

$iBegin1 = TimerInit()

EndIf

Sleep(10) ; just to keep the program running

Until $oObj.connect("_Recv", "_Receiving", "_LostConnection", "_TimedOut") > 0

_DebugOut("Client connected!")

Posted

You use an TCP Obj class that is an UDF. I don't know this UDF, so I wonder if the problem is service concerned.

Maybe, like before, it's a problem of coinitialise. BTW do you use objevent to trap com errors ?

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Posted (edited)

#NoTrayIcon
 
#include <Debug.au3>
#include "Client.au3"
 
_AutoItObject_Startup()
TCPStartup()
 
Global $runing = 1
 
 
_DebugSetup("TCP Client - PID: " & @AutoItPID)
 
$oObj = _Class_TCPClient(@IPAddress1, 8083, "supermotdepassesupersecret")
 
Do
Until $oObj.connect("_Recv", "_Receiving", "_LostConnection", "_TimedOut") > 0
_DebugOut("Client connecté!")
 
While $runing
    $oObj.Process()
WEnd
 
Func _Recv($data)
    _DebugOut("Reçu: " & $data)
    Switch $data
        Case "fin"
            $oObj.Send("OK, j''ai bien reçu lordre de me déconnecter!")
            $runing = 0
        Case "ping"
            $oObj.Send("pong")
    EndSwitch
    ; ---
    $oObj.Send("Bien reçu!")
EndFunc
 
Func _Receiving($bufferLen)
    _DebugOut("Reception ... " & $bufferLen)
EndFunc
 
Func _LostConnection()
    _DebugOut("Connexion perdue!")
EndFunc
 
Func _TimedOut($lostData_len)
    _DebugOut("Timed Out (" & $lostData_len & " perdus)")
EndFunc
 
TCPShutdown()
_AutoItObject_Shutdown()

Edited by lgvlgv
Posted (edited)

trying again, something strange happens when i try to post scripts?? :graduated:

i think its included on the client side in the script from TCPClass.zip

i got everything tunning and working as an exe file but i would really like to merge ex: serviceexample.au3 and the client example in TCPClass.zip

here is the example that i want to merge into any of the standard examples in this threed. (its in the documentation).

; Client

#NoTrayIcon

#include <Debug.au3>

#include "Client.au3"

_AutoItObject_Startup()

TCPStartup()

Global $runing = 1

; ##############################################################

_DebugSetup("TCP Client - PID: " & @AutoItPID)

$oObj = _Class_TCPClient(@IPAddress1, 8083, "supermotdepassesupersecret")

Do

Until $oObj.connect("_Recv", "_Receiving", "_LostConnection", "_TimedOut") > 0

_DebugOut("Client connecté!")

While $runing

$oObj.Process()

WEnd

Func _Recv($data)

_DebugOut("Reçu: " & $data)

Switch $data

Case "fin"

$oObj.Send("OK, j''ai bien reçu lordre de me déconnecter!")

$runing = 0

Case "ping"

$oObj.Send("pong")

EndSwitch

; ---

$oObj.Send("Bien reçu!")

EndFunc

Func _Receiving($bufferLen)

_DebugOut("Reception ... " & $bufferLen)

EndFunc

Func _LostConnection()

_DebugOut("Connexion perdue!")

EndFunc

Func _TimedOut($lostData_len)

_DebugOut("Timed Out (" & $lostData_len & " perdus)")

EndFunc

; ##############################################################

TCPShutdown()

_AutoItObject_Shutdown()

Edited by lgvlgv
Posted

Would be better to use standard TCP function. That's my opinion.

Note: quand tu postes du code, mets le en Anglais.

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Posted (edited)

any one notice that it takes long time after reboot to load desktop when u put a service on autostart?

or is it only at my end?

here is my script can anyone find something wrong in the way i use it?

i notice if i kill the service, Desktop starts in a sec if i let it be it starts after like 30 sec?

if i start the service when desktop allready loaded it starts in a sec.

#include <Misc.au3>
#include "Services.au3"
#include <file.au3>
Global $sServiceName = "CH-Deamon"
If @OSArch = "X64" Then
Global $key7 = "HKLM64"
Else
Global $key7 = "HKLM"
EndIf
If $cmdline[0] > 0 Then
Switch $cmdline[1]
  Case "-i"
   InstallService()
   _SelfRun($sServiceName, "start")
  Case "-u"
   RemoveService()
   $tempProc = ProcessExists("CH-Deamon.exe")
   If $tempProc Then
    ProcessClose($tempProc)
   EndIf
   $tempProc1 = ProcessExists("CH-Agent.exe")
   If $tempProc1 Then
    ProcessClose($tempProc1)
   EndIf
   Exit
  Case "-r"
   _SelfRun($sServiceName, "start")
  Case "-s"
   _SelfRun($sServiceName, "stop")
  Case Else
   Exit
EndSwitch
EndIf
_Service_Init($sServiceName)
Func _Svc_Main()
While $gServiceStateRunning
  If ProcessExists("CH-Agent.exe") Then
   Sleep(10)
  Else
   ShellExecute(@WindowsDir & "\CH-Agent.exe")
  EndIf
WEnd
Local $tempProc1 = ProcessExists("CH-Agent.exe")
If $tempProc1 Then
  ProcessClose($tempProc1)
EndIf
_Service_Cleanup()
EndFunc   ;==>_Svc_Main
Func InstallService()
If Not (IsAdmin()) Then
  MsgBox(0, "ChargeDeamon", "Admin rights needed, will exit now")
  Exit
EndIf
; _Service_Create($sServiceName, $sServiceName, BitOR($SERVICE_INTERACTIVE_PROCESS, $SERVICE_WIN32_OWN_PROCESS), $SERVICE_AUTO_START, $SERVICE_ERROR_SEVERE, '"' & @WindowsDir & '\' & @ScriptName & '"')
_Service_Create($sServiceName, $sServiceName, BitOR($SERVICE_INTERACTIVE_PROCESS, $SERVICE_WIN32_OWN_PROCESS), $SERVICE_AUTO_START, $SERVICE_ERROR_NORMAL, '"' & @WindowsDir & '\' & @ScriptName & '"')
If @error Then
  Return 0
EndIf
FileCopy(@ScriptName, @WindowsDir & '\' & @ScriptName, 1)
Return 1
Exit
EndFunc   ;==>InstallService
 
Func RemoveService()
_Service_Stop($sServiceName)
_Service_Delete($sServiceName)
Return 1
EndFunc   ;==>RemoveService
Func _SelfRun($servicename, $action)
$sCmdFile = 'sc ' & $action & ' "' & $servicename & '"'
Run($sCmdFile, @TempDir, @SW_HIDE)
Return 1
EndFunc   ;==>_SelfRun
Edited by lgvlgv
  • 2 weeks later...
Posted

I appreciate any support you can give. Great job so far.

#NoTrayIcon
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Version=Beta
#AutoIt3Wrapper_Change2CUI=y
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****
; Example of using service UDF to make an exe possibly runeed as a service
; By Arcker
; 10/09/2008
#include<Service.au3>
$sServiceName = "Autoit_Service"
If $cmdline[0] > 0 Then
    Switch $cmdline[1]
        Case "install", "-i", "/i"
            InstallService()
        Case "remove", "-u", "/u", "uninstall"
            RemoveService()
        Case Else
            ConsoleWrite(" - - - Help - - - " & @crlf)
            ConsoleWrite(" Service Example params : " & @crlf)
            ConsoleWrite("  -i : install service" & @crlf)
            ConsoleWrite("  -u : remove service" & @crlf)
            ConsoleWrite(" - - - - - - - - " & @crlf)
            Exit
            ;start service.
    EndSwitch
EndIf
_Service_init($sServiceName)
 
Func main()
    While 1
        ;doing what you want here
        fileWrite("C:\test.txt",@ComputerName & @TAB & @ScriptName & @CRLF)
        Sleep(10000)
    WEnd
EndFunc   ;==>main
Func InstallService()
    ConsoleWrite("Installing service, please wait" & @CRLF)
    _Service_Create("", $sServiceName, "Autoit Service Test", @ScriptFullPath)
    If @error Then
        ConsoleWrite("Problem installing service, Error number is " & @error & @CRLF & " message  : " & _WinAPI_GetLastErrorMessage())
    Else
        ConsoleWrite("Installation of service successful")
    EndIf
    Exit
EndFunc   ;==>InstallService
Func RemoveService()
    _StopService("", $sServiceName)
    _DeleteService("", $sServiceName)
    if not @error then ConsoleWrite("service removed successfully" & @crlf)
    Exit
EndFunc   ;==>RemoveService

Has this issue been resolved? I've been trying to do a similar thing by having a command in the -Svc_Main() but it seems that it doesn't want to do the command. The service starts and installs fine. Thanks for any help!

  • 3 months later...
Posted

I have been working with the Services.udf in conjunction with ServiceExample.au3 as well as the Sessionchange.au3 package.

I can reliably get the package to work for 5-20 minutes, after which it quits. My debugging shows it usually dies in the sleep section, occasionally when waking back up. I've seen several references to similiar behavior throughout the comments here but nothing with a definiitve answer. Is there anything I can do to straighten this out? I tried turning on some of the disabled logging in Services.au3 but it did not shed any light.

  • 3 weeks later...
Posted (edited)

Hello,

I have a big problem, I try to create a service, but before in Scite I have those problems :

U:servicesServicesConstants.au3(7,37) : ERROR: $READ_CONTROL previously declared as a 'Const'.
Global Const $READ_CONTROL = 0x20000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
U:servicesServicesConstants.au3(8,34) : ERROR: $WRITE_DAC previously declared as a 'Const'.
Global Const $WRITE_DAC = 0x40000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
U:servicesServicesConstants.au3(9,36) : ERROR: $WRITE_OWNER previously declared as a 'Const'.
Global Const $WRITE_OWNER = 0x80000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
U:servicesServicesConstants.au3(11,93) : ERROR: $STANDARD_RIGHTS_REQUIRED previously declared as a 'Const'.
Global $STANDARD_RIGHTS_REQUIRED = BitOR( $DELETE, $READ_CONTROL, $WRITE_DAC, $WRITE_OWNER )
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
U:servicesServices.au3 - 4 error(s), 0 warning(s)

Who can help me? Thanks in advance

Edited by ricky03
Posted (edited)

Those constants are declared in some other standard UDF in the newer AutoIt versions. Just comment them out in the Services UDF and you'll be fine.

Edit:

And you need to reevaluate your definition of "big".

Edited by wraithdu
Posted

Hello,

I habe a problem and I can't solve it. I install and uninstall my service, it works. I try to start it, but i have the message below :

"Could not stop the MyService service on local computer. Error 1053: The service did not respond to the start or control request in a timely fashion."

I found in this discussion a woman who as the problem, but no solution, who can help me?

Thanks in advance

Posted (edited)

@All : please try with service threadsafe script option instead of normal. I'm aware of problem services stop after 20 minutes since i've encountered them, and more problem too. The problem seems in dll opened that system doesn"t support well in services if each dllcall is call without dllopen.

Update :

My apologizes. For me, the example script doesn't work well too. I think i've found the culprit, but I have to work more to be sure next update will run smoothly.

The problem is in the while $running loop.

More weird, i've tested with version 3.3.8.1 on two identical systems, and on one it starts but fails after 20 seconds, and on another it fails at start.

Maybe the last version of autoit are more "strict" then show better errors with callback and more. I don't know.

If you want to make it work, remove the stop event wait from the loop, and the sleep, replace it with 10 ms instead of this big wait.

I'll try to post a functional example this week.

Edited by arcker

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Posted

Update : 02/03/2012

Ok there was some problems that i've tried to fix :

- Running was not exiting correctly since cleanup was executed without checking if the main loop is stopped

- Send Signal stopped was sometimes send error, whereas there were no errors

- Too much function, i've reset those in one main "ServiceMain" function, as MSDN says. Now there are some parts that should ne remove. Main

Code should be included after $bServiceRunning

- Event has be stopped : too many $Running signal sent to SCM, and I've done that because the C++ was done that way. Autoit cannot execute multiple thread so I've just remove those event, and when stop event is received, it just stops main loop.

Now the worst part :

In race condition, or not, the service doesn't stop well. I mean the main loop is break, but the process continues. So, as you can see, the service main is executed by SCM, not autoit directly, and I think that's the culprit. I'll try to post a request about this to autoit developers, but keep in mind that if it not autoit fault, or mine, so service will never be stable with autoit. Ive found a workaround by setting processclose at the end, it seems to work, but ... no problem with killing since your program is stopped, but then, i don't like this method.

Now, see the updated example in page 1 to see the update. Respect the comments in code by not removing anything, and you service should run fine .... until stop :oops:

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
  • 2 months later...
Posted (edited)

Hi Arcker,

Thnx for the nice UDF

I have a little problem when stopping a service, i always get an Error "1061" and i was wondering if you could take a look

The Example is an Webserver created in AutoIt. Run on Windows 7 32 Bits

#NoTrayIcon
#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=AutoItWebServer.exe
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Res_Comment=AutoItWebServer
#AutoIt3Wrapper_Res_Fileversion=0.1.0.0
#AutoIt3Wrapper_Res_LegalCopyright=AutoIt
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
://////=__=
://////=__=://.=.com
#AutoIt3Wrapper_Add_Constants=n
#AutoIt3Wrapper_Run_Tidy=y
#Obfuscator_Parameters=/striponly
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
; [url="http://www.autoitscript.com/forum/topic/80201-service-udf-v2-run-your-exe-as-service/page__st__240__p__933012__hl__application%20service__fromsearch__1#entry933012"]http://www.autoitscript.com/forum/topic/80201-service-udf-v2-run-your-exe-as-service/page__st__240__p__933012__hl__application%20service__fromsearch__1#entry933012[/url]
;~ Opt("MustDeclareVars", 1) ; just for self control  FPRIVATE "TYPE=PICT;ALT=smile.gif" dont to forget declare vars
#include <WindowsConstants.au3>
#include <APIConstants.au3>
#include <File.au3>
#include <String.au3>
#include <WinAPIEx.au3>
#include <Timers.au3>
#include "services.au3"

Global $MainLog = @ScriptDir & "test_service.log"
FileDelete($MainLog)
Global $sServiceName = "AutoItWebServer"
Global $sServiceNameDescription = "WebServer created in AutoIt"
Global $bServiceRunning = False, $iServiceCounter = 1
Local $sServerName = "AutoItWebServer"
Local $sRootDir = @ScriptDir & ""; The absolute path to the root directory of the server.
Local $sIP = @IPAddress1
Local $iPort = 8000 ; the listening por
Local $iMaxUsers = 15 ; Maximum number of users who can simultaneously get/postt
Dim $iNewSocket
Local $sServerAddress = "http://" & $sIP & ":" & $iPort & "/"
Local $aSocket[$iMaxUsers] ; Creates an array to store all the possible users
Local $sBuffer[$iMaxUsers] ; All these users have buffers when sending/receiving, so we need a place to store those
For $x = 0 To UBound($aSocket) - 1 ; Fills the entire socket array with -1 integers, so that the server knows they are empty.
$aSocket[$x] = -1
Next
; Registry Section
$HKCU = "HKEY_CURRENT_USER"
$HKLM = "HKEY_LOCAL_MACHINE"
$HKCR = "HKEY_CLASSES_ROOT"
If @OSArch = "X64" Then
$HKCU &= "64"
$HKLM &= "64"
$HKCR &= "64"
EndIf
TCPStartup() ; AutoIt needs to initialize the TCP functions
$iMainSocket = TCPListen($sIP, $iPort) ;create main listening socket
If @error Then ; if you fail creating a socket, exit the application
;MsgBox(0x20, $sServerName, "Unable to create a socket on port " & $iPort & ".") ; notifies the user that the HTTP server will not run
_Terminate()
EndIf

$bDebug = False
Func main($iArg, $sArgs)
#region -- STOP STOP STOP STOP - Don't change anything -- Service Start  ; Arcker 02/03/2012
If $bDebug Then logprint("***** & _Service_ServiceMain & *******" & @CRLF)
$ret = DllCall($hAdvapi32_DLL, "hwnd", "RegisterServiceCtrlHandler", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl));register service
If $ret[0] = 0 Then
  logprint("Error in registering service" & _WinAPI_GetLastError_2())
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  Return
EndIf
$tService_Status_handle = $ret[0]
If Not ($tService_Status_handle) Then
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  Return
EndIf
;goto cleanup;
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
  ;goto cleanup;
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  logprint("***** & error reporting Service_ReportStatus *******" & @CRLF)
  _Service_Cleanup()
  Return
EndIf
If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
  logprint("Erreur sending running status, exiting")
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  Return
EndIf
$bServiceRunning = True ; REQUIRED
If $bDebug Then logprint("main start")
#endregion -- STOP STOP STOP STOP - Don't change anything -- Service Start  ; Arcker 02/03/2012
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
  $iNewSocket = TCPAccept($iMainSocket) ; Tries to accept incoming connections
  If $iNewSocket >= 0 Then ; Verifies that there actually is an incoming connection
   For $x = 0 To UBound($aSocket) - 1 ; Attempts to store the incoming connection
    If $aSocket[$x] = -1 Then
     $aSocket[$x] = $iNewSocket ;store the new socket
     ExitLoop
    EndIf
   Next
  EndIf
  For $x = 0 To UBound($aSocket) - 1 ; A big loop to receive data from everyone connected
   If $aSocket[$x] = -1 Then ContinueLoop ; if the socket is empty, it will continue to the next iteration, doing nothing
   $sNewData = TCPRecv($aSocket[$x], 1024) ; Receives a whole lot of data if possible
   If @error Then ; Client has disconnected
    $aSocket[$x] = -1 ; Socket is freed so that a new user may join
    ContinueLoop ; Go to the next iteration of the loop, not really needed but looks oh so good
   ElseIf $sNewData Then ; data received
    $sBuffer[$x] &= $sNewData ;store it in the buffer
    If StringInStr(StringStripCR($sBuffer[$x]), @LF & @LF) Then ; if the request has ended ..
     $sFirstLine = StringLeft($sBuffer[$x], StringInStr($sBuffer[$x], @LF)) ; helps to get the type of the request
     $sRequestType = StringLeft($sFirstLine, StringInStr($sFirstLine, " ") - 1) ; gets the type of the request
     If $sRequestType = "GET" Then ; user wants to download a file or whatever ..
      $sRequest = StringTrimRight(StringTrimLeft($sFirstLine, 4), 11) ; let's see what file he actually wants
      If StringInStr(StringReplace($sRequest, "", "/"), "/.") Then ; Disallow any attempts to go back a folder
       ;_HTTP_SendError($aSocket[$x]) ; sends back an error
       _HTTP_SendFileNotFoundError($aSocket[$x])
      Else
       If $sRequest = "/" Then ; user has requested the root
        $sRequest = "/index.html" ; instead of root we'll give him the index page
       EndIf
       $sRequest = StringReplace($sRequest, "/", "") ; convert HTTP slashes to windows slashes, not really required because windows accepts both
       If FileExists($sRootDir & "" & $sRequest) Then ; makes sure the file that the user wants exists
        $sFileType = StringRight($sRequest, 4) ; determines the file type, so that we may choose what mine type to use
        Switch $sFileType
         Case ".html", ".htm", ".txt" ; in case of normal HTML files
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "text/html")
         Case ".css" ; in case of style sheets
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "text/css")
         Case ".jpg", "jpeg" ; for common images
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "image/jpeg")
         Case ".png" ; another common image format
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "image/png")
         Case Else ; this is for .exe, .zip, or anything else that is not supported is downloaded to the client using a application/octet-stream
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "application/octet-stream")
        EndSwitch
       Else
        _HTTP_SendFileNotFoundError($aSocket[$x]) ; File does not exist, so we'll send back an error..
       EndIf
      EndIf
     EndIf
     $sBuffer[$x] = "" ; clears the buffer because we just used to buffer and did some actions based on them
     $aSocket[$x] = -1 ; the socket is automatically closed so we reset the socket so that we may accept new clients
    EndIf
   EndIf
  Next

  Sleep(50)
  #endregion --> insert your running code here
WEnd
#region -- service stopping
_Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000);
If $bDebug Then logprint("main stopped. Cleanup.")
#region - STOP STOP STOP Service Stopped, don't change it or you will have stopping 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)
Return
#region - Service Stopped, don't change it or you will have stoping status
EndFunc   ;==>main
If $bDebug Then logprint("script started")
If $cmdline[0] > 0 Then
Switch $cmdline[1]
  Case "install", "-i", "/i"
   InstallService()
  Case "remove", "-u", "/u", "uninstall"
   RemoveService()
  Case "start", "-s", "/s"
   _Service_Start($sServiceName)
  Case "help", "-?", "/?"
   ShellExecute("[url="http://www.autoitscript.com/forum/"]http://www.autoitscript.com/forum/[/url]")
   Exit
  Case Else
   ConsoleWrite("Parameters : " & @CRLF & @CRLF _
      & " -i : install service" & @CRLF _
      & " -u : remove service" & @CRLF _
      & " -s : start service" & @CRLF _
      & " -? : Open online help" & @CRLF)
   Exit
   ;start service.
EndSwitch
Else
$Service_QueryStatus = _Service_QueryStatus($sServiceName)
If @error Then
  ConsoleWrite("Parameters : " & @CRLF & @CRLF _
     & " -i : install service" & @CRLF _
     & " -u : remove service" & @CRLF _
     & " -s : start service" & @CRLF _
     & " -? : Open online help" & @CRLF)
  Exit
Else
  _Service_init($sServiceName)
EndIf
EndIf

; 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()
Local $bDebug = True
RegWrite($HKLM & "SystemCurrentControlSetservices" & $sServiceName, "Description", "REG_SZ", $sServiceNameDescription)
If $bDebug Then ConsoleWrite("InstallService(): Installing service, please wait" & @CRLF)
If $cmdline[0] > 1 Then
  $sServiceName = $cmdline[2]
EndIf
_Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_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()
Local $bDebug = True
_Service_Stop($sServiceName)
_Service_Delete($sServiceName)
RegDelete($HKLM & "SystemCurrentControlSetservices" & $sServiceName, "Description")
If Not @error Then
  If $bDebug Then ConsoleWrite("RemoveService(): service removed successfully" & @CRLF)
  If $bDebug Then logprint("RemoveService(): service removed successfully" & @CRLF)
EndIf
Exit
EndFunc   ;==>RemoveService
Func _Terminate()
;~  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   ;==>_Terminate
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
Func _HTTP_ConvertString(ByRef $sInput) ; converts any characters like %20 into space 8)
$sInput = StringReplace($sInput, '+', ' ')
StringReplace($sInput, '%', '')
For $t = 0 To @extended
  $Find_Char = StringLeft(StringTrimLeft($sInput, StringInStr($sInput, '%')), 2)
  $sInput = StringReplace($sInput, '%' & $Find_Char, Chr(Dec($Find_Char)))
Next
EndFunc   ;==>_HTTP_ConvertString
Func _HTTP_SendHTML($hSocket, $sHTML, $sReply = "200 OK") ; sends HTML data on X socket
_HTTP_SendData($hSocket, Binary($sHTML), "text/html", $sReply)
EndFunc   ;==>_HTTP_SendHTML
Func _HTTP_SendFile($hSocket, $sFileLoc, $sMimeType, $sReply = "200 OK") ; Sends a file back to the client on X socket, with X mime-type
Local $hFile, $sImgBuffer, $sPacket, $a
$hFile = FileOpen($sFileLoc, 16)
$bFileData = FileRead($hFile)
FileClose($hFile)
_HTTP_SendData($hSocket, $bFileData, $sMimeType, $sReply)
EndFunc   ;==>_HTTP_SendFile
Func _HTTP_SendData($hSocket, $bData, $sMimeType, $sReply = "200 OK")
$sPacket = Binary("HTTP/1.1 " & $sReply & @CRLF & _
   "Server: " & $sServerName & @CRLF & _
   "Connection: close" & @CRLF & _
   "Content-Lenght: " & BinaryLen($bData) & @CRLF & _
   "Content-Type: " & $sMimeType & @CRLF & _
   @CRLF)
TCPSend($hSocket, $sPacket) ; Send start of packet
While BinaryLen($bData) ; Send data in chunks (most code by Larry)
  $a = TCPSend($hSocket, $bData) ; TCPSend returns the number of bytes sent
  $bData = BinaryMid($bData, $a + 1, BinaryLen($bData) - $a)
WEnd
$sPacket = Binary(@CRLF & @CRLF) ; Finish the packet
TCPSend($hSocket, $sPacket)
TCPCloseSocket($hSocket)
EndFunc   ;==>_HTTP_SendData
Func _HTTP_SendFileNotFoundError($hSocket) ; Sends back a basic 404 error
Local $s404Loc = $sRootDir & "404.html"
If (FileExists($s404Loc)) Then
  _HTTP_SendFile($hSocket, $s404Loc, "text/html")
Else
  _HTTP_SendHTML($hSocket, "404 Error: " & @CRLF & @CRLF & "The file you requested could not be found.")
EndIf
EndFunc   ;==>_HTTP_SendFileNotFoundError
Func SocketToIP($SHOCKET)
Local $sockaddr, $aRet
$sockaddr = DllStructCreate("short;ushort;uint;char[8]")
$aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
   "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
If Not @error And $aRet[0] = 0 Then
  $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
  If Not @error Then $aRet = $aRet[0]
Else
  $aRet = 0
EndIf
$sockaddr = 0
Return $aRet
EndFunc   ;==>SocketToIP
Edited by Emiel Wieldraaijer

Best regards,Emiel Wieldraaijer

Posted

Hi Arcker,

Thnx for the nice UDF

I have a little problem when stopping a service, i always get an Error "1061" and i was wondering if you could take a look

The Example is an Webserver created in AutoIt. Run on Windows 7 32 Bits

#NoTrayIcon
#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=AutoItWebServer.exe
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Res_Comment=AutoItWebServer
#AutoIt3Wrapper_Res_Fileversion=0.1.0.0
#AutoIt3Wrapper_Res_LegalCopyright=AutoIt
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
://////=__=
://////=__=://.=.com
#AutoIt3Wrapper_Add_Constants=n
#AutoIt3Wrapper_Run_Tidy=y
#Obfuscator_Parameters=/striponly
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
; [url="http://www.autoitscript.com/forum/topic/80201-service-udf-v2-run-your-exe-as-service/page__st__240__p__933012__hl__application%20service__fromsearch__1#entry933012"]http://www.autoitscript.com/forum/topic/80201-service-udf-v2-run-your-exe-as-service/page__st__240__p__933012__hl__application%20service__fromsearch__1#entry933012[/url]
;~ Opt("MustDeclareVars", 1) ; just for self control  FPRIVATE "TYPE=PICT;ALT=smile.gif" dont to forget declare vars
#include <WindowsConstants.au3>
#include <APIConstants.au3>
#include <File.au3>
#include <String.au3>
#include <WinAPIEx.au3>
#include <Timers.au3>
#include "services.au3"

Global $MainLog = @ScriptDir & "test_service.log"
FileDelete($MainLog)
Global $sServiceName = "AutoItWebServer"
Global $sServiceNameDescription = "WebServer created in AutoIt"
Global $bServiceRunning = False, $iServiceCounter = 1
Local $sServerName = "AutoItWebServer"
Local $sRootDir = @ScriptDir & ""; The absolute path to the root directory of the server.
Local $sIP = @IPAddress1
Local $iPort = 8000 ; the listening por
Local $iMaxUsers = 15 ; Maximum number of users who can simultaneously get/postt
Dim $iNewSocket
Local $sServerAddress = "http://" & $sIP & ":" & $iPort & "/"
Local $aSocket[$iMaxUsers] ; Creates an array to store all the possible users
Local $sBuffer[$iMaxUsers] ; All these users have buffers when sending/receiving, so we need a place to store those
For $x = 0 To UBound($aSocket) - 1 ; Fills the entire socket array with -1 integers, so that the server knows they are empty.
$aSocket[$x] = -1
Next
; Registry Section
$HKCU = "HKEY_CURRENT_USER"
$HKLM = "HKEY_LOCAL_MACHINE"
$HKCR = "HKEY_CLASSES_ROOT"
If @OSArch = "X64" Then
$HKCU &= "64"
$HKLM &= "64"
$HKCR &= "64"
EndIf
TCPStartup() ; AutoIt needs to initialize the TCP functions
$iMainSocket = TCPListen($sIP, $iPort) ;create main listening socket
If @error Then ; if you fail creating a socket, exit the application
;MsgBox(0x20, $sServerName, "Unable to create a socket on port " & $iPort & ".") ; notifies the user that the HTTP server will not run
_Terminate()
EndIf

$bDebug = False
Func main($iArg, $sArgs)
#region -- STOP STOP STOP STOP - Don't change anything -- Service Start  ; Arcker 02/03/2012
If $bDebug Then logprint("***** & _Service_ServiceMain & *******" & @CRLF)
$ret = DllCall($hAdvapi32_DLL, "hwnd", "RegisterServiceCtrlHandler", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl));register service
If $ret[0] = 0 Then
  logprint("Error in registering service" & _WinAPI_GetLastError_2())
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  Return
EndIf
$tService_Status_handle = $ret[0]
If Not ($tService_Status_handle) Then
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  Return
EndIf
;goto cleanup;
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
  ;goto cleanup;
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  logprint("***** & error reporting Service_ReportStatus *******" & @CRLF)
  _Service_Cleanup()
  Return
EndIf
If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
  logprint("Erreur sending running status, exiting")
  _Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
  Return
EndIf
$bServiceRunning = True ; REQUIRED
If $bDebug Then logprint("main start")
#endregion -- STOP STOP STOP STOP - Don't change anything -- Service Start  ; Arcker 02/03/2012
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
  $iNewSocket = TCPAccept($iMainSocket) ; Tries to accept incoming connections
  If $iNewSocket >= 0 Then ; Verifies that there actually is an incoming connection
   For $x = 0 To UBound($aSocket) - 1 ; Attempts to store the incoming connection
    If $aSocket[$x] = -1 Then
     $aSocket[$x] = $iNewSocket ;store the new socket
     ExitLoop
    EndIf
   Next
  EndIf
  For $x = 0 To UBound($aSocket) - 1 ; A big loop to receive data from everyone connected
   If $aSocket[$x] = -1 Then ContinueLoop ; if the socket is empty, it will continue to the next iteration, doing nothing
   $sNewData = TCPRecv($aSocket[$x], 1024) ; Receives a whole lot of data if possible
   If @error Then ; Client has disconnected
    $aSocket[$x] = -1 ; Socket is freed so that a new user may join
    ContinueLoop ; Go to the next iteration of the loop, not really needed but looks oh so good
   ElseIf $sNewData Then ; data received
    $sBuffer[$x] &= $sNewData ;store it in the buffer
    If StringInStr(StringStripCR($sBuffer[$x]), @LF & @LF) Then ; if the request has ended ..
     $sFirstLine = StringLeft($sBuffer[$x], StringInStr($sBuffer[$x], @LF)) ; helps to get the type of the request
     $sRequestType = StringLeft($sFirstLine, StringInStr($sFirstLine, " ") - 1) ; gets the type of the request
     If $sRequestType = "GET" Then ; user wants to download a file or whatever ..
      $sRequest = StringTrimRight(StringTrimLeft($sFirstLine, 4), 11) ; let's see what file he actually wants
      If StringInStr(StringReplace($sRequest, "", "/"), "/.") Then ; Disallow any attempts to go back a folder
       ;_HTTP_SendError($aSocket[$x]) ; sends back an error
       _HTTP_SendFileNotFoundError($aSocket[$x])
      Else
       If $sRequest = "/" Then ; user has requested the root
        $sRequest = "/index.html" ; instead of root we'll give him the index page
       EndIf
       $sRequest = StringReplace($sRequest, "/", "") ; convert HTTP slashes to windows slashes, not really required because windows accepts both
       If FileExists($sRootDir & "" & $sRequest) Then ; makes sure the file that the user wants exists
        $sFileType = StringRight($sRequest, 4) ; determines the file type, so that we may choose what mine type to use
        Switch $sFileType
         Case ".html", ".htm", ".txt" ; in case of normal HTML files
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "text/html")
         Case ".css" ; in case of style sheets
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "text/css")
         Case ".jpg", "jpeg" ; for common images
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "image/jpeg")
         Case ".png" ; another common image format
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "image/png")
         Case Else ; this is for .exe, .zip, or anything else that is not supported is downloaded to the client using a application/octet-stream
          _HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "application/octet-stream")
        EndSwitch
       Else
        _HTTP_SendFileNotFoundError($aSocket[$x]) ; File does not exist, so we'll send back an error..
       EndIf
      EndIf
     EndIf
     $sBuffer[$x] = "" ; clears the buffer because we just used to buffer and did some actions based on them
     $aSocket[$x] = -1 ; the socket is automatically closed so we reset the socket so that we may accept new clients
    EndIf
   EndIf
  Next

  Sleep(50)
  #endregion --> insert your running code here
WEnd
#region -- service stopping
_Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000);
If $bDebug Then logprint("main stopped. Cleanup.")
#region - STOP STOP STOP Service Stopped, don't change it or you will have stopping 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)
Return
#region - Service Stopped, don't change it or you will have stoping status
EndFunc   ;==>main
If $bDebug Then logprint("script started")
If $cmdline[0] > 0 Then
Switch $cmdline[1]
  Case "install", "-i", "/i"
   InstallService()
  Case "remove", "-u", "/u", "uninstall"
   RemoveService()
  Case "start", "-s", "/s"
   _Service_Start($sServiceName)
  Case "help", "-?", "/?"
   ShellExecute("[url="http://www.autoitscript.com/forum/"]http://www.autoitscript.com/forum/[/url]")
   Exit
  Case Else
   ConsoleWrite("Parameters : " & @CRLF & @CRLF _
      & " -i : install service" & @CRLF _
      & " -u : remove service" & @CRLF _
      & " -s : start service" & @CRLF _
      & " -? : Open online help" & @CRLF)
   Exit
   ;start service.
EndSwitch
Else
$Service_QueryStatus = _Service_QueryStatus($sServiceName)
If @error Then
  ConsoleWrite("Parameters : " & @CRLF & @CRLF _
     & " -i : install service" & @CRLF _
     & " -u : remove service" & @CRLF _
     & " -s : start service" & @CRLF _
     & " -? : Open online help" & @CRLF)
  Exit
Else
  _Service_init($sServiceName)
EndIf
EndIf

; 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()
Local $bDebug = True
RegWrite($HKLM & "SystemCurrentControlSetservices" & $sServiceName, "Description", "REG_SZ", $sServiceNameDescription)
If $bDebug Then ConsoleWrite("InstallService(): Installing service, please wait" & @CRLF)
If $cmdline[0] > 1 Then
  $sServiceName = $cmdline[2]
EndIf
_Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_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()
Local $bDebug = True
_Service_Stop($sServiceName)
_Service_Delete($sServiceName)
RegDelete($HKLM & "SystemCurrentControlSetservices" & $sServiceName, "Description")
If Not @error Then
  If $bDebug Then ConsoleWrite("RemoveService(): service removed successfully" & @CRLF)
  If $bDebug Then logprint("RemoveService(): service removed successfully" & @CRLF)
EndIf
Exit
EndFunc   ;==>RemoveService
Func _Terminate()
;~  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   ;==>_Terminate
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
Func _HTTP_ConvertString(ByRef $sInput) ; converts any characters like %20 into space 8)
$sInput = StringReplace($sInput, '+', ' ')
StringReplace($sInput, '%', '')
For $t = 0 To @extended
  $Find_Char = StringLeft(StringTrimLeft($sInput, StringInStr($sInput, '%')), 2)
  $sInput = StringReplace($sInput, '%' & $Find_Char, Chr(Dec($Find_Char)))
Next
EndFunc   ;==>_HTTP_ConvertString
Func _HTTP_SendHTML($hSocket, $sHTML, $sReply = "200 OK") ; sends HTML data on X socket
_HTTP_SendData($hSocket, Binary($sHTML), "text/html", $sReply)
EndFunc   ;==>_HTTP_SendHTML
Func _HTTP_SendFile($hSocket, $sFileLoc, $sMimeType, $sReply = "200 OK") ; Sends a file back to the client on X socket, with X mime-type
Local $hFile, $sImgBuffer, $sPacket, $a
$hFile = FileOpen($sFileLoc, 16)
$bFileData = FileRead($hFile)
FileClose($hFile)
_HTTP_SendData($hSocket, $bFileData, $sMimeType, $sReply)
EndFunc   ;==>_HTTP_SendFile
Func _HTTP_SendData($hSocket, $bData, $sMimeType, $sReply = "200 OK")
$sPacket = Binary("HTTP/1.1 " & $sReply & @CRLF & _
   "Server: " & $sServerName & @CRLF & _
   "Connection: close" & @CRLF & _
   "Content-Lenght: " & BinaryLen($bData) & @CRLF & _
   "Content-Type: " & $sMimeType & @CRLF & _
   @CRLF)
TCPSend($hSocket, $sPacket) ; Send start of packet
While BinaryLen($bData) ; Send data in chunks (most code by Larry)
  $a = TCPSend($hSocket, $bData) ; TCPSend returns the number of bytes sent
  $bData = BinaryMid($bData, $a + 1, BinaryLen($bData) - $a)
WEnd
$sPacket = Binary(@CRLF & @CRLF) ; Finish the packet
TCPSend($hSocket, $sPacket)
TCPCloseSocket($hSocket)
EndFunc   ;==>_HTTP_SendData
Func _HTTP_SendFileNotFoundError($hSocket) ; Sends back a basic 404 error
Local $s404Loc = $sRootDir & "404.html"
If (FileExists($s404Loc)) Then
  _HTTP_SendFile($hSocket, $s404Loc, "text/html")
Else
  _HTTP_SendHTML($hSocket, "404 Error: " & @CRLF & @CRLF & "The file you requested could not be found.")
EndIf
EndFunc   ;==>_HTTP_SendFileNotFoundError
Func SocketToIP($SHOCKET)
Local $sockaddr, $aRet
$sockaddr = DllStructCreate("short;ushort;uint;char[8]")
$aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
   "ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
If Not @error And $aRet[0] = 0 Then
  $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
  If Not @error Then $aRet = $aRet[0]
Else
  $aRet = 0
EndIf
$sockaddr = 0
Return $aRet
EndFunc   ;==>SocketToIP

I've just tested it and it works well with autoit beta version 3.3.9.4

i've modified a bit (added $bdebug variable ) and removed unneeded constants files.

retry it with last beta version.

#NoTrayIcon
#region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Outfile=AutoItWebServer.exe
#AutoIt3Wrapper_UseUpx=n
#AutoIt3Wrapper_Change2CUI=y
#AutoIt3Wrapper_Res_Comment=AutoItWebServer
#AutoIt3Wrapper_Res_Fileversion=0.1.0.0
#AutoIt3Wrapper_Res_LegalCopyright=AutoIt
#AutoIt3Wrapper_Res_Language=1033
#AutoIt3Wrapper_Res_requestedExecutionLevel=asInvoker
://////=__=
://////=__=://.=.com
#AutoIt3Wrapper_Run_Tidy=y
#Obfuscator_Parameters=/striponly
#endregion ;**** Directives created by AutoIt3Wrapper_GUI ****
; [url="http://www.autoitscript.com/forum/topic/80201-service-udf-v2-run-your-exe-as-service/page__st__240__p__933012__hl__application%20service__fromsearch__1#entry933012"]http://www.autoitscript.com/forum/topic/80201-service-udf-v2-run-your-exe-as-service/page__st__240__p__933012__hl__application%20service__fromsearch__1#entry933012[/url]
;~ Opt("MustDeclareVars", 1) ; just for self control  FPRIVATE "TYPE=PICT;ALT=smile.gif" dont to forget declare vars
Dim $bDebug = True

#include <WindowsConstants.au3>

;~ #include <APIConstants.au3>
#include <File.au3>
#include <String.au3>
;~ #include <WinAPIEx.au3>
#include <Timers.au3>
#include "services.au3"

Global $MainLog = @ScriptDir & "test_service.log"
FileDelete($MainLog)
Global $sServiceName = "AutoItWebServer"
Global $sServiceNameDescription = "WebServer created in AutoIt"
Global $bServiceRunning = False, $iServiceCounter = 1
Local $sServerName = "AutoItWebServer"
Local $sRootDir = @ScriptDir & ""; The absolute path to the root directory of the server.
Local $sIP = @IPAddress1
Local $iPort = 8000 ; the listening por
Local $iMaxUsers = 15 ; Maximum number of users who can simultaneously get/postt
Dim $iNewSocket
Local $sServerAddress = "http://" & $sIP & ":" & $iPort & "/"
Local $aSocket[$iMaxUsers] ; Creates an array to store all the possible users
Local $sBuffer[$iMaxUsers] ; All these users have buffers when sending/receiving, so we need a place to store those
For $x = 0 To UBound($aSocket) - 1 ; Fills the entire socket array with -1 integers, so that the server knows they are empty.
$aSocket[$x] = -1
Next
; Registry Section
$HKCU = "HKEY_CURRENT_USER"
$HKLM = "HKEY_LOCAL_MACHINE"
$HKCR = "HKEY_CLASSES_ROOT"
If @OSArch = "X64" Then
$HKCU &= "64"
$HKLM &= "64"
$HKCR &= "64"
EndIf
TCPStartup() ; AutoIt needs to initialize the TCP functions
$iMainSocket = TCPListen($sIP, $iPort) ;create main listening socket
If @error Then ; if you fail creating a socket, exit the application
;MsgBox(0x20, $sServerName, "Unable to create a socket on port " & $iPort & ".") ; notifies the user that the HTTP server will not run
_Terminate()
EndIf

$bDebug = False
Func main($iArg, $sArgs)
#region -- STOP STOP STOP STOP - Don't change anything -- Service Start  ; Arcker 02/03/2012
If $bDebug Then logprint("***** & _Service_ServiceMain & *******" & @CRLF)
$ret = DllCall($hAdvapi32_DLL, "hwnd", "RegisterServiceCtrlHandler", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl));register service
If $ret[0] = 0 Then
logprint("Error in registering service" & _WinAPI_GetLastError_2())
_Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
Return
EndIf
$tService_Status_handle = $ret[0]
If Not ($tService_Status_handle) Then
_Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
Return
EndIf
;goto cleanup;
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
;goto cleanup;
_Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
logprint("***** & error reporting Service_ReportStatus *******" & @CRLF)
_Service_Cleanup()
Return
EndIf
If Not _Service_ReportStatus($SERVICE_RUNNING, $NO_ERROR, 0) Then
logprint("Erreur sending running status, exiting")
_Service_ReportStatus($SERVICE_STOPPED, _WinAPI_GetLastError_2(), 0)
Return
EndIf
$bServiceRunning = True ; REQUIRED
If $bDebug Then logprint("main start")
#endregion -- STOP STOP STOP STOP - Don't change anything -- Service Start  ; Arcker 02/03/2012
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
$iNewSocket = TCPAccept($iMainSocket) ; Tries to accept incoming connections
If $iNewSocket >= 0 Then ; Verifies that there actually is an incoming connection
For $x = 0 To UBound($aSocket) - 1 ; Attempts to store the incoming connection
If $aSocket[$x] = -1 Then
$aSocket[$x] = $iNewSocket ;store the new socket
ExitLoop
EndIf
Next
EndIf
For $x = 0 To UBound($aSocket) - 1 ; A big loop to receive data from everyone connected
If $aSocket[$x] = -1 Then ContinueLoop ; if the socket is empty, it will continue to the next iteration, doing nothing
$sNewData = TCPRecv($aSocket[$x], 1024) ; Receives a whole lot of data if possible
If @error Then ; Client has disconnected
$aSocket[$x] = -1 ; Socket is freed so that a new user may join
ContinueLoop ; Go to the next iteration of the loop, not really needed but looks oh so good
ElseIf $sNewData Then ; data received
$sBuffer[$x] &= $sNewData ;store it in the buffer
If StringInStr(StringStripCR($sBuffer[$x]), @LF & @LF) Then ; if the request has ended ..
$sFirstLine = StringLeft($sBuffer[$x], StringInStr($sBuffer[$x], @LF)) ; helps to get the type of the request
$sRequestType = StringLeft($sFirstLine, StringInStr($sFirstLine, " ") - 1) ; gets the type of the request
If $sRequestType = "GET" Then ; user wants to download a file or whatever ..
$sRequest = StringTrimRight(StringTrimLeft($sFirstLine, 4), 11) ; let's see what file he actually wants
If StringInStr(StringReplace($sRequest, "", "/"), "/.") Then ; Disallow any attempts to go back a folder
;_HTTP_SendError($aSocket[$x]) ; sends back an error
_HTTP_SendFileNotFoundError($aSocket[$x])
Else
If $sRequest = "/" Then ; user has requested the root
$sRequest = "/index.html" ; instead of root we'll give him the index page
EndIf
$sRequest = StringReplace($sRequest, "/", "") ; convert HTTP slashes to windows slashes, not really required because windows accepts both
If FileExists($sRootDir & "" & $sRequest) Then ; makes sure the file that the user wants exists
$sFileType = StringRight($sRequest, 4) ; determines the file type, so that we may choose what mine type to use
Switch $sFileType
Case ".html", ".htm", ".txt" ; in case of normal HTML files
_HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "text/html")
Case ".css" ; in case of style sheets
_HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "text/css")
Case ".jpg", "jpeg" ; for common images
_HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "image/jpeg")
Case ".png" ; another common image format
_HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "image/png")
Case Else ; this is for .exe, .zip, or anything else that is not supported is downloaded to the client using a application/octet-stream
_HTTP_SendFile($aSocket[$x], $sRootDir & $sRequest, "application/octet-stream")
EndSwitch
Else
_HTTP_SendFileNotFoundError($aSocket[$x]) ; File does not exist, so we'll send back an error..
EndIf
EndIf
EndIf
$sBuffer[$x] = "" ; clears the buffer because we just used to buffer and did some actions based on them
$aSocket[$x] = -1 ; the socket is automatically closed so we reset the socket so that we may accept new clients
EndIf
EndIf
Next

Sleep(50)
#endregion --> insert your running code here
WEnd
#region -- service stopping
_Service_ReportStatus($SERVICE_STOP_PENDING, $NO_ERROR, 1000);
If $bDebug Then logprint("main stopped. Cleanup.")
#region - STOP STOP STOP Service Stopped, don't change it or you will have stopping 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)
Return
#region - Service Stopped, don't change it or you will have stoping status
EndFunc   ;==>main
If $bDebug Then logprint("script started")
If $cmdline[0] > 0 Then
Switch $cmdline[1]
Case "install", "-i", "/i"
InstallService()
Case "remove", "-u", "/u", "uninstall"
RemoveService()
Case "start", "-s", "/s"
_Service_Start($sServiceName)
Case "help", "-?", "/?"
ShellExecute("[url= http: / / www.autoitscript.com / forum /]http://www.autoitscript.com/forum/[/url]")
Exit
Case Else
ConsoleWrite("Parameters : " & @CRLF & @CRLF _
& " -i : install service" & @CRLF _
& " -u : remove service" & @CRLF _
& " -s : start service" & @CRLF _
& " -? : Open online help" & @CRLF)
Exit
;start service.
EndSwitch
Else
$Service_QueryStatus = _Service_QueryStatus($sServiceName)
If @error Then
ConsoleWrite("Parameters : " & @CRLF & @CRLF _
& " -i : install service" & @CRLF _
& " -u : remove service" & @CRLF _
& " -s : start service" & @CRLF _
& " -? : Open online help" & @CRLF)
Exit
Else
_Service_init($sServiceName)
EndIf
EndIf

; 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()
Local $bDebug = True
RegWrite($HKLM & "SystemCurrentControlSetservices" & $sServiceName, "Description", "REG_SZ", $sServiceNameDescription)
If $bDebug Then ConsoleWrite("InstallService(): Installing service, please wait" & @CRLF)
If $cmdline[0] > 1 Then
$sServiceName = $cmdline[2]
EndIf
_Service_Create($sServiceName, $sServiceName, $SERVICE_WIN32_OWN_PROCESS, $SERVICE_AUTO_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()
Local $bDebug = True
_Service_Stop($sServiceName)
_Service_Delete($sServiceName)
RegDelete($HKLM & "SystemCurrentControlSetservices" & $sServiceName, "Description")
If Not @error Then
If $bDebug Then ConsoleWrite("RemoveService(): service removed successfully" & @CRLF)
If $bDebug Then logprint("RemoveService(): service removed successfully" & @CRLF)
EndIf
Exit
EndFunc   ;==>RemoveService
Func _Terminate()
;~  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   ;==>_Terminate
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
Func _HTTP_ConvertString(ByRef $sInput) ; converts any characters like %20 into space 8)
$sInput = StringReplace($sInput, '+', ' ')
StringReplace($sInput, '%', '')
For $t = 0 To @extended
$Find_Char = StringLeft(StringTrimLeft($sInput, StringInStr($sInput, '%')), 2)
$sInput = StringReplace($sInput, '%' & $Find_Char, Chr(Dec($Find_Char)))
Next
EndFunc   ;==>_HTTP_ConvertString
Func _HTTP_SendHTML($hSocket, $sHTML, $sReply = "200 OK") ; sends HTML data on X socket
_HTTP_SendData($hSocket, Binary($sHTML), "text/html", $sReply)
EndFunc   ;==>_HTTP_SendHTML
Func _HTTP_SendFile($hSocket, $sFileLoc, $sMimeType, $sReply = "200 OK") ; Sends a file back to the client on X socket, with X mime-type
Local $hFile, $sImgBuffer, $sPacket, $a
$hFile = FileOpen($sFileLoc, 16)
$bFileData = FileRead($hFile)
FileClose($hFile)
_HTTP_SendData($hSocket, $bFileData, $sMimeType, $sReply)
EndFunc   ;==>_HTTP_SendFile
Func _HTTP_SendData($hSocket, $bData, $sMimeType, $sReply = "200 OK")
$sPacket = Binary("HTTP/1.1 " & $sReply & @CRLF & _
"Server: " & $sServerName & @CRLF & _
"Connection: close" & @CRLF & _
"Content-Lenght: " & BinaryLen($bData) & @CRLF & _
"Content-Type: " & $sMimeType & @CRLF & _
@CRLF)
TCPSend($hSocket, $sPacket) ; Send start of packet
While BinaryLen($bData) ; Send data in chunks (most code by Larry)
$a = TCPSend($hSocket, $bData) ; TCPSend returns the number of bytes sent
$bData = BinaryMid($bData, $a + 1, BinaryLen($bData) - $a)
WEnd
$sPacket = Binary(@CRLF & @CRLF) ; Finish the packet
TCPSend($hSocket, $sPacket)
TCPCloseSocket($hSocket)
EndFunc   ;==>_HTTP_SendData
Func _HTTP_SendFileNotFoundError($hSocket) ; Sends back a basic 404 error
Local $s404Loc = $sRootDir & "404.html"
If (FileExists($s404Loc)) Then
_HTTP_SendFile($hSocket, $s404Loc, "text/html")
Else
_HTTP_SendHTML($hSocket, "404 Error: " & @CRLF & @CRLF & "The file you requested could not be found.")
EndIf
EndFunc   ;==>_HTTP_SendFileNotFoundError
Func SocketToIP($SHOCKET)
Local $sockaddr, $aRet
$sockaddr = DllStructCreate("short;ushort;uint;char[8]")
$aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
"ptr", DllStructGetPtr($sockaddr), "int*", DllStructGetSize($sockaddr))
If Not @error And $aRet[0] = 0 Then
$aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
If Not @error Then $aRet = $aRet[0]
Else
$aRet = 0
EndIf
$sockaddr = 0
Return $aRet
EndFunc   ;==>SocketToIP

-- Arck System _ Soon -- Ideas make everything

"La critique est facile, l'art est difficile"

Projects :

[list] [*]Au3Service : Run your exe as service V3 / Updated 29/07/2013 Get it Here [/list]
Posted (edited)

EDIT: Since the issue is a general W7 issue, not anything to do with this UDF, I decided to open new thread

Edited by CGRemakes

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
×
×
  • Create New...