Jump to content

_Service_UDF v4 : Build your own service with autoit code


arcker
 Share

Recommended Posts

Hi,

I am using yours example for an NT Service and it works fine, but sometimes when the computer is starting up and logging on I'll get the message Error: Variable used without being declared. It is very random and not consistent.

In the _Svc_Main() section I have justed added very basic stuff.

Any help is appreciated.

I haved added this section, which shouldn't cause a problem:

Func _ReduceMemory($i_PID = -1)
    
    If $i_PID <> -1 Then
        Local $ai_Handle = DllCall("kernel32.dll", 'int', 'OpenProcess', 'int', 0x1f0fff, 'int', False, 'int', $i_PID)
        Local $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', $ai_Handle[0])
        DllCall('kernel32.dll', 'int', 'CloseHandle', 'int', $ai_Handle[0])
    Else
        Local $ai_Return = DllCall("psapi.dll", 'int', 'EmptyWorkingSet', 'long', -1)
    EndIf
    
    Return $ai_Return[0]
EndFunc;==> _ReduceMemory()

Hi,

Yes It happened to me on Winhttp async function.

The answer is that you have to open every dll you use in your script by using dllopen.

That prevents system to open dll each time. It's thread safe and I never had this problem again.

Give it a try.

PS : be very careful with emptyworkingset. From my experience, it can be really painful for the OS and can make it swap very hard.

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

Hi,

Yes It happened to me on Winhttp async function.

The answer is that you have to open every dll you use in your script by using dllopen.

That prevents system to open dll each time. It's thread safe and I never had this problem again.

Give it a try.

PS : be very careful with emptyworkingset. From my experience, it can be really painful for the OS and can make it swap very hard.

