views:

3519

answers:

3

I was looking a lot for method to get parent process in .NET, but found only P/Invoke way.

A: 

Here is managed way:

using System.Diagnostics;

var pc = new PerformanceCounter("Process",
   "Creating Process ID",
   Process.GetCurrentProcess().ProcessName);

return Process.GetProcessById((int)pc.NextValue()); 
abatishchev
Your solution may not work if there are multiple processes with the same name. See: http://csharpfeeds.com/post/1743/Retrieving_the_Parent_Process_of_a_Child_when_Multiple_Instances_Exist_Robert_Villahermosa.aspx
Michael Hale
As stated by Michael, this is a partial solution. With multiple instances off the same process, only 1 PID is returned.
Niels R.
@Niels R.: agree with no doubt
abatishchev
@romkyns: Edit to unvote? So nice
abatishchev
@abat Yes, edit to unvote. Why not? I don't want any of my co-workers to use this solution because it only seems to work - until two instances with the same name are available. Perhaps I should have downvoted, like the two others did...
romkyns
+7  A: 

This code provides a nice interface for finding the Parent process object and takes into account the possibility of multiple processes with the same name:

Usage:

Console.WriteLine("ParentPid: " + Process.GetProcessById(6972).Parent().Id);

Code:

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 (processId.NextValue().As<int>().Equals(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));
    }
}
Michael Hale
Where is the method `float.As` defined?
Mark Byers
It's coming from LiquidSyntax (http://code.google.com/p/liquidsyntax/). I thought I had removed all references to liquid syntax, but you caught one :)
Michael Hale
+4  A: 

Here is a solution. It uses p/invoke, but seems to work well, 32 or 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;
            }
        }
    }
Simon Mourier
Sweet, I'll try this out when I get a chance.
jpierson
Nice but not managed :)
abatishchev
It's actually managed, but not portable on another OS than Windows you're right. However, the notion of a parent process is not portable either, since it's not in the .NET Framework itself, so I don't think it's a big issue.
Simon Mourier