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

时间:2011-05-05 17:17:11

标签: c# .net 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);

这将在Windows任务管理器中生成2个进程。然后,我试图用以下方法终止进程:

ieProcess.Kill();

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

11 个答案:

答案 0 :(得分:57)

这对我非常有用:

/// <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

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会自动关闭所有子进程,从而无需使用上述代码。如果您希望我发布代码,请告诉我。

答案 1 :(得分:11)

我不喜欢这里提出的任何解决方案。

以下是我提出的建议:

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");

答案 2 :(得分:10)

您应该致电Process.CloseMainWindow(),它会将消息发送到流程的主窗口。可以将其视为用户单击“X”关闭按钮或文件 | 退出菜单项。

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

答案 3 :(得分: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);
    }
}

答案 4 :(得分: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 { }
}

答案 5 :(得分:6)

如果有人需要dotnet核心解决方案, dotnet cli 会提出如上所述的基于 taskill 的实现,并递归 pgrep / kill 对于基于unix的系统。 Full implementation can be found on github。遗憾的是,该课程是内部课程,因此您必须将其复制到您的代码库中。

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

$"pgrep -P {parentId}"

杀死进程:

$"kill -TERM {processId}"

答案 6 :(得分:4)

您使用的是IE8还是IE9?由于其新的多进程架构,这绝对会启动多个进程。无论如何,请查看this other answer获取进程树并将其删除。

答案 7 :(得分:2)

另一种非常有用的方法是使用develop。可以将进程分配给作业对象。这种过程的子进程会自动分配给同一个作业对象。

可以立即终止分配给作业对象的所有进程,例如与Windows API for Job Objects

  

终止当前与作业关联的所有进程。

TerminateJobObjectC# example in this answer)改为使用based on this answer标志,其中:

  

当作业的最后一个句柄关闭时,导致与作业关联的所有进程终止。

答案 8 :(得分:1)

使用.NET Core 3.0,有一种方法专门用于此目的,即已经存在的Process.Kill()方法中的new overload。 IOW对类型为process.Kill(true)的变量process进行Process会杀死该进程及其所有后代。自然,这是跨平台的。

答案 9 :(得分:0)

How to properly close Internet Explorer when launched from PowerShell?

其中一些人在上述帖子中评论说,这是由Win7中的一个错误引起的(因为对于使用其他版本的Windows的用户来说似乎不会发生这种情况)。互联网上的许多页面,包括微软的页面声称用户错误,并告诉你只需在IE对象上使用可用的退出方法,该方法也是支持关闭所有子进程(据报道在Win8 / XP等中也是如此) )

我必须承认,就我而言,它是用户错误。我在win7中,退出方法对我不起作用的原因是因为编码错误。也就是我在声明时创建IE对象,然后在代码中创建另一个(附加到同一个对象)...当我意识到这个问题时,我几乎已经完成了破坏父子查杀程序以便为我工作。

由于IE的功能如何,您作为父级生成的processID可以附加到您未创建的其他窗口/子进程。使用quit,请记住,根据用户设置(如退出时的空缓存),流程可能需要几分钟才能完成任务并关闭。

答案 10 :(得分:0)

根据文档

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();