C# - find parent process through P/Invoke NtQue...

C# - Find the process tree given the parent process id .
The problem with that approach is that it does not scale well because it has go through the process list repeately, however, from the internet search, we did find that we can use the P/Invoke method into the NtQueryInformationProcess. Here is information on how to use the it.

msdn - NtQueryInformationProcess 
Also, from codeproject, there is an example on how to use it (in C++ code)
codeproject - Get Process Info with NtQueryInformationProcess 

Here is the code, and I tried to add more things around the call to Format error messages if possible.

[StructLayout(LayoutKind.Sequential)]
  public struct ParentProcessUtilities
  {
    // these members must match PROCESS_BASIC_INFORMATION
    // you can find more information and example here :   http://www.codeproject.com/Articles/19685/Get-Process-Info-with-NtQueryInformationProcess
    // also, check this out:  http://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx
    internal IntPtr Reserverd1;
    internal IntPtr pebBaseAddress;
    internal IntPtr Reserved2_0;
    internal IntPtr Reserved2_1;
    internal IntPtr UniqueProcessId;
    internal IntPtr InheritedFromUniqueProcessId;

    // there is a good site that tells you how you can use the P/Invoke from  C#
    //    http://www.pinvoke.net/default.aspx/kernel32.formatmessage
    [DllImport("Kernel32.dll", SetLastError=true)]
    private static extern uint FormatMessage(
      uint dwFalgs,
      IntPtr lpSource,
      uint dwMessageId,
      uint dwLanguageId,
      ref IntPtr lpBuffer,
      uint nSize,
      IntPtr Arguments);

    // from header files
    const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
    const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
    const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
    const uint FORMAT_MESSAGE_ARGUMENT_ARRAY = 0x00002000;
    const uint FORMAT_MESSAGE_FROM_HMODULE = 0x00000800;
    const uint FORMAT_MESSAGE_FROM_STRING = 0x00000400;


    // you will need to p/invoke the NtQueryProcessInformation
    // see pinvoke.net for more information.
    //
    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(
      IntPtr processHandle,
      int processInformationClass,
      ref ParentProcessUtilities processInformation,
      int processInformationLength, out int returnLength);

    // you may use the LocalFree to free memory (usually the buffer) allocated
    // on unmanaged world
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr LocalFree(IntPtr hMem);

    // built around the p/invoke to get the parent process
    /// <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().Id);
    }

     /// <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)
     {
       // you cannot do this, because it you cannot expect the process id 
       // can automatically convert to system internal handle
       //IntPtr handle = new IntPtr(id);
       //return GetParentProcess(handle);
       // you will need to get the handle through the process class
       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)
     {
       var pbi = new ParentProcessUtilities();

       int returnLength;
       int status = NtQueryInformationProcess(handle,
                                           0,
                                           ref pbi,
                                           Marshal.SizeOf(pbi), // you cannot use the "sizeof(ParentProcessUtilities)"
                                           out returnLength);
       if (status != 0)
       {
         IntPtr lpMsgBuf = IntPtr.Zero;

         uint dwFlags = FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
            IntPtr.Zero,
            (uint) Marshal.GetLastWin32Error(), // (uint) Marshal.GetLastWin32Error(),
            0,
            ref lpMsgBuf,
            0,
            IntPtr.Zero);

         if (dwFlags == 0)
         {
           // handle the error
           int le = Marshal.GetLastWin32Error();
           throw new Win32Exception(status);
         }
         else
         {
           string sRet = Marshal.PtrToStringAnsi(lpMsgBuf);
           // free the buffer
           lpMsgBuf = LocalFree(lpMsgBuf);
           Console.WriteLine("Error : {0}", sRet);
         }
       }
       try
       {
         return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
       }
       catch (ArgumentException)
       {
         // not found
         return null;
       }
     }
Below is the code that I used to drive this piece of code.
static void Main(string[] args)
    {
      //GetProcessAndChildrenMain();
      if (args.Length < 1)
      {
        Console.WriteLine("Usage : ProcessTree <pid>");
        return;
      }
      Process process = ParentProcessUtilities.GetParentProcess(Convert.ToInt32(args[0]));
      if (process != null)
      {
        Console.WriteLine(process.Id + " " + process.MainModule.ModuleName);
      }

    }


转载于:https://my.oschina.net/u/854138/blog/90804

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值