在 C# 中以编程方式杀死进程树
Posted
技术标签:
【中文标题】在 C# 中以编程方式杀死进程树【英文标题】:Kill process tree programmatically in C# 【发布时间】:2011-08-19 14:09:31 【问题描述】:我正在使用如下所示的代码以编程方式启动 Internet Explorer:
ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
这会生成 2 个在 Windows 任务管理器中可见的进程。然后,我尝试终止进程:
ieProcess.Kill();
这会导致任务管理器中的一个进程被关闭,而另一个则保留。我尝试检查任何具有子进程的属性,但没有找到。我怎样才能杀死另一个进程呢?更一般地说,如何杀死与使用 Process.Start 启动的进程相关联的所有进程?
【问题讨论】:
也许我遗漏了什么,但这怎么会启动两个进程? @Etienne 我不知道,我也是这么想的。但是当我正常启动 IE 时,它也会启动 2 个进程。我不知道这是否值得注意,但我在 64 位机器上使用 32 位 IE。 @Etienne de Martel:IE 的 UI 使用了多个进程,基本上每个打开的选项卡有 1 个主进程 + 1 个子进程。 @0xA3 有趣的是,我认为它只是像 Firefox 一样工作,只有一个进程和一堆不断挂起的线程。 感谢您修改了 sn-p/class 【参考方案1】:这对我来说效果很好:
/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
private static void KillProcessAndChildren(int pid)
// Cannot close 'system idle process'.
if (pid == 0)
return;
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection moc = searcher.Get();
foreach (ManagementObject mo in moc)
KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
try
Process proc = Process.GetProcessById(pid);
proc.Kill();
catch (ArgumentException)
// Process already exited.
2016 年 4 月 26 日更新
在Visual Studio 2015 Update 2
上测试Win7 x64
。现在仍然和 3 年前一样有效。
2017 年 11 月 14 日更新
增加了对系统空闲进程if (pid == 0)
的检查
2018-03-02 更新
需要添加对System.Management
命名空间的引用,请参阅下面@MinimalTech 的评论。如果您安装了 ReSharper,它会自动为您执行此操作。
2018 年 10 月 10 日更新
最常见的用例是杀死我们自己的 C# 进程已启动的所有子进程。
在这种情况下,更好的解决方案是在 C# 中使用 Win32 调用来使任何派生进程成为子进程。这意味着当父进程退出时,任何子进程都会被 Windows 自动关闭,这样就不需要上面的代码了。如果您希望我发布代码,请告诉我。
【讨论】:
孙辈呢?我认为这应该是一种递归方法。 @kerem erm 我认为是 如果E_ACCESSDENIED
同时列出进程怎么办?
你太棒了!!使用 .NET 4.0 和 VS2010 像魅力一样工作。只是为了提醒不知道的人(比如我),您必须使用 System.Management 命名空间。但是为了能够使用它,您必须转到您的项目名称 -> 右键单击它 -> 添加引用 -> .NET -> 并选择 System.Management 程序集作为@Femaref 在此处注意:***.com/questions/3692384/…
请注意,Windows 会重用进程 ID。如果一个进程产生子进程并退出而让其子进程运行,然后您的进程重用原始进程的 id,那么它似乎有更多的子进程。然后,上述方法也将尝试杀死这些(它可能有也可能没有权限)。一种解决方案是添加对进程启动时间的检查,并确认它是在树中要被杀死的根进程之后。【参考方案2】:
如果有人需要 dotnet 核心解决方案,
Dotnet 核心 3.0
process.Kill(true);
见official documentation
Dotnet 核心 2.0
对于 .Net 2.0,dotnet cli 提出了一个基于上述 taskill 的实现以及用于基于 unix 的系统的递归 pgrep/kill . Full implementation can be found on github。遗憾的是,该类是内部的,因此您必须将其复制到您的代码库中。
列出子进程(必须递归完成):
$"pgrep -P parentId"
杀死进程:
$"kill -TERM processId"
【讨论】:
恕我直言,这应该是公认的答案,因为 dot net 也可以在 linux 上运行。 Dotnet core 2.0 的这个实现救了我的命哈哈【参考方案3】:我不喜欢这里介绍的任何解决方案。
这是我的想法:
private static void EndProcessTree(string imageName)
Process.Start(new ProcessStartInfo
FileName = "taskkill",
Arguments = $"/im imageName /f /t",
CreateNoWindow = true,
UseShellExecute = false
).WaitForExit();
使用方法:
EndProcessTree("chrome.exe");
Process Class (System.Diagnostics)
ProcessStartInfo Class (System.Diagnostics)
Taskkill
【讨论】:
从编译自动化程序的经验来看,这在多个进程并行运行的生产环境中是非常危险的。简单示例:尝试杀死 explorer.exe 或 cmd.exe。很大一部分用户环境将消失。 这根本不起作用。 Process.GetProcessByName() 返回的信息在那里,但调用它并没有失败,只是没有做任何事情。 您的代码已被复制并粘贴。像你一样通过 chrome.exe。不要认为 taskkill 是一个标准的 windows 实用程序,并没有在我的 windows 10 机器上触发。【参考方案4】:您应该调用Process.CloseMainWindow()
,它将向进程的主窗口发送一条消息。把它想象成让用户点击“X”关闭按钮或文件 | 退出菜单项。
向 Internet Explorer 发送消息以关闭它自己比去杀死它的所有进程更安全。这些进程可能正在做任何事情,您需要让 IE 做它的事情并完成,然后在做一些对未来运行可能很重要的事情中杀死它。这适用于你杀死的任何程序。
【讨论】:
我认为这是首选方式...对于具有 UI 的进程。 问题是Process.CloseMainWindow()
和Process.Close()
并不总是有效。【参考方案5】:
如果有人感兴趣,我从另一页中提取了一个答案并稍作修改。它现在是一个带有静态方法的自包含类。它确实没有有适当的错误处理或日志记录。修改以用于您自己的需要。将您的根进程提供给 KillProcessTree 即可。
class ProcessUtilities
public static void KillProcessTree(Process root)
if (root != null)
var list = new List<Process>();
GetProcessAndChildren(Process.GetProcesses(), root, list, 1);
foreach (Process p in list)
try
p.Kill();
catch (Exception ex)
//Log error?
private static int GetParentProcessId(Process p)
int parentId = 0;
try
ManagementObject mo = new ManagementObject("win32_process.handle='" + p.Id + "'");
mo.Get();
parentId = Convert.ToInt32(mo["ParentProcessId"]);
catch (Exception ex)
Console.WriteLine(ex.ToString());
parentId = 0;
return parentId;
private static void GetProcessAndChildren(Process[] plist, Process parent, List<Process> output, int indent)
foreach (Process p in plist)
if (GetParentProcessId(p) == parent.Id)
GetProcessAndChildren(plist, p, output, indent + 1);
output.Add(parent);
【讨论】:
【参考方案6】:另一个解决方案是使用 taskill 命令。我在我的应用程序中使用下一个代码:
public static void Kill()
try
ProcessStartInfo processStartInfo = new ProcessStartInfo("taskkill", "/F /T /IM your_parent_process_to_kill.exe")
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
UseShellExecute = false,
WorkingDirectory = System.AppDomain.CurrentDomain.BaseDirectory,
RedirectStandardOutput = true,
RedirectStandardError = true
;
Process.Start(processStartInfo);
catch
【讨论】:
【参考方案7】:您使用的是 IE8 还是 IE9?由于其新的多进程架构,这绝对会启动多个进程。不管怎样,看看this other answer 获取进程树并杀死它。
【讨论】:
是的,这既回答了为什么启动 2 个进程,也回答了如何杀死进程树。不知怎的,我之前找不到这个,谢谢。 虽然,我不得不承认,我期待它会简单得多。酒吧。 @robr:如果代码有效,应该是简单的复制粘贴就不会成功。【参考方案8】:另一种非常有用的方法是使用Windows API for Job Objects。可以将进程分配给作业对象。这样一个进程的子进程会自动分配给同一个作业对象。
分配给作业对象的所有进程都可以立即终止,例如TerminateJobObject 其中:
终止当前与作业关联的所有进程。
C# example in this answer (based on this answer) 使用 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 标志,其中:
当作业的最后一个句柄关闭时,导致与作业关联的所有进程终止。
【讨论】:
【参考方案9】:在 .NET Core 3.0 中,有一个专门用于此目的的方法,即现有 Process.Kill()
方法的 new overload。 IOW,对Process
类型的变量process
执行process.Kill(true)
会杀死该进程及其所有后代。这自然是跨平台的。
【讨论】:
这是否已被验证在 Linux 上正常工作?文档 (docs.microsoft.com/en-us/dotnet/api/…) 提到了许多 Windows 细节。 在前面的评论中,我发现了这个 (developers.redhat.com/blog/2019/10/29/…)。看起来 Linux 的情况严重受损...... @0b101010 哪一部分准确地说明了 Linux 的终止进程树严重受损? 这是添加此功能的提交,显示其跨平台可用性:github.com/dotnet/runtime/commit/…(搜索 KillTree)。 我指的是 RedHat 博客文章中记录的Process
类的全部功能。【参考方案10】:
How to properly close Internet Explorer when launched from PowerShell?
以上线程中的一些人评论说这是由 Win7 中的错误引起的(因为使用其他版本的 Windows 的用户似乎不会发生这种情况)。互联网上的许多页面,包括微软的页面声称用户错误,并告诉您简单地使用 IE 对象上可用的退出方法,该方法也应该关闭所有子进程(据报道在 Win8/XP 等中也是如此)
我必须承认,就我而言,这是用户错误。我在win7中,退出方法对我不起作用的原因是编码错误。也就是说,我在声明时创建了 IE 对象,然后稍后在代码中创建另一个(附加到同一个对象)......当我意识到这个问题时,我几乎已经完成了破解父子杀死例程为我工作的工作。
由于 IE 的功能,您作为父进程生成的 processID 可以附加到您未创建的其他窗口/子进程。使用 quit,请记住,根据用户设置(例如退出时的空缓存),进程可能需要几分钟才能完成任务并关闭。
【讨论】:
【参考方案11】:根据文档
Kill 方法异步执行。调用Kill方法后,调用WaitForExit方法等待进程退出,或者查看HasExited属性判断进程是否退出。
ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
ieProcess.Kill();
ieProcess.WaitForExit();
【讨论】:
这真的解决了多线程问题吗?我上次处理这个问题已经 9 年了,所以我可能忘记了,但不确定这会解决吗? 这解决了即使在您通过调用 Kill 方法杀死进程后,如果它调用 GetProcessById 您的例程仍可能会拾取它,因为它没有等到进程退出以上是关于在 C# 中以编程方式杀死进程树的主要内容,如果未能解决你的问题,请参考以下文章