如何以托管方式在.NET中获取父进程

aba*_*hev 80 c# pinvoke managed process parent

我正在寻找很多方法来获取.NET中的父进程,但只找到了P/Invoke方式.

Sim*_*ier 137

这是一个解决方案.它使用p/invoke,但似乎运行良好,32或64 cpu:

    /// <summary>
    /// A utility class to determine a process parent.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct ParentProcessUtilities
    {
        // These members must match PROCESS_BASIC_INFORMATION
        internal IntPtr Reserved1;
        internal IntPtr PebBaseAddress;
        internal IntPtr Reserved2_0;
        internal IntPtr Reserved2_1;
        internal IntPtr UniqueProcessId;
        internal IntPtr InheritedFromUniqueProcessId;

        [DllImport("ntdll.dll")]
        private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);

        /// <summary>
        /// Gets the parent process of the current process.
        /// </summary>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess()
        {
            return GetParentProcess(Process.GetCurrentProcess().Handle);
        }

        /// <summary>
        /// Gets the parent process of specified process.
        /// </summary>
        /// <param name="id">The process id.</param>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess(int id)
        {
            Process process = Process.GetProcessById(id);
            return GetParentProcess(process.Handle);
        }

        /// <summary>
        /// Gets the parent process of a specified process.
        /// </summary>
        /// <param name="handle">The process handle.</param>
        /// <returns>An instance of the Process class.</returns>
        public static Process GetParentProcess(IntPtr handle)
        {
            ParentProcessUtilities pbi = new ParentProcessUtilities();
            int returnLength;
            int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
            if (status != 0)
                throw new Win32Exception(status);

            try
            {
                return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
            }
            catch (ArgumentException)
            {
                // not found
                return null;
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • @ justin.m.chase - 已经存在了将近20年,所以我怀疑它将在明天被删除,并且没有任何替代的NT功能可以让我的知识进行父进程,但是,确定,使用风险由您自己承担. (19认同)
  • 它实际上是托管的,但不能在Windows上运行,而不是Windows.但是,父进程的概念也不可移植,因为它不在.NET Framework本身,所以我认为这不是一个大问题. (12认同)
  • 大!没有慢速性能计数器.我真的很讨厌"没有管理"的评论.如何使用P/Invoke更好地查询perf计数器. (9认同)
  • 不幸的是,此功能仅限内部功能 MSDN说这个"[NtQueryInformationProcess可能会在未来版本的Windows中被更改或不可用.应用程序应该使用本主题中列出的备用函数."http://msdn.microsoft.com/en-us/library/windows/desktop/ ms684280(v = vs.85)的.aspx (5认同)
  • 当我将该方法的性能与其他方法进行比较时,该方法“快至少10倍”。接受的答案打勾:“ 2600657”。这个答案打勾:“ 8454”。 (3认同)
  • 我有一个使用性能计数器来获取父ID的系统。不幸的是,当循环遍历300多个进程并创建性能计数器以获取父ID时,性能非常糟糕。我宁愿避免直接Win32 API调用,但区别是在1秒内停止了服务,而不是使用PerformanceCounter版本花费几分钟。结果,在运行大量服务的服务器上,由于性能原因,这是最适合的主要版本。 (2认同)
  • NtQueryInformationProcess返回NT状态代码,而不是Win32错误代码。所以`抛出新的Win32Exception(status)`是不合适的。 (2认同)

Mic*_*ale 57

此代码为查找父进程对象提供了一个很好的接口,并考虑了具有相同名称的多个进程的可能性:

用法:

Console.WriteLine("ParentPid: " + Process.GetProcessById(6972).Parent().Id);
Run Code Online (Sandbox Code Playgroud)

码:

public static class ProcessExtensions {
    private static string FindIndexedProcessName(int pid) {
        var processName = Process.GetProcessById(pid).ProcessName;
        var processesByName = Process.GetProcessesByName(processName);
        string processIndexdName = null;

        for (var index = 0; index < processesByName.Length; index++) {
            processIndexdName = index == 0 ? processName : processName + "#" + index;
            var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
            if ((int) processId.NextValue() == pid) {
                return processIndexdName;
            }
        }

        return processIndexdName;
    }

    private static Process FindPidFromIndexedProcessName(string indexedProcessName) {
        var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
        return Process.GetProcessById((int) parentId.NextValue());
    }

    public static Process Parent(this Process process) {
        return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这些是一些令人惊讶的命名方法. (17认同)
  • 不幸的是,当性能计数器类别名称被本地化时(例如,在非英语Windows上),它不起作用. (6认同)
  • 在我的测试中,这比Simon Mourier的解决方案要慢得多.此外,它不幸地做了某种"带来前进过程"的机制.我不知道为什么.还有其他人经历过这个吗?我正在运行的测试是由Visual Studio创建的安装引导程序EXE,它启动MSIEXEC.exe Windows安装程序. (4认同)
  • 我建议西蒙的版本除非有迫切的理由,因为性能差异很大. (4认同)
  • 方法`float.As`在哪里定义? (2认同)

小智 7

这条路:

public static Process GetParent(this Process process)
{
  try
  {
    using (var query = new ManagementObjectSearcher(
      "SELECT * " +
      "FROM Win32_Process " +
      "WHERE ProcessId=" + process.Id))
    {
      return query
        .Get()
        .OfType<ManagementObject>()
        .Select(p => Process.GetProcessById((int)(uint)p["ParentProcessId"]))
        .FirstOrDefault();
    }
  }
  catch
  {
    return null;
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 有效,但 WMI 可能会超慢(秒)。pinvoke 是要走的路。 (2认同)

Jer*_*ray 5

这是我对托管解决方案的尝试。

它轮询所有进程的性能计数器,并将子 PID 的字典返回给父 PID。然后你可以用你当前的 PID 检查字典来查看你的父母、祖父母等。

当然,它获得的信息量太大了。随意优化。

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace PidExamples
{
    class ParentPid
    {
        static void Main(string[] args)
        {
            var childPidToParentPid = GetAllProcessParentPids();
            int currentProcessId = Process.GetCurrentProcess().Id;

            Console.WriteLine("Current Process ID: " + currentProcessId);
            Console.WriteLine("Parent Process ID: " + childPidToParentPid[currentProcessId]);
        }

        public static Dictionary<int, int> GetAllProcessParentPids()
        {
            var childPidToParentPid = new Dictionary<int, int>();

            var processCounters = new SortedDictionary<string, PerformanceCounter[]>();
            var category = new PerformanceCounterCategory("Process");

            // As the base system always has more than one process running, 
            // don't special case a single instance return.
            var instanceNames = category.GetInstanceNames();
            foreach(string t in instanceNames)
            {
                try
                {
                    processCounters[t] = category.GetCounters(t);
                }
                catch (InvalidOperationException)
                {
                    // Transient processes may no longer exist between 
                    // GetInstanceNames and when the counters are queried.
                }
            }

            foreach (var kvp in processCounters)
            {
                int childPid = -1;
                int parentPid = -1;

                foreach (var counter in kvp.Value)
                {
                    if ("ID Process".CompareTo(counter.CounterName) == 0)
                    {
                        childPid = (int)(counter.NextValue());
                    }
                    else if ("Creating Process ID".CompareTo(counter.CounterName) == 0)
                    {
                        parentPid = (int)(counter.NextValue());
                    }
                }

                if (childPid != -1 && parentPid != -1)
                {
                    childPidToParentPid[childPid] = parentPid;
                }
            }

            return childPidToParentPid;
        }
    }
}    
Run Code Online (Sandbox Code Playgroud)

在其他新闻中,我了解到我的机器上有多少个性能计数器:13401。天哪。

  • 此方法有效,但似乎非常慢。在我的机器上花了 10 多秒。 (2认同)