Closing my program, any child commands/programs are not closed continuing to run lazarus / 21-General ---------------------------------------------------------------------- mbisax · 2023-11-16 14:53 If I execute an external process from a program, closing the program, the external process continues to live running and I have to close it manually. This  is in contrast to what I read from: https://wiki.freepascal.org/ Executing_External_Programs#Run_detached_program  ("Normally a program started by your application is a child process and is killed, when your application is killed.") An example of code that produces the same problem in Linux as in Windows:   procedure ExecProcess(Command: ansistring);   var     AProcess: TProcess;   begin     AProcess := TProcess.Create(nil);     AProcess.CommandLine := Command;     AProcess.Execute;     AProcess.Free;   end; begin   {$ifdef LINUX}     ExecProcess('mousepad');     {$else}     ExecProcess('notepad.exe');     {$endif} end; if I run in Lazarus closing the program mousepad also closes. If, however, I run it directly in a Linux console or in Windows (either in Lazarus or directly) mousepad/notepad does not close. Am I missing something, is this normal or a malfunction? Thank you in advance. Lazarus 2.2.6 FPC 3.2.2 ---------------------------------------------------------------------- KodeZwerg · 2023-11-16 15:20 Quote from: mbisax on November 16, 2023, 03:53:40 pm    AProcess := TProcess.Create(nil);Not tested, just a guessing, "nil" would not bind the created process to your process. Also I can think that the local "AProcess" gets out of scope so what should the destructor call when you close app? ---------------------------------------------------------------------- Remy Lebeau · 2023-11-16 16:52 Quote from: mbisax on November 16, 2023, 03:53:40 pmhttps://wiki.freep ascal.org/Executing_External_Programs#Run_detached_program  ("Normally a program started by your application is a child process and is killed, when your application is killed.") I don't know about Linux, but processes on Windows do not work that way by default.  A spawned process runs independently of its parent process by default.  If you want a spawned process to terminate when the parent process terminates, you have to take extra steps to set that up, namely to create a Job object, configure the Job to terminate all processes when the Job is closed, and then assign both parent and child processes to that Job.  When the parent process is closed/terminated and closes its handle to the Job, the child process will also be terminated. See Destroying all child processes (and grandchildren) when the parent exits. Quote from: KodeZwerg on November 16, 2023, 04:20:34 pmQuote from: mbisax on November 16, 2023, 03:53:40 pm    AProcess := TProcess.Create(nil);Not tested, just a guessing, "nil" would not bind the created process to your process. TProcess is a TComponent descendant.  The nil in that statement is just for the component memory ownership.  It has nothing to do with the spawned process itself. ---------------------------------------------------------------------- mbisax · 2023-11-16 17:10 Quote from: KodeZwerg on November 16, 2023, 04:20:34 pmQuote from: mbisax on November 16, 2023, 03:53:40 pm    AProcess := TProcess.Create(nil);Not tested, just a guessing, "nil" would not bind the created process to your process. Also I can think that the local "AProcess" gets out of scope so what should the destructor call when you close app? I also tried to pass the owner but the result was the same. Changing the function: procedure ExecProcess(FatherOwner: TComponent; Command: ansistring); AProcess := TProcess.Create(AOwner:TComponent); and calling with: ExecProcess(self, 'mousepad'); But, same result. ---------------------------------------------------------------------- Remy Lebeau · 2023-11-16 18:05 Quote from: mbisax on November 16, 2023, 06:10:26 pmI also tried to pass the owner but the result was the same. Of course, because ownership of the TProcess object in memory has nothing to do with ownership of the spawned process it creates. ---------------------------------------------------------------------- mbisax · 2023-11-16 20:07 Quote from: Remy Lebeau on November 16, 2023, 07:05:40 pmQuote from: mbisax on November 16, 2023, 06:10:26 pmI also tried to pass the owner but the result was the same. Of course, because ownership of the TProcess object in memory has nothing to do with ownership of the spawned process it creates. Right, but in the many tests I did I also had to try this possibility. I believe that, if in the Close event, I put a Free of the process, previously saved in a variable, I could close the child process but it would not solve the problem in the case that the program closes due to an exception type error. In this case the program would not pass through the Close event and the child processes would remain running ---------------------------------------------------------------------- KodeZwerg · 2023-11-16 20:16 Beside the correct way that Remy told, here is another approach: 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 unit Unit1; {$mode Delphi} {$IF Defined(WIN32) or Defined(WIN64) or Defined(MSWindows)}  {$DEFINE Windows} { We are on Windows }{$IFEND Windows} interface uses  {$IF Defined(Windows)}  Windows,  {$IFEND Windows}  Process,  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type   { TForm1 }   TForm1 = class(TForm)    Button1: TButton;    procedure Button1Click(Sender: TObject);    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);  private    FPID: DWORD;  public  end; var  Form1: TForm1; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);var  AProcess: TProcess;begin  AProcess := TProcess.Create(nil);  try    AProcess.Executable := 'notepad.exe';    AProcess.InheritHandles := False;    AProcess.Options := AProcess.Options + [poNoConsole, poNewProcessGroup, poDetached];    AProcess.Execute;    FPID := AProcess.ProcessID;  finally    AProcess.Free;  end;end; procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);{$IF Defined(Windows)}var  hProcess: THandle;  {$IFEND Windows}begin  {$IF Defined(Windows)}  hProcess := OpenProcess(PROCESS_TERMINATE or PROCESS_QUERY_INFORMATION, False, FPID);  if (hProcess <> 0) then    begin      TerminateProcess(hProcess, 0);      CloseHandle(hProcess);    end;  {$IFEND Windows}  CloseAction := caFree;end; end.Take care, this does not test if the Process ID belong to the process you started, it just check if there is a valid Process ID and Terminate it. ---------------------------------------------------------------------- Remy Lebeau · 2023-11-16 20:35 Quote from: KodeZwerg on November 16, 2023, 09:16:31 pmBeside the correct way that Remy told, here is another approach: That approach suffers from the problem that the child process is not terminated if the parent process crashes or is killed.  Putting both parent and child process into a Job is the only way to guarantee that. ---------------------------------------------------------------------- mbisax · 2023-11-17 08:01 Quote from: KodeZwerg on November 16, 2023, 09:16:31 pmBeside the correct way that Remy told, here is another approach: Effectively, this code close the notepad process when close, but, as say Remy and as I said, do not resolve my problem when program crash and exit with a exception.