Thanks Arcker for your reply and explaination. Two questions: I have 2 dlls that I will be using and I was wondering where would be the best place to put them when I use DllOpen (they'll need to be open whenever the service is running)? Since I am using the _ReduceMemory function I see no need to close "kernel32.dll" or "psapi.dll" after I open them. The documentation says the dlls usually close upon termination of the script, though they recommend using DllClose.

Second, have you thought about incorporating a reduce memory function into your service? Just curious.

Thanks

Edited by Merrik
Link to comment
Share on other sites

@arcker

I'm using your UDF to build a service & here is code snippet

Func _Svc_Main()
    .
    .
    .
    <Do something>
    .
    .
    .
    Sleep(2000)
    _SelfRun($sServiceName,"stop")
    WEnd
    _Service_Cleanup()
EndFunc

In spite of inserting _SelfRun($sServiceName,"stop") , the service still runs where as I want the service to terminate itself after the job is done. Can you please tell me where am I making the mistake?

I do have the same question. I used

_StopService(@ComputerName, $sServiceName)

but this occassionally ended in an windows error. So I'm also looking for the proper way of how to end a service from within.

My service is actually triggering a second script. I guess I could call _StopService in the second script. But preferably I would like to end the service from within itself.

Link to comment
Share on other sites

Thanks Arcker for your reply and explaination. Two questions: I have 2 dlls that I will be using and I was wondering where would be the best place to put them when I use DllOpen (they'll need to be open whenever the service is running)? Since I am using the _ReduceMemory function I see no need to close "kernel32.dll" or "psapi.dll" after I open them. The documentation says the dlls usually close upon termination of the script, though they recommend using DllClose.

Second, have you thought about incorporating a reduce memory function into your service? Just curious.

Thanks

If you begin ot start using dll in thread safe method ( I use this word wo often but I don't know if this is the good term ), you have to, for clean code, use everydll by opening them

at start, and close them with exit function.

For your question, why do I would use reduce memory in my service ? If you use thread safe method, every dll that you open will grow your total working set, but that's normal.

I don't have to reduce my scripts or my service, or whatever in the computer. So i re-ask, why would I introduce this ?

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

I do have the same question. I used

_StopService(@ComputerName, $sServiceName)

but this occassionally ended in an windows error. So I'm also looking for the proper way of how to end a service from within.

My service is actually triggering a second script. I guess I could call _StopService in the second script. But preferably I would like to end the service from within itself.

you don't have to use this to stop your script, did you study the example ?

you have to tell to tell SCM that you want to stop, then then the stop event is called.

If you look in the service example, you can see that so stop the service :

; stoping program correctly.
    logPrint("main outer. evnt=" & _WinAPI_WaitForSingleObject_2($service_stop_event, 0))
    $counter = 20000
    Local $t1 = _Timer_SetTimer($hGUI, 500, "myStopTimer") ; sends _Service_ReportStatus($SERVICE_STOP_PENDING every timeout/10 ms like MSDN said.
    Sleep(5000) ; emulating hard working during stop
    logPrint("main stoped. Cleanup1.")
    _Timer_KillTimer($hGUI, $t1) ; no more stop pending
    logPrint("main stoped. Cleanup2.")
    Sleep(100)
    Local $x = GUIGetMsg(1) ; emulating gui close and so on
    logPrint("main stoped. Cleanup3.")
    GUIDelete($hGUI) ; emulating gui close and so on
    logPrint("main stoped. Cleanup4.")
    Sleep(100)
    _Service_ReportStatus($SERVICE_STOPPED, $NO_ERROR, 0) ; That all! Our AutoIt Service stops just there! 0 timeout meens "Now"    logPrint("main stoped. Cleanup5.") ; never executing

It is how to tell your "mom" that stops you, but that's never you that order to stop.

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

uploaded feature by HolmesShelock.

It let you detect session change within service. Can be really useful ( del locked files, maintenance operation while computer is locked, etc )

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

  • 1 month later...

Helo

First of all Thank you for your great work !

I have a question: I tried with your example codes to make my own function. All Work fine in 32 Bit Environements.

Log created: July 14, 2011 : 9:03:30 PM

_______________________________________

July 14, 2011 : 9:03:30 PM [1168] >> Service started: Sessionchange

July 14, 2011 : 9:03:46 PM [1168] >> Service stopped: Sessionchange

On 64 Bit Systems:

If i stop the service for example "net stop sessionchange" or "net stop autoit_service" on a 64Bit Computer

it kills the process - no chance to get out of the main function correctly.

I have also tried to compile the code with 64 Bit - same result.

_______________________________________

Log created: July 14, 2011 : 9:09:55 PM

_______________________________________

July 14, 2011 : 9:09:55 PM [18140] >> Service started: Sessionchange

???? Missing ????

Any Idea ?

Regards

Martin

Link to comment
Share on other sites

no idea, will try since I work on win 7 x64 now :)

edit : ok got it

I think it's more a problem between WinXP and Win7

I suppose that's your 32bit is a windows xp and not win7 32 right ?

here is the solution. Change svc_main in sessionchange.au3 with this :

Func _Svc_Main()
    WriteLog("Service started: SessionChange")
    WriteLog("main loop. evnt=" & _WinAPI_WaitForSingleObject($service_stop_event, 0))
    While $gServiceStateRunning
        Sleep(10)
    WEnd
    WriteLog("main loop. evnt=" & _WinAPI_WaitForSingleObject($service_stop_event, 0))
    _Service_Cleanup()
    WriteLog("Service stopped: SessionChange")
EndFunc
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]
Link to comment
Share on other sites

  • 2 weeks later...

Hey, vehery nice UDF Arcker! Thanks for that

Some Makros like @desktopdir arent available for a service script, neither for a service after logon, nor for a service started while being logged on already.

is there a workaround, another solution?

Link to comment
Share on other sites

@Flok3r

Well, think about it. The service is running in the SYSTEM account. How could it have an active desktop? For those specific macros to work, you would need to have a user logged in, and then have your service temporarily impersonate that user to grab the info. Much better to use non-user specific locations for log and configuration files IMO.

Link to comment
Share on other sites

Ok, impersonating as user is possible with the parameters $sServiceUser and $sPassword, but i have several problems with that:

1. These params can only be set by servicecreate func, but i need the makros for all users

2. i would need each password for all users in order to impersonate the respecting user upon logon

3. and how can i receive the currently logged in user (through registry) ?

So how can i use the makros without knowing the users pw?

A possibility to run an exe with user privileges from service would solve my problem, any way to do that without RunAs, which requires pw?

EDIT:

For anyone interested, i just found this key in the registry, didnt know about it:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI\LastLoggedOnUser

Im using Win 7, so can someone on XP please report me, if the key is available at the exact same path in XP too?

Edited by Flok3r
Link to comment
Share on other sites

  • 3 weeks later...

_Services_UDF : Run your script as a service v1.2

|

By Arcker.

Updated on 27/05/2011

|

Thx to ShminkyBoy, wraithdu, Udgeen and HolmesShelock for their great contributions.

Intro / History.

<snipped>

Arcker,

Are you considering to implement the support of the new Delayed-auto Start Type to your Services UDF?

Link to comment
Share on other sites

  • 3 weeks later...

Hello,

first I want to thank you for doing such a good work.

I would like to run the same EXE in multiple instances with different service names. As the service name is requierd for all functions in services.au3 I wanted to ask, if there is a way to find out wether a script is started as a service and which service name "belongs" to script.

Thx, gismo

Link to comment
Share on other sites

@Gismo

Maybe by using parameters ?

Service1 = cmdline => yourexe.exe /service1

Service2 = cmdline => yourexe.exe /service2

then with a simple wmi request like that :

"wmic process where name="yourexe.exe" get commandline" <= dos command, but do it in COM

, parse result, and find the process.

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

@Gismo

Maybe by using parameters ?

Service1 = cmdline => yourexe.exe /service1

Service2 = cmdline => yourexe.exe /service2

Hello arcker,

thank you for your fast reply! Using parameters is of course possible but it is not a perfect solution because the servicename and the parameter must be identical but can be different. Is there a way to get a list of all services' names and process IDs to compare them with @AutoItPID to find the parent service?

Thx! gismo

Link to comment
Share on other sites

  • 2 weeks later...

I am trying to setup dependencies for a service but depending on the dependency name size the _Service_Create function and even the _Service_SetDependencies function set the DependOnSevice Registry entry with a trash dependency appended.

For example: let say the Dependency name is "ABC".

It ends with a DependOnService Registry entry of:

"DependOnService"=hex(7):41,00,42,00,43,00,00,00,c3,c6,a1,7d,fc,00,00,80,ee,01,\

00,00,00,00

Another problem is with the _Service_QueryDependencies that retrieves the dependencies as:

Dependencies[0]=A

Dependencies[1]=B

Dependencies[2]=C

instead of:

Dependencies[0]=ABC

Printing the result of _StringToHex($sFull) in the _Service_QueryDependencies it shows:

$sFull = 4100420043000000C3C6A17DFC000080EE01000000000000

Both problems seems to be mapping problems that for the create functions I could not determine if they are a problem in this functions or in the DllStruct type functions.

Could someone help to fix this?

Thanks!

Link to comment
Share on other sites

  • 2 weeks later...
  • 2 weeks later...

The com error:

AutoIt COM error check. We intercepted a COM Error !

err.description is:

err.windescription: CoInitialize has not been called.

err.number is: 80020009

err.lastdllerror is: 0

err.scriptline is: -1

err.source is: ADODB.Connection

err.helpfile is:

err.helpcontext is: 1240640

AutoIt COM error check. We intercepted a COM Error !

err.description is:

err.windescription: CoInitialize has not been called.

err.number is: 80020009

err.lastdllerror is: 0

err.scriptline is: -1

err.source is: ADODB.Connection

err.helpfile is:

err.helpcontext is: 1240640

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