53

我正在使用如下所示的代码以编程方式启动 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 启动的进程相关的所有进程?

4

11 回答 11

80

这对我来说非常有效:

/// <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 自动关闭,这样就不需要上面的代码了。如果您希望我发布代码,请告诉我。

于 2012-05-01T19:12:47.657 回答
29

如果有人需要 dotnet 核心解决方案,

点网核心 3.0

process.Kill(true);

官方文档

点网核心 2.0

对于 .Net 2.0 , dotnet cli提出了一个基于上述taskill的实现,以及用于基于 unix 的系统的递归pgrep/kill完整的实现可以在 github 上找到。可悲的是,该类是内部的,因此您必须将其复制到您的代码库中。

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

$"pgrep -P {parentId}"

杀死进程:

$"kill -TERM {processId}"
于 2017-08-14T04:56:55.877 回答
13

我不喜欢这里介绍的任何解决方案。

这是我想出的:

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");
于 2017-02-19T21:13:03.430 回答
10

您应该调用Process.CloseMainWindow()which 将向进程的主窗口发送消息。将其视为让用户单击“X”关闭按钮或File | 退出菜单项。

向 Internet Explorer 发送消息以关闭自身比去杀死它的所有进程更安全。这些进程可能正在做任何事情,您需要让 IE 做它的事情并完成,然后在做一些对未来运行可能很重要的事情中杀死它。这适用于您杀死的任何程序。

于 2012-11-14T10:07:11.893 回答
9

如果有人有兴趣,我从另一页中提取了一个答案并稍作修改。它现在是一个带有静态方法的自包含类。它没有适当的错误处理或日志记录。修改以用于您自己的需要。将您的根进程提供给 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);
    }
}
于 2011-05-07T15:25:31.283 回答
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 { }
}
于 2015-09-15T20:27:38.393 回答
4

你用的是IE8还是IE9?由于其新的多进程架构,这绝对会启动多个进程。无论如何,看看这个其他的答案来获取进程树并杀死它。

于 2011-05-05T17:28:36.320 回答
3

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

分配给作业对象的所有进程都可以立即终止,例如使用TerminateJobObject

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

此答案中的C# 示例基于此答案)改为使用JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE标志,其中:

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

于 2017-05-17T09:42:01.387 回答
1

在 .NET Core 3.0 中,有一种方法可以解决这个问题,即现有方法的新重载。Process.Kill()IOW,对类型process.Kill(true)变量执行操作会杀死该进程及其所有后代。这自然是跨平台的。processProcess

于 2019-09-30T22:33:20.773 回答
0

从 PowerShell 启动时如何正确关闭 Internet Explorer?

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

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

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

于 2015-11-20T19:31:28.723 回答
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();
于 2020-08-12T01:35:23.350 回答