如何杀死使用Process.Start启动后PID发生变化的派生进程?
现象原因
- 以Windows 10及以上版本的计算器为例:系统自带的
calc.exe本质是代理启动程序,本身不承担计算器的运行逻辑。你调用Process.Start("calc.exe")拿到的进程ID是这个代理程序的PID,代理程序完成UWP版计算器CalculatorApp.exe的唤起操作后就会自动退出,所以你后续看到的运行中计算器的PID和你拿到的ID不一致,调用已经退出的进程的Kill()方法自然会报错。 - 你提到的打开a.txt、Word文档等关联启动场景同理:
Process.Start("目标文件路径")实际启动的是系统Shell关联进程,这个进程只负责调用对应后缀的默认打开程序(记事本、Word等),启动完成后Shell进程就会退出,你拿到的是这个已退出进程的对象,自然无法控制实际打开文件的程序。
解决方法
根据你的使用场景可以选择以下方案:
- 如果你明确知道要启动的程序的完整绝对路径,直接启动该主程序即可,不需要走关联启动逻辑,这种情况拿到的Process对象就是实际运行的程序,可以直接调用
Kill()方法。示例:
// 直接启动记事本主程序,而不是打开txt文件走关联启动 Process p = Process.Start(@"C:\Windows\System32\notepad.exe", @"C:\test\a.txt"); Thread.Sleep(3000); p.Kill();
- 如果是必须走关联启动的场景(比如不知道用户默认打开程序路径的情况),可以通过启动前后对比同程序名的PID列表,找到新增的目标进程:
// 示例:关联打开txt文件,找到实际启动的记事本进程 // 启动前记录所有已存在的记事本进程ID HashSet<int> existedPids = new HashSet<int>(Process.GetProcessesByName("notepad").Select(proc => proc.Id)); // 走关联启动打开txt文件 Process.Start(@"C:\test\a.txt"); // 等待程序启动完成,可根据程序启动速度调整等待时长 Thread.Sleep(1000); // 匹配新增的进程 Process targetProc = Process.GetProcessesByName("notepad").FirstOrDefault(proc => !existedPids.Contains(proc.Id)); if (targetProc != null) { Console.WriteLine($"实际启动的进程ID:{targetProc.Id}"); // 后续需要杀死进程时调用即可 // Thread.Sleep(3000); // targetProc.Kill(); }
注意事项
部分软件(如Office系列)默认采用单实例多文档的运行逻辑,新打开文件时会复用已存在的进程,不会生成新的PID,这种场景下无法通过杀死进程的方式单独关闭你打开的文档,需要调用对应软件的官方COM接口操作文档关闭。
内容的提问来源于stack exchange,提问作者chouette jeffrey
相关产品推荐
相关产品推荐

