// Find my own parent.
Process myProcess = Process.GetCurrentProcess();
Console.WriteLine(myProcess.ParentProcess().ProcessName);
// Create a child, and find its parent.
Process p = Process.Start("notepad.exe");
Console.WriteLine(p.ParentProcess().ProcessName);
This code displays the parent of a test program, then starts a Notepad instance and requests its parent. The resulting console looks like this (with and without a debugger):
I've seen C# implementations that read performance counters or call WMI queries to get the parent process id, but I assume that the following extension method will outperform these:
//-----------------------------------------------------------------------
// <copyright file="ProcessExtensions.cs" company="DockOfTheBay">
// http://www.dotbay.be
// </copyright>
// <summary>Defines the ProcessExtensions class.</summary>
//-----------------------------------------------------------------------
namespace DockOfTheBay
{
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
/// <summary>
/// Extension Methods for the System.Diagnostics.Process Class.
/// </summary>
public static class ProcessExtensions
{
/// <summary>
/// Returns the Parent Process of a Process
/// </summary>
/// <param name="process">The Windows Process.</param>
/// <returns>The Parent Process of the Process.</returns>
public static Process ParentProcess(this Process process)
{
int parentPid = 0;
int processPid = process.Id;
uint TH32CS_SNAPPROCESS = 2;
// Take snapshot of processes
IntPtr hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnapshot == IntPtr.Zero)
{
return null;
}
PROCESSENTRY32 procInfo = new PROCESSENTRY32();
procInfo.dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32));
// Read first
if (Process32First(hSnapshot, ref procInfo) == false)
{
return null;
}
// Loop through the snapshot
do
{
// If it's me, then ask for my parent.
if (processPid == procInfo.th32ProcessID)
{
parentPid = (int)procInfo.th32ParentProcessID;
}
}
while (parentPid == 0 && Process32Next(hSnapshot, ref procInfo)); // Read next
if (parentPid > 0)
{
return Process.GetProcessById(parentPid);
}
else
{
return null;
}
}
/// <summary>
/// Takes a snapshot of the specified processes, as well as the heaps,
/// modules, and threads used by these processes.
/// </summary>
/// <param name="dwFlags">
/// The portions of the system to be included in the snapshot.
/// </param>
/// <param name="th32ProcessID">
/// The process identifier of the process to be included in the snapshot.
/// </param>
/// <returns>
/// If the function succeeds, it returns an open handle to the specified snapshot.
/// If the function fails, it returns INVALID_HANDLE_VALUE.
/// </returns>
[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
/// <summary>
/// Retrieves information about the first process encountered in a system snapshot.
/// </summary>
/// <param name="hSnapshot">A handle to the snapshot.</param>
/// <param name="lppe">A pointer to a PROCESSENTRY32 structure.</param>
/// <returns>
/// Returns TRUE if the first entry of the process list has been copied to the buffer.
/// Returns FALSE otherwise.
/// </returns>
[DllImport("kernel32.dll")]
private static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
/// <summary>
/// Retrieves information about the next process recorded in a system snapshot.
/// </summary>
/// <param name="hSnapshot">A handle to the snapshot.</param>
/// <param name="lppe">A pointer to a PROCESSENTRY32 structure.</param>
/// <returns>
/// Returns TRUE if the next entry of the process list has been copied to the buffer.
/// Returns FALSE otherwise.</returns>
[DllImport("kernel32.dll")]
private static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
/// <summary>
/// Describes an entry from a list of the processes residing
/// in the system address space when a snapshot was taken.
/// </summary>
[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;
}
}
}
thx, great code!!
ReplyDeleteToo bad you copyrighted it
ReplyDeleteYou forgot to CloseHandle(hSnapshot)
ReplyDelete