How to create a Child process depending on it's Parent?
Asked Answered
S

3

9

My application (main.exe) is executing a Child process (child.exe) using ShellExecuteEx.

But when I close or kill (via Process-Explorer) main.exe the child process remains active.

How to gracefully handle that, when main.exe terminates child.exe terminates also?

Sero answered 11/1, 2012 at 15:43 Comment(3)
Get the main executable to send a message to the child executable when the main executable closes.Abradant
not when then main executable gets killedSero
Jobs appears to be a graceful solution. Also, you can inherit parent process handle and wait for it be be signaled upon termination.Newcomer
H
15

You need to use jobs. Main executable should create a job object, then you'll need to set JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE flag to your job object.

uses
  JobsApi;
//...
var
  jLimit: TJobObjectExtendedLimitInformation;

  hJob := CreateJobObject(nil, PChar('JobName');
  if hJob <> 0 then
  begin
    jLimit.BasicLimitInformation.LimitFlags := JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
      SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, @jLimit,
        SizeOf(TJobObjectExtendedLimitInformation));
  end; 

Then you need to execute another process with CreateProcess function where dwCreationFlags must be set to CREATE_BREAKAWAY_FROM_JOB. If this function succeeds call AssignProcessToJobObject.

function ExecuteProcess(const EXE : String; const AParams: string = ''; AJob: Boolean = True): THandle;
var
  SI : TStartupInfo;
  PI : TProcessInformation;
  AFlag: Cardinal;
begin
  Result := INVALID_HANDLE_VALUE;
  FillChar(SI,SizeOf(SI),0);
  SI.cb := SizeOf(SI);

  if AJob then
    AFlag := CREATE_BREAKAWAY_FROM_JOB
  else
    AFlag := 0;


  if CreateProcess(
     nil,
     PChar(EXE + ' ' + AParams),
     nil,
     nil,
     False,
     AFlag,
     nil,
     nil,
     SI,
     PI
     ) then
  begin
   { close thread handle }
    CloseHandle(PI.hThread);
    Result := PI.hProcess;
  end;
end;
//...
  hApp := ExecuteProcess('PathToExecutable');

  if hApp <> INVALID_HANDLE_VALUE then
  begin
     AssignProcessToJobObject(hJob, hApp);
  end;

When all of this done all the child processes will be automatically terminated even if the main executable has been killed. You can get the JobsApi unit here. Note: I've not tested it with Delphi 7.

EDIT: Here you can download working demo project.

Heterogony answered 11/1, 2012 at 16:15 Comment(8)
I have tested your code. I used the CreateJobObject on my Form create. added a Button for ExecuteProcess. the child process runs ok, AssignProcessToJobObject returns True. but when I close my parent application the child process remains alive.Sero
@zigi70 Probably you are doing something wrong. We are using this technique successfully in our multi-modular software. I've edited my answer and included my working demo project source code link.Heterogony
I have uploaded my project here. would you be so kind to take a look.Sero
Tested your project with D7/Delphi 2009. running on XP SP3. same result... notepad.exe remains. (at first I thought it was the full path issue which I did not provide in my application)Sero
@zigi70 I'm compiling it with Delphi XE and it works OK on both XP and Windows 7. As I've said I've not tested it with different Delphi versions but I cannot imagine why it doesn't work in your scenario.Heterogony
@zigi70 I've downloaded your project and when I close the main application child process terminates (same if I kill the main process). What else are you expecting to see?Heterogony
you wont believe if I tell you what causing this: Process Explorer . is the one to blame! :-PSero
@Heterogony Links don't work any more. Please put them up again or add them here.Lacefield
P
3

Try using Job Objects , check these functions CreateJobObject and AssignProcessToJobObject.

A job object allows groups of processes to be managed as a unit. Job objects are namable, securable, shareable objects that control attributes of the processes associated with them. Operations performed on a job object affect all processes associated with the job object. Examples include enforcing limits such as working set size and process priority or terminating all processes associated with a job.

Pompey answered 11/1, 2012 at 16:4 Comment(0)
R
0

I think, it's very cool code. It's working for me, but I add some changes to be able user to set show window flags for child processes like SW_SHOW/SW_HIDE.

...

function ExecuteProcess(const EXE : String; const AParams: string = '';
  const nCmdShow: Integer = SW_SHOW; AJob: Boolean = True): THandle;
var
  SI : TStartupInfo;
  PI : TProcessInformation;
  AFlag: Cardinal;
begin
  Result := INVALID_HANDLE_VALUE;
  FillChar(SI,SizeOf(SI),0);
  SI.cb := SizeOf(SI);
  SI.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  SI.wShowWindow := nCmdShow;

  if AJob then
    AFlag := CREATE_BREAKAWAY_FROM_JOB
  else
    AFlag := 0;

...

Recipience answered 19/1, 2012 at 11:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.