Windows service, self stop on condition lazarus / 67-Windows ---------------------------------------------------------------------- cris75 · 2021-08-11 10:27 Hi, with the help of the wiki and this (quite old) discussion https://forum.lazarus.freepascal.org/index.php/topic,20274.0.html, I successfully wrote some windows services, and they work as expected; as a base of developing I used the approach by Udo Schmal here, https://www.gocher.me/Daemon in which he sets the FreeOnTerminate property of the thread to true when he starts the service; when the service is started, I usually check for the existence of a config file from which I retrieve a handful of settings to be used in the execution; as of today, if the config file does not exist I just don't go on and terminate the thread, but a thing I thought it was easy to do, that I've been not able to (and would like), is to "stop" (automatically) the service if this condition is met; probably I'm missing something.. if I'm not getting confused, I saw more than one time an "example" of what I'm saying, of a windows service that once started (by pressing "start" or with "net start servicename") automatically stops (for some reason, obviously), how could I reproduce this behavior? Do you think it's possible? ---------------------------------------------------------------------- cris75 · 2021-08-12 07:50 ..no reply of any kind until now to my post.. I'm wondering if my question is silly or poorly asked.. If so forgive me in advance.. ---------------------------------------------------------------------- Bart · 2021-08-12 08:30 It's a program, so you can stop it like any other program. If it's derived from TCustomApplication then Application.Terminate should do. And, of course, you could always do Halt(); You must have the OS configered not to restart this service when it stops. Bart ---------------------------------------------------------------------- cris75 · 2021-08-12 10:28 QuoteYou must have the OS configered not to restart this service when it stops I don't think the operating system will restart the service if this one is "stopped" as you would usually do via services manager or by shell command "net stop service".. but I assume maybe I don't understand what you're trying to explain me..  to be clear, this is the execute method of the thread: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TDaemonThread.Execute;var i: integer;begin  Parent.EventLog1.Info('Begin of Main thread');   i:= 0;  Application.Log(etDebug, 'Thread.Execute');  try    repeat      Sleep(1000); //milliseconds      inc(i);      Application.Log(etDebug, 'Thread.Loop ' + Format('Tick :%d', [i]));      if i = 5 then Terminate;  // this is an example condition for which the thread will be terminated    until Terminated;  // the loop will be exited because of the thread terminated  finally    Application.Log(etDebug, 'Thread.LoopStopped');  end;  { at this point how could I stop the service? }end; I suppose that to get the behavior I want, the daemon has to know about the termination of the thread and somehow "stop" itself; I use "Parent" declared in line 24 (see attached code) for EventLog, I thought "Parent.Stop" could have done it (stop the service) but i was wrong.. ---------------------------------------------------------------------- balazsszekely · 2021-08-12 11:21 You should pass GenericDaemon to DaemonThread via the constructor. Something like this(not tested): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   TGenericDaemon = class; //forward declaration   TDaemonThread = class(TThread)    Parent: TGenericDaemon;    FGenericDaemon: TGenericDaemon;  //add this    procedure SetParent(AOwner: TGenericDaemon);  protected    procedure Execute; override; //execute should be in protected section  public    constructor Create(AGenericDaemon: TGenericDaemon);   //add this                                                             destructor Destroy; override;   end; Then on constructor create, assign GenericDaemon to a local variable: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i constructor TDaemonThread.Create(AGenericDaemon: TGenericDaemon);begin  inherited Create(True);  FGenericDaemon := AGenericDaemon;end;   On Daemon start: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   //...   FThread:= TDaemonThread.Create(Self); //add this  FThread.SetParent(self);  FThread.FreeOnTerminate:= true;  FThread.Start; Finally on thread execute: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TDaemonThread.Execute;var i: integer;begin  Parent.EventLog1.Info('Begin of Main thread');   i:= 0;  Application.Log(etDebug, 'Thread.Execute');  try    repeat      Sleep(1000); //milliseconds      inc(i);      Application.Log(etDebug, 'Thread.Loop ' + Format('Tick :%d', [i]));      if i = 5 then FGenericDaemon.Stop;//add this    until Terminated;  // the loop will be exited because of the thread terminated  finally    Application.Log(etDebug, 'Thread.LoopStopped');  end;  { at this point how could I stop the service? }end; ---------------------------------------------------------------------- cris75 · 2021-08-12 12:16 Thank you. It compiles and run, but it seems it doesn't work, in windows services manager it is not shown as stopped (as I expected)  attached screenshot; btw.. I can't manually stop the service anymore, I have to kill genericdaemon.exe process to uninstall the service now.. this is the log: Code: [Select]genericdaemon [2021-08-12 13:55:58.714 Debug] DaemonMapper.Create genericdaemon [2021-08-12 13:55:58.715 Debug] DaemonMapper.Createted genericdaemon [2021-08-12 13:55:58.715 Debug] DaemonMapper.Run genericdaemon [2021-08-12 13:55:58.718 Debug] Daemon.Start: true genericdaemon [2021-08-12 13:55:58.718 Debug] Daemon.Execute: false genericdaemon [2021-08-12 13:55:58.718 Debug] Thread.Execute genericdaemon [2021-08-12 13:55:59.734 Debug] Thread.Loop Tick :1 genericdaemon [2021-08-12 13:56:00.736 Debug] Thread.Loop Tick :2 genericdaemon [2021-08-12 13:56:01.739 Debug] Thread.Loop Tick :3 genericdaemon [2021-08-12 13:56:02.749 Debug] Thread.Loop Tick :4 genericdaemon [2021-08-12 13:56:03.749 Debug] Thread.Loop Tick :5 genericdaemon [2021-08-12 13:56:03.749 Debug] Daemon.Stop: true ---------------------------------------------------------------------- balazsszekely · 2021-08-12 12:20 According to your log, the Service stopped. Please try to add: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i function TGenericDaemon.Stop: boolean;begin  result:= inherited Stop;  Application.Log(etDebug, 'Daemon.Stop: ' + BoolToStr(result));   FThread.Terminate;  FThread.WaitFor;   FThread:= nil;  FreeAndNil(EventLog1);  Application.Terminate; //<-This lineend; ---------------------------------------------------------------------- cris75 · 2021-08-12 12:30 yes, you are right, the log say so.. ..but the process is still there running.. and services manager still shows it running tried your last suggestion, no change for me  p.s. still can't manually stop it, have to kill the process ---------------------------------------------------------------------- cris75 · 2021-08-12 18:15 I double-checked everything, it seems okay, can't understand why the process doesn't close.. and why manually stopping the service hangs and return an error.. Does somebody have a clue..? ---------------------------------------------------------------------- trev · 2021-08-12 23:47 Maybe the MS service documentation helps: https://docs.microsoft.com/en-us/windows/win32/services/service- control-program-tasks ---------------------------------------------------------------------- cris75 · 2021-08-13 07:49 Thank you all for your time; thank you @trev, I'm going to give a look.. ---------------------------------------------------------------------- cris75 · 2021-08-13 10:56 @trev I checked the link, thank you ..if I understood correctly, it should be done via ServiceManager my approach was to add a private method to TGenericDaemon to connect to the service control manager and invoke the "stop" via TServiceManager method StopService I assumed that my service is certainly running at the moment of the "self-stop service" invocation, I limited to modify slightly the "IsServiceRunning" function in the Wiki for ServiceManager here https://wiki.freepascal.org/ServiceManager now it works, but was asking myself if the approach is ok and/or I did it correctly or the result is a mess of code that produces a functioning result for a matter of luck... if someone has some spare time to give a look at the code and/or review it i'd be glad, thank you all the code is attached ---------------------------------------------------------------------- trev · 2021-08-13 11:18 You're welcome. I'm glad it helped.