Jump to content

_Service_UDF v4 : Build your own service with autoit code


arcker
 Share

Recommended Posts

Still the same problem. The problem is in this function:

Func _Service_ServiceMain($iArg, $pArgs)
    Local $ret = DllCall($ghADVAPI32, "ptr", "RegisterServiceCtrlHandlerExW", "ptr", DllStructGetPtr($tServiceName), "ptr", DllCallbackGetPtr($tServiceCtrl), "ptr", 0) ;register service
    If @error Or ($ret[0] = 0) Then Exit
    $tService_Status_handle = $ret[0]
    If Not $tService_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)
    _Svc_Main()
EndFunc   ;==>_Service_ServiceMain

_Svc_Main() function is called, but there seems to be no function defined with that name. Or am I misunderstanding how this was intended to be used? I can comment that line out and everything compiles fine but then it seems like it's not reporting status. I would start a new thread and post my program and ask for some help except for the svc_main compile error.

I haven't

Link to comment
Share on other sites

Hi,

I had the same problem today. I searched for _Svc_Main() in Services.au3 and found one instance so I commented it out and compiled the scipt and it ran. for now it is just a simple return the status and display it in a message box test script so i don't know if removing that will have impact as my script grows.

Link to comment
Share on other sites

Actually I think I figured it out. I think he means for us to put our program body into a function called _Svc_Main. Then compile with the Services.au3. Unfortunately arcker assumes we know to do this. I only figured it out by looking at the two examples in the first post in this thread.

Link to comment
Share on other sites

Actually it's also called in services.au3, even though it doesn't exist. I know I'm an infrequent poster, but let's not be rude.

I was trying to compile my script to call service reporting functions in services.au3. I couldn't get it working though, it kept coming back and saying _Svc_Main didn't exist. I finally did by using the example scripts and putting the body of my program in a function called _Svc_Main. A few tweaks also, but it is working now.

Edited by skreien
Link to comment
Share on other sites

Sounds like you hacked it together without fully understanding how it works and how you should implement a service. This is not a simple cut and paste operation, so I hope you got it right.

Well now... how do I respond to that? Yes you're right, I am trying to build something without fully understanding how the services UDF works. I'm trying to learn it (Holy CRAP! SOMEONE ACTUALLY TRYING TO LEARN IT! WHAT WILL ALL THE EXPERIENCED PEOPLE LIKE YOU DO??) without any explanations of how it works and apparently in your case, without anyone willing to answer questions or comments about it with anything other than insults. I fully understand services and how they work, but as a newbie to running an autoit script as a service I was attempting to ask questions and learn something new. I thought that's what this forum was for.

Now, if you have anything constructive to add to the conversation like why that function is called from services.au3 when it doesn't exist, and what if anything inexperienced people are supposed to do about it, then please do. Otherwise, please shut up and give someone else a chance to post a real answer.

Can anyone post a real answer about if you're supposed to build your program body into a function called _svc_main? It doesn't say that anywhere. When I looked at the examples, I thought the name was arbitrary. That's why I posted here in the first place.

Edited by skreien
Link to comment
Share on other sites

Janxster: It seems like Arcker built the services UDF to require the script body in a function called _Svc_Main. I've confirmed mine works after doing that and uncommenting the line in services.au3, and removing most of the calls to the functions that I was doing in the body of my script since the UDF will do that for you. Since we haven't heard from Arcker or anyone else yet that this is the way it is intended to be used I'm going to assume I'm using it correctly.

Arcker: of the two examples posted, only one of them names the script body function _Svc_Main; that's what got me confused. Might want to correct that as it won't even compile. Or put a note at the top of services.au3 with an explanation of that convention. That would have saved me a few days time if I had known that. Otherwise, thanks for a very cool UDF!

Link to comment
Share on other sites

_Svc_Main() is where the startup initialization of your service is done and where the idle loop sits, and where your cleanup would be initiated when your service receives the stop command. It's not really the main meat of your service because _Svc_Main() is not where your service receives and processes messages. That happens in _Service_Ctrl() where you would communicate via custom messages (at least that is one option).

I'm all about learning. I started somewhere also. But I'm suspect when the person asking for help hasn't even bothered reading through the EXAMPLE to figure out how it works. If you had, you would have found the _Svc_Main() function and could have asked an intelligent question, instead of babbling about how you can't find it and it doesn't work. READ, UNDERSTAND, then DO.

Edited by wraithdu
Link to comment
Share on other sites

Wraithdu,

I did read the examples, I am trying to understand, and I'm trying to apply my understanding to see if it is correct. When I found it not correct, I posted a question trying to clear up my confusion. Sorry if it sounds stupid to someone that already knows how to use the services UDF, but questions often will sound stupid to an expert when a novice is trying to learn something new from zero. Answering with sarcasm and hostility like you did only serves to enforce an un-deserved elitist reputation. Not to mention making you sound like a jerk, whether you deserve it or not.

As I said previously, the two examples are not consistent with names. One of the examples doesn't even compile. How am I supposed to garner an understanding when half the examples you want me to read don't even work? Also, in the example that does work, there is no function called _Service_Ctrl.

Your post has shown me that I still need to continue working through it. Thank you for answering. Next time please just answer, or better yet, give enough of a push in the right direction that I can try and figure it out for myself.

I'm not and never have asked for anyone to code anything for me, nor am I even asking for any answers to coding questions in this case. All I asked for was just to help me gain an understanding of and properly use a UDF I've never used before. If this board can't help with that, or all it answers questions with is sarcasm, then it might as well close the doors.

Edited by skreien
Link to comment
Share on other sites

_Service_Ctrl() is in the Services.au3 file. It is one of the registered callbacks, which is why it is in that file. I can't speak for all the examples as I'm only responsible for the changes in ServiceExample.au3, and _Svc_Main() is definitely in there.

Agreed though, arcker could beef up the documentation a bit.

Link to comment
Share on other sites

wow wow wowwwwww

i retested and reposted all of the au3

I simply don't understand since i don't need to comment svc_main.

I'll recheck but it should work on the first time.

I'll update the documentation too; after cheking that.

-- 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]
Link to comment
Share on other sites

skreien & wraithdu,

Thanks for your help.

It worked ok for for me with _Svc_Main() commented, I think, because I am using the UDF just to manipulate existing Windows services. I do not have a _Svc_Main() function in my script and that would explain the error on compiling. I was unaware it was necessary. I didn't fully examine the intricate details of the example and UDF as I was in a hurry to fix 200+ machines ASAP. I will look into adding the "_Svc_Main()" into my script to use it as it is built.

The UDF is very well documented and I expeceted to see the same in the example. I figured the examples in the example were just that. For instance if you want to install your script as a service here is an example of the code to add to your script "Func InstallService()".

I am still unsure what the _Svc_Main() function does beside call the _Service_Cleanup() function when the service stops. But i do see other references in the main UDF.

Could the _Svc_Main() function be a part of the UDF?

arcker,

Thanks for your time and your time saving work and sharing it.

Edited by janxster
Link to comment
Share on other sites

Yes, some of the function from the Services.au3 UDF can be used to manipulate existing services on their own. This is NOT the point of this UDF or thread (well, not exactly). The whole point of this is to install and run your script AS A SERVICE ITSELF. If that's what you were actually trying to do, and had commented out the _Svc_Main() function, then you'd be very surprised when your service immediately stopped (the service stops when _Svc_Main() returns). Windows wouldn't have been very happy either since your didn't tell it that your service was stopping.

If you want to use some functions standalone, take them out of the UDF and put them directly in your script or in a stripped down version of the UDF.

Edited by wraithdu
Link to comment
Share on other sites

The way the services.udf is currently, if you even include services.udf in your script then _Svc_Main has to exist or your script won't compile. Even if you only use it to check for existence of a service or stop or start a service.

Link to comment
Share on other sites

  • 3 months later...
  • 2 months later...

So I've tried two implementations to get my service application to recognize a STOP when it's sent.

Basically I've plugged my application into the main_init() function from the 2nd example and my application basically runs a loop to check the status of a file and writes it to a memory location. When I use either of the implementations to detect a stop, it causes my application to not even get to the point where it checks file status.

I've tried making my loop in the main_init() function like these:

Implementation 1

Do
If _WinAPI_WaitForSingleObject($service_stop_event, 0) Then
  $forever = 1
  ExitLoop ;;goes back to _Svc_Main()
Else
  ;;my app is here
EndIf
Until $forever = 1

Implementation 2

Do
$Status = _Service_QueryStatus($sServiceName)
If $Status[1] = $SERVICE_STOP_PENDING Then
  $forever = 1
  ExitLoop ;;goes back to _Svc_Main()
Else
  ;;my app is here
EndIf
Until $forever = 1

Any ideas why this may not be working or how I should be detecting a stop sent to the service?

Edited by cvocvo
Link to comment
Share on other sites

  • 1 month later...

I just downloaded and tried to use the script, but it seems to be missing function _svc_main. Can you let me know what I might be doing wrong.

_Services_UDF : Run your script as a service v1.1

|

By Arcker.

Updated on 11/01/2010

|

Thx to ShminkyBoy, wraithdu & Udgeen for their great contributions.

Intro / History.

Hi,

Here is my last UDF.

I've taken some functions already made by SumTimWong, seen here :

OpenScManager and i've added mines.

With this UDF, you can compile your exe and run it as service.

Any comments are welcome.

Previous download for both was over 3000, that leads me to make an update.

Hope you'll like it,

Regards, Arcker

Features

- Transform your application by adding few functions to make it compatible with SCM

- Examples show you how to make GUIs and so on ( I won't be responsible for security reasons. A gui running as service will have system priviliges. )

- Event coded : not cpu consuming.

Howto.

  • Compile an example
  • Choose an appropriate location and copy the script here.
  • open a command prompt, and execute the compiled script with option –I
  • start / execute "services.msc" . You will see a service called "Autoit_service". you can execute "sc query" in a command prompt too.
  • Launch it : it will run the previous compile script. The main function will be executed after the service_init.
  • stop and relaunch the service as you wish.

Downloads

Main UDF with Constants

Note : 11/01/2010 Update by Wraithdu to work on Win7 ( Unicode optimised )

Examples demo

Provide install parameters and so on

by Spudw2k, optimised by myself to fit new code.

ServiceMenu, by ShminkyBoy

Excellent example on how to make a GUI.

Updated to 0.3 by ShminkyBoy

Synoptic

And for End Users, I've tried to explain the service control manager and the way it works with programs.

post-8413-12566401082517_thumb.jpg

Best Practice, by udgeen :

Good news! Probably i've found the working method of integrating service.au3 with other projects

I realised it after ASock.au3 project by Zatorg (please, sorry if im wrong) - ASock is asynck socket - tcp on event (uses ws2_32.dll).

Asock & sqlite didnt work together. The only reason for that was..._ArrayDisplay() func with gui!!! Ok. I made special sqlite.au3 without dependences. It works, but my udf seemed too be much havy to use at another project.

Few weeks ago i returned to service.au3 and found TCP UDF, Event driven project based on ASock.au3. It seemed to work as example, but didn't work at all as service.

In my variant of service_example.au3 i posted msdn words about service_main procedure, that it must contain all global vars of project

  • U have to combine all Globals in one place: for example at the the begining. U have to make it with other udfs too... silly work
  • Then sort Global Const and other Global statements. If u see something like global $x = 1 do that way: global $x leeve at top. $x =1 insert into module's (udf or project) Init func.
  • U have to do it even with standart udf... or use only necessary functions from it in your own include. Or... maybe u have another plan?
  • Try to build your project with modified udfs - does it works now? Hmm... But it have to Maybe later after everything will work fine i'll say "msdn is wrong, microsoft lies"... But maybe i'll say that microsoft - is not so bad, because autoit works in it FPRIVATE "TYPE=PICT;ALT=smile.gif"
I'll try to post that project as an another service_example.au3 in some weeks here. If it will works.

Some advice: use SysInternals Process Explorer (free gui based), or kill.exe from support tools to stop suspended service process. U can start-stop service even net start/net stop commands. Use file logging while debuging. No need to install-uninstall service after every recompilation: only stop, recompile, start. See, if it was suspended (while stopping) - kill process. The only reason not to stop service correctly i've found for today is unclean exit: opened sockets, maybe some dlls.

FAQ.

Hey, I've got error 1063 or error 0, what does that mean ?

It simply means that you intend to run your script in scite or directly by executing it.

Your script has to be installed as service and run from it. Several ways to do it :

  • net start "yourservicename"
  • Services.msc
  • Use API provided _Service_start, Service_stop.
I want to make a GUI !

That's your choice. You have to consider Udgeen best practice and my advice.

Example by shminkyBoy provide a gui, but it's a proof of concept to prove that gui works.

I REALLY DON'T RECOMMEND to make a gui SINCE it will be run as a Service with SYSTEM privileges

The only GUIs I did was for install progression, without any interactivity. Ban all functions that include files management.

I've to let the main function that way ? That's contraignant.

Hey, a script intended to run as service is special no ? Autoit is not C++. The only way to have a "Main" in autoit is to have a function.

If you find another way, please share it.

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