在.NET中找到进程树

时间:2009-02-13 10:16:02

标签: c# .net windows interop

我正在寻找一种简单的方法来查找流程树(如Process Explorer之类的工具所示),使用C#或其他.NET语言。找到另一个进程的命令行参数(System.Diagnostics.Process上的StartInfo对于当前进程以外的进程似乎无效)也很有用。

我认为这些事情只能通过调用win32 api来完成,但我很高兴被证明是错误的。

4 个答案:

答案 0 :(得分:5)

如果您不想进行P / Invoke,可以使用性能计数器获取父ID:

foreach (var p in Process.GetProcesses())
{
   var performanceCounter = new PerformanceCounter("Process", "Creating Process ID", p.ProcessName);
   var parent = GetProcessIdIfStillRunning((int)performanceCounter.RawValue);
   Console.WriteLine(" Process {0}(pid {1} was started by Process {2}(Pid {3})",
              p.ProcessName, p.Id, parent.ProcessName, parent.ProcessId );
}

//Below is helper stuff to deal with exceptions from 
//looking-up no-longer existing parent processes:

struct MyProcInfo
{
    public int ProcessId;
    public string ProcessName;
}

static MyProcInfo GetProcessIdIfStillRunning(int pid)
{
    try
    {
        var p = Process.GetProcessById(pid);
        return new MyProcInfo() { ProcessId = p.Id, ProcessName = p.ProcessName };
    }
    catch (ArgumentException)
    {
        return new MyProcInfo() { ProcessId = -1, ProcessName = "No-longer existant process" };
    }
}

现在只需将它放入任何想要的树结构中,你就完成了。

答案 1 :(得分:2)

您也可以尝试查看WMI(例如Win32_Process类)。

以下是通过进程ID获取进程命令行的示例:

                using (var mos = new ManagementObjectSearcher(
                    "SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + pid))
                {
                    foreach (var obj in mos.Get())
                    {
                        object data = obj.Properties["CommandLine"].Value;
                        if (data != null)
                        {
                            Console.WriteLine("{0}: commandline = {1}", pid, data.ToString());
                        }
                    }
                }
            }
        }

我从最近写的一些代码中删除了这个。出于您的目的,您可以使用其他技术(例如一次获取多个属性和/或进程)。但是你明白了。

编辑:例如,构建树所需的父进程ID是“ParentProcessId”属性。

但我想,使用Win32 API会更快。请注意,并非所有您需要的功能都可以正确使用。对于某些东西,您可能会使用(某些)不受支持的NtQueryProcessInformation()函数或来自NTDLL的其他函数。

答案 2 :(得分:2)

我不明白为什么你不想p / invoke。如果你看一下Reflector中的System.Diagnostics,你会发现它在内部使用了p / invokes。无论如何,Process类确实有一种方法来检索进程的父PID。代替:

结构定义:

[StructLayout(LayoutKind.Sequential)]
struct PROCESS_BASIC_INFORMATION
{
    public int ExitStatus;
    public int PebBaseAddress;
    public int AffinityMask;
    public int BasePriority;
    public int UniqueProcessId;
    public int InheritedFromUniqueProcessId;
}

(简化)函数导入:

[DllImport("ntdll.dll")]
static extern int NtQueryInformationProcess(
    IntPtr ProcessHandle,
    int ProcessInformationClass,
    out PROCESS_BASIC_INFORMATION ProcessInformation,
    int ProcessInformationLength,
    out int ReturnLength
    );

代码:

Process p = Process.GetProcessById(1234);
PROCESS_BASIC_INFORMATION pbi;
int size;

NtQueryInformationProcess(p.Handle, 0, out pbi, Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), out size);
// pbi.InheritedFromUniqueProcessId now contains the process' parent PID

您需要在文件顶部插入这些用法:

using System.Runtime.InteropServices;
using System.Diagnostics;

如果你想枚举进程,你最好使用NtQuerySystemInformation - 虽然这段代码有点太长了,无法在这里发布。

答案 3 :(得分:-1)

我很确定你需要使用WinAPI。请参阅this code snippet作为示例。从对象列表及其父对象构建树是一种相当标准的算法。