在C#中,如何可靠地终止进程树

5
在C#中,我们使用以下代码来终止进程树。有时它能够工作,有时可能无法工作,可能与Windows 7和/或64位有关。
它查找给定进程的子进程的方式是通过调用GetProcesses获取系统中的所有进程,然后调用NtQueryInformationProcess查找每个父进程为给定进程的进程。它以递归方式执行此操作,以遍历整个树。
在线文档说不应该使用NtQueryInformationProcess。相反,有一种称为EnumProcesses的东西,但我找不到任何C#示例,只有其他语言。
有什么可靠的方法可以在C#中终止进程树?
    public static void TerminateProcessTree(Process process)
    {
        IntPtr processHandle = process.Handle;
        uint processId = (uint)process.Id;

        // Retrieve all processes on the system
        Process[] processes = Process.GetProcesses();
        foreach (Process proc in processes)
        {
            // Get some basic information about the process
            PROCESS_BASIC_INFORMATION procInfo = new PROCESS_BASIC_INFORMATION();
            try
            {
                uint bytesWritten;
                Win32Api.NtQueryInformationProcess(proc.Handle, 0, ref procInfo,
                    (uint)Marshal.SizeOf(procInfo), out bytesWritten); // == 0 is OK

                // Is it a child process of the process we're trying to terminate?
                if (procInfo.InheritedFromUniqueProcessId == processId)
                {
                    // Terminate the child process (and its child processes)
                    // by calling this method recursively
                    TerminateProcessTree(proc);
                }
            }
            catch (Exception /* ex */)
            {
                // Ignore, most likely 'Access Denied'
            }
        }

        // Finally, terminate the process itself:
        if (!process.HasExited)
        {
            try
            {
                process.Kill();
            }
            catch { }
        }
    }

1
在Windows上使用C++执行“Kill Process Tree”的等效操作(显然您已经知道如何P/Invoke) - Cody Gray
你的问题归结为“如何找到所有子进程”。杀死它们是这个问题的一个简单扩展。因此,这是一个重复的问题。 - usr
@usr:感谢您的标记。我仍在尝试弄清楚要使用哪个using语句。 - Mike Dunlavey
@MikeDunlavey 不确定你的意思。听起来像是一个简单的研究任务,无论它是什么。如果你做不到,就提出一个新问题吧。 - usr
哦,如果我们要将此问题作为重复关闭,我链接的那个问题是一个更好的选择。但是我特意没有投票关闭,因为它不是任何一个问题的完全重复。首先,它使用了一种不同的语言。即使翻译代码很简单,它也不是重复的。(Mike,我不知道你所说的“using”语句是什么意思。这是你无助迷失的方式吗?如果你完全不了解.NET,你可能需要提一下。我根据你的声望做出了一些假设。;-)) - Cody Gray
@Cody:声望更多是关于在网站上花费的时间和一般的忙碌程度。我对 .Net 还是比较新手。 - Mike Dunlavey
1个回答

9
使用ManagementObjectSearcher和一点递归:
private static void KillProcessAndChildren(int pid)
{
    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.
    }
 }

请原谅我的天真,但我尝试了using System.Management;,但似乎没有给我访问权限。我一定是漏了什么。 - Mike Dunlavey
2
你是否添加了对 System.Management.dll 的引用? - Yuval Itzchakov
1
做到了。感谢您帮我解决问题。 - Mike Dunlavey
1
你不想先结束父进程以避免它重新启动进程吗? - Austin Salgat
这就是 Process.Kill(bool) 的实现方式:https://github.com/dotnet/runtime/blob/2f6f3c55e4c230ac9134abeaef494c17c01c97f7/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.Win32.cs#L386 (该方法是在此问题提出后新增的。) - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接