如何创建一个Child进程取决于它的父进程?

时间:2012-01-11 15:43:47

标签: delphi delphi-7

我的应用程序( main.exe )正在使用ShellExecuteEx执行子进程( child.exe )。

但当我关闭或终止(通过Process-Explorer) main.exe 时,子进程仍然有效。

main.exe 终止 child.exe 时,如何正常处理?

3 个答案:

答案 0 :(得分:13)

您需要使用jobs。主可执行文件应为create a job object,然后您需要set JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE标记到您的作业对象。

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; 

然后,您需要使用CreateProcess函数执行另一个进程,其中dwCreationFlags必须设置为CREATE_BREAKAWAY_FROM_JOB。如果此功能成功,请致电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;

完成所有这些操作后,即使主可执行文件已被终止,所有子进程也将自动终止。您可以获得JobsApi单元here。注意:我没有使用Delphi 7进行测试。

编辑:Here您可以下载工作演示项目。

答案 1 :(得分:3)

尝试使用Job Objects,检查这些功能CreateJobObjectAssignProcessToJobObject

  

作业对象允许将进程组作为一个单元进行管理。工作   对象是可控制的,安全的,可控制的可共享对象   与它们相关的进程的属性。执行的操作   在作业对象上影响与作业对象关联的所有进程。   示例包括强制执行工作集大小和过程等限制   优先级或终止与作业关联的所有流程

答案 2 :(得分:0)

我认为,这是非常酷的代码。它对我有用,但我添加了一些更改,以便能够为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;

...