How can I get the PID of the parent process of my application

29,007

Solution 1

WMI is the easier way to do this in C#. The Win32_Process class has the ParentProcessId property. Here's an example:

using System;
using System.Management;  // <=== Add Reference required!!
using System.Diagnostics;

class Program {
    public static void Main() {
        var myId = Process.GetCurrentProcess().Id;
        var query = string.Format("SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {0}", myId);
        var search = new ManagementObjectSearcher("root\\CIMV2", query);
        var results = search.Get().GetEnumerator();
        results.MoveNext();
        var queryObj = results.Current;
        var parentId = (uint)queryObj["ParentProcessId"];
        var parent = Process.GetProcessById((int)parentId);
        Console.WriteLine("I was started by {0}", parent.ProcessName);
        Console.ReadLine();
    }
}

Output when run from Visual Studio:

I was started by devenv

Solution 2

Using Brian R. Bondy's answer as a guide, as well as what is on PInvoke.net, and some Reflector output, I have produced this, for use in LinqPad MyExtensions:

using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;

static class ProcessExtensions
{
    public static int ParentProcessId(this Process process)
    {
      return ParentProcessId(process.Id);
    }
    public static int ParentProcessId(int Id)
    {
        PROCESSENTRY32 pe32 = new PROCESSENTRY32{};
        pe32.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));
        using(var hSnapshot = CreateToolhelp32Snapshot(SnapshotFlags.Process, (uint)Id))
        {
            if(hSnapshot.IsInvalid)
                throw new Win32Exception();

            if(!Process32First(hSnapshot, ref pe32))
            {
                int errno = Marshal.GetLastWin32Error();
                if(errno == ERROR_NO_MORE_FILES)
                    return -1;
                throw new Win32Exception(errno);
            }    
            do {
                    if(pe32.th32ProcessID == (uint)Id)
                        return (int)pe32.th32ParentProcessID;
            } while(Process32Next(hSnapshot, ref pe32));
        }
        return -1;
    }
    private const int ERROR_NO_MORE_FILES = 0x12;
    [DllImport("kernel32.dll", SetLastError=true)]
    private static extern SafeSnapshotHandle CreateToolhelp32Snapshot(SnapshotFlags flags, uint id);
    [DllImport("kernel32.dll", SetLastError=true)]
    private static extern bool Process32First(SafeSnapshotHandle hSnapshot, ref PROCESSENTRY32 lppe);
    [DllImport("kernel32.dll", SetLastError=true)]
    private static extern bool Process32Next(SafeSnapshotHandle hSnapshot, ref PROCESSENTRY32 lppe);

    [Flags]
    private enum SnapshotFlags : uint
    {
        HeapList = 0x00000001,
        Process  = 0x00000002,
        Thread   = 0x00000004,
        Module   = 0x00000008,
        Module32 = 0x00000010,
        All      = (HeapList | Process | Thread | Module),
        Inherit  = 0x80000000,
        NoHeaps  = 0x40000000
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESSENTRY32 
    { 
      public uint dwSize; 
      public uint cntUsage; 
      public uint th32ProcessID; 
      public IntPtr th32DefaultHeapID; 
      public uint th32ModuleID; 
      public uint cntThreads; 
      public uint th32ParentProcessID; 
      public int pcPriClassBase; 
      public uint dwFlags; 
      [MarshalAs(UnmanagedType.ByValTStr, SizeConst=260)] public string szExeFile; 
    };
    [SuppressUnmanagedCodeSecurity, HostProtection(SecurityAction.LinkDemand, MayLeakOnAbort=true)]
    internal sealed class SafeSnapshotHandle : SafeHandleMinusOneIsInvalid
    {
        internal SafeSnapshotHandle() : base(true)
        {
        }

        [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode=true)]
        internal SafeSnapshotHandle(IntPtr handle) : base(true)
        {
            base.SetHandle(handle);
        }

        protected override bool ReleaseHandle()
        {
            return CloseHandle(base.handle);
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true, ExactSpelling=true)]
        private static extern bool CloseHandle(IntPtr handle);
    }
}

Solution 3

If you have control over the parent application, you could modify the parent to pass its PID to the child when it launches the process.

Solution 4

Check the th32ParentProcessID member of a CreateToolhelp32Snapshot enumeration.

For an example of how to do this see my post here.

Since you are using C# though you'll need to use DllImports. In the linked post there are MSDN pages for each for the functions you need. At the bottom of each MSDN page they have the code for DllImport for C#.

There is also an easier way using managed code only but it doesn't work if you have the more than one process name started by different applications.

Share:
29,007
Salvador
Author by

Salvador

Updated on July 26, 2020

Comments

  • Salvador
    Salvador almost 4 years

    My winform application is launched by another application (the parent), I need determine the pid of the application which launch my application using C#.

  • khargoosh
    khargoosh about 8 years
    Simplicity at its best. This is the answer I was looking for.
  • Adjit
    Adjit over 2 years
    Great answer! I do have one question though, why do you cast the ParentProcessId to a uint and then to an int?