在 C# 中以编程方式杀死进程树
我使用如下代码以编程方式启动 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 启动的进程关联的所有进程?
I am starting Internet Explorer programmatically with code that looks like this:
ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
This generates 2 processes visible in the Windows Task Manager. Then, I attempt to kill the process with:
ieProcess.Kill();
This results in one of the processes in Task Manager being shut down, and the other remains. I tried checking for any properties that would have children processes, but found none. How can I kill the other process also? More generally, how do you kill all the processes associated with a process that you start with Process.Start?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(11)
如果有人感兴趣,我从另一页上获取了一个答案并稍作修改。它现在是一个带有静态方法的自包含类。它没有有适当的错误处理或日志记录。修改以适合您自己的需要。将你的根进程提供给 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);
}
}
另一种解决方案是使用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 { }
}
另一种非常有用的方法是使用 Windows API作业对象。一个进程可以分配给一个作业对象。此类进程的子进程会自动分配给同一作业对象。
分配给作业对象的所有进程都可以立即终止,例如使用 TerminateJobObject 其中:
终止当前与作业关联的所有进程。
此答案中的 C# 示例 (基于此答案)使用 JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 标志,其中:
当作业的最后一个句柄关闭时,导致与作业关联的所有进程终止。
对于 .NET Core 3.0,有一种方法可以实现这一点,即 现有 Process.Kill()
方法的新重载。 IOW,对 Process
类型的变量 process
执行 process.Kill(true)
会杀死该进程及其所有后代。这自然是跨平台的。
根据文档
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();
从 PowerShell 启动时如何正确关闭 Internet Explorer?< /a>
一些人在上面的帖子中评论说这是由 Win7 中的错误引起的(因为使用其他版本 Windows 的用户似乎不会发生这种情况)。互联网上的许多页面,包括微软的页面都声称用户错误,并告诉您只需使用 IE 对象上的可用退出方法,该方法也应该关闭所有子进程(据报道在 Win8/XP 等中也是如此)
我必须承认,就我而言,这是用户错误。我使用的是win7,退出方法对我不起作用的原因是编码错误。也就是说,我在声明时创建了 IE 对象,然后在代码中创建了另一个(附加到同一对象)......当我意识到这个问题时,我几乎完成了对父子杀戮例程的破解工作。
由于 IE 的功能,您作为父进程生成的 processID 可能会附加到您未创建的其他窗口/子进程。使用退出,并记住,根据用户设置(例如退出时清空缓存),进程可能需要几分钟才能完成任务并关闭。
这对我来说非常有效:
/// <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-04-26
在 Win7 x64
上的 Visual Studio 2015 Update 2
上测试。现在仍然和 3 年前一样好用。
更新 2017-11-14
添加了对系统空闲进程的检查 if (pid == 0)
更新 2018-03-02
需要添加对 System.Management
命名空间的引用,请参阅下面来自 @MinimalTech 的评论。如果您安装了 ReSharper,它将自动为您执行此操作。
更新 2018-10-10
最常见的用例是杀死我们自己的 C# 进程已启动的任何子进程。
在这种情况下,更好的解决方案是在 C# 中使用 Win32 调用使任何生成的进程成为子进程。这意味着当父进程退出时,所有子进程都会被Windows自动关闭,这样就不再需要上面的代码了。如果您希望我发布代码,请告诉我。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我不喜欢这里提出的任何解决方案。
这是我的想法:
如何使用:
I'm not a fan of any of the solutions presented here.
Here's what I came up with:
How to use: