You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何终止由CreateProcess启动的BAT文件所创建的子进程?

问题:终止由BAT脚本启动的子进程

示例代码

var
  sParams: string;
  SI: TStartupInfo;
  PI: TProcessInformation;
begin
  FillChar(SI, SizeOf(SI), #0);
  FillChar(PI, SizeOf(PI), #0);
  with SI do
  begin
    cb := SizeOf(SI);
    dwFlags := STARTF_USESHOWWINDOW;
    wShowWindow := SW_SHOW
  end;
  sParams := 'ping 127.0.0.1 -t';
  UniqueString(sParams);
  if CreateProcess(nil, PChar(sParams), nil, nil, False, 0, nil, nil, SI, PI) then
    FProcessHandle := PI.hProcess;
end;

现象说明

  • 直接启动ping命令时,调用TerminateProcess(FProcessHandle, 0)可以成功关闭控制台并终止ping进程。
  • 当修改参数为启动BAT脚本:
    sParams := 'run.bat';
    
    BAT脚本内容为:
    ping 127.0.0.1 -t
    
    此时调用TerminateProcess(FProcessHandle, 0)只能终止启动BAT的cmd.exe进程,而ping进程会继续运行。

解决方案

方法1:使用进程组(推荐,优雅终止)

通过设置进程组标志,让cmd.exe和它启动的子进程属于同一进程组,发送中断信号即可一次性终止所有关联进程。

修改后的启动代码:

var
  sParams: string;
  SI: TStartupInfo;
  PI: TProcessInformation;
begin
  FillChar(SI, SizeOf(SI), #0);
  FillChar(PI, SizeOf(PI), #0);
  with SI do
  begin
    cb := SizeOf(SI);
    dwFlags := STARTF_USESHOWWINDOW;
    wShowWindow := SW_SHOW
  end;
  // 显式调用cmd.exe执行BAT,确保能设置进程组
  sParams := 'cmd /c run.bat';
  UniqueString(sParams);
  // 启用CREATE_NEW_PROCESS_GROUP标志,创建新进程组
  if CreateProcess(nil, PChar(sParams), nil, nil, False, CREATE_NEW_PROCESS_GROUP, nil, nil, SI, PI) then
  begin
    FProcessHandle := PI.hProcess;
    // 发送CTRL_BREAK_EVENT到进程组,触发所有关联进程终止
    GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, PI.dwProcessId);
    // 等待进程完全退出后释放句柄
    WaitForSingleObject(PI.hProcess, INFINITE);
    CloseHandle(PI.hProcess);
    CloseHandle(PI.hThread);
  end;
end;

原理:CREATE_NEW_PROCESS_GROUP会让启动的cmd.exe成为进程组组长,GenerateConsoleCtrlEvent发送的中断信号会被进程组内所有进程接收,cmd.exe会自动将信号转发给子进程ping,实现整体终止。

方法2:枚举并终止子进程

如果无法修改启动逻辑,可以通过枚举系统进程,找到父进程为cmd.exe的ping进程并单独终止。

实现代码:

procedure TerminateChildProcesses(ParentPID: DWORD);
var
  hSnapshot: THandle;
  pe: TProcessEntry32;
  hProcess: THandle;
begin
  hSnapshot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  if hSnapshot = INVALID_HANDLE_VALUE then Exit;
  
  pe.dwSize := SizeOf(TProcessEntry32);
  if Process32First(hSnapshot, pe) then
  begin
    repeat
      // 筛选父进程ID匹配的子进程
      if pe.th32ParentProcessID = ParentPID then
      begin
        hProcess := OpenProcess(PROCESS_TERMINATE, False, pe.th32ProcessID);
        if hProcess <> 0 then
        begin
          TerminateProcess(hProcess, 0);
          CloseHandle(hProcess);
        end;
      end;
    until not Process32Next(hSnapshot, pe);
  end;
  
  CloseHandle(hSnapshot);
end;

// 调用方式:先终止子进程,再终止cmd进程
TerminateChildProcesses(PI.dwProcessId);
TerminateProcess(FProcessHandle, 0);

注意:此方法需要当前进程拥有足够权限终止目标进程,且枚举过程中可能存在进程已退出的情况,需做好错误处理。

内容的提问来源于stack exchange,提问作者Pit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 07:36:18