在C#中以编程方式杀死进程树

rob*_*obr 40 .net c# kill-process

我以编程方式启动Internet Explorer,代码如下所示:

ProcessStartInfo startInfo = new ProcessStartInfo("iexplore.exe");
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = "http://www.google.com";
Process ieProcess = Process.Start(startInfo);
Run Code Online (Sandbox Code Playgroud)

这将生成Windows任务管理器中可见的2个进程.然后,我尝试用以下方法终止进程:

ieProcess.Kill();
Run Code Online (Sandbox Code Playgroud)

这导致任务管理器中的一个进程被关闭,另一个进程仍然存在.我尝试检查任何具有子进程的属性,但没有找到.我怎么能杀死其他进程呢?更一般地说,如何杀死与Process.Start开始的进程相关的所有进程?

Con*_*ngo 62

这对我很有用:

/// <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.
    }
}
Run Code Online (Sandbox Code Playgroud)

更新2016-04-26

测试在Visual Studio 2015 Update 2Win7 x64.现在仍然像3年前一样有效.

更新2017-11-14

添加了系统空闲进程的检查 if (pid == 0)

更新2018-03-02

需要添加对System.Management命名空间的引用,请参阅下面@MinimalTech的注释.如果您安装了ReSharper,它将自动为您执行此操作.

更新2018-10-10

最常见的用例是杀死我们自己的C#进程已启动的所有子进程.

在这种情况下,更好的解决方案是在C#中使用Win32调用,以使任何生成的进程成为子进程.这意味着当父进程退出时,Windows会自动关闭所有子进程,从而无需使用上述代码.如果您要我发布代码,请告诉我.

  • @kerem erm我想是的 (7认同)
  • 你很棒!!像.NET 4.0和VS2010一样工作.只是要注意一些不知道的人(比如我),你必须使用System.Management命名空间.但是为了能够使用它,你必须转到你的项目名称 - >右键单击它 - >添加引用 - > .NET - >并选择System.Management程序集作为@Femaref注意它:https://stackoverflow.com /问题/ 3692384 /缺指令-或使用组件组基准-WMI的managementobjectsearcher (3认同)
  • 请注意,Windows 重复使用进程 ID。如果一个进程生成子进程并退出,使其子进程继续运行,然后您的进程重用原始进程的 id,那么它将显示为具有其他子进程。然后,上述方法将尝试杀死它们(它可能有也可能没有权限)。一种解决方案是添加对进程启动时间的检查,并确认它是在树中的根进程被杀死之后。 (2认同)

Owe*_*wen 11

我不是这里提出的任何解决方案的粉丝.

这是我想出的:

private static void EndProcessTree(string imageName)
{
    Process.Start(new ProcessStartInfo
    {
        FileName = "taskkill",
        Arguments = $"/im {imageName} /f /t",
        CreateNoWindow = true,
        UseShellExecute = false
    }).WaitForExit();
}
Run Code Online (Sandbox Code Playgroud)

如何使用:

EndProcessTree("chrome.exe");
Run Code Online (Sandbox Code Playgroud)

  • 根据编译自动化程序的经验,这在多个进程并行运行的生产环境中将非常危险。简单的例子:尝试杀死explorer.exe或cmd.exe。用户环境的很大一部分将会消失。 (3认同)

Cyp*_*ier 11

如果有人需要dotnet核心解决方案,dotnet cli会提出一个基于taskill的实现,如上所述,以及基于unix的系统的递归pgrep/kill.可以在github上找到完整的实现.遗憾的是,该类是内部的,因此您必须将其复制到您的代码库中.

列出子进程(必须递归完成):

$"pgrep -P {parentId}"
Run Code Online (Sandbox Code Playgroud)

杀死进程:

$"kill -TERM {processId}"
Run Code Online (Sandbox Code Playgroud)


小智 10

您应该调用Process.CloseMainWindow()哪个将向进程的主窗口发送消息.将其视为用户单击"X"关闭按钮或文件 | 退出菜单项.

向Internet Explorer发送消息以关闭自己更安全,而不是杀死所有进程.这些过程可能正在做任何事情,你需要让IE做它的事情并完成之前,在做一些对未来运行可能很重要的事情中杀死它.对于您杀死的任何程序都是如此.

  • 我认为这是具有UI的流程的首选方式. (5认同)

rob*_*obr 7

如果有人有兴趣,我从其他页面中获取了一个答案并稍作修改.它是一个自包含的类,现在使用静态方法.它具有适当的错误处理或记录.修改以用于您自己的需要.将您的根进程提供给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);
    }
}
Run Code Online (Sandbox Code Playgroud)


Jua*_*lez 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 { }
}
Run Code Online (Sandbox Code Playgroud)