delphi 如何根据父流程创建子流程?

kd3sttzy  于 2023-03-18  发布在  其他
关注(0)|答案(3)|浏览(156)

我的应用程序(main.exe)正在使用ShellExecuteEx执行子进程(child.exe)。
但是当我关闭或终止(通过Process-Explorer)main.exe时,子进程仍然处于活动状态。
main.exe终止child.exe也终止时,如何优雅地处理这种情况?

vulvrdjw

vulvrdjw1#

您需要使用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您可以下载工作演示项目。

eyh26e7m

eyh26e7m2#

尝试使用Job Objects,检查这些函数CreateJobObjectAssignProcessToJobObject
作业对象允许将多组进程作为一个单元进行管理。作业对象是可命名、可保护、可共享的对象,它们控制与之关联的进程的属性。在作业对象上执行的操作会影响与该作业对象关联的所有进程。示例包括强制限制(如工作集大小和进程优先级)或终止与作业关联的所有进程

p4tfgftt

p4tfgftt3#

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

...

相关问题