Rhyous

April 30, 2010

How to get the parent process that launched a C# application?

Filed under: C# (C-Sharp) — J. Abram barneck @ 9:32 am

Hey all,

I have a process that is a C# process.  I need to do something different if someone just double-clicks the application than if it is launched by a certain other process.  So I decided to check the parent process.

I couldn’t find a simple C# only method. But I did find a code snippet that works. There were actually lots of posts on that provided the following code snippet or variations thereof, so I consider it to be public domain.  So obviously I didn’t write this part.

        private static Process GetParentProcess()
        {
            int iParentPid = 0;
            int iCurrentPid = Process.GetCurrentProcess().Id;

            IntPtr oHnd = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

            if (oHnd == IntPtr.Zero)
                return null;

            PROCESSENTRY32 oProcInfo = new PROCESSENTRY32();

            oProcInfo.dwSize =
            (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(PROCESSENTRY32));

            if (Process32First(oHnd, ref oProcInfo) == false)
                return null;

            do
            {
                if (iCurrentPid == oProcInfo.th32ProcessID)
                    iParentPid = (int)oProcInfo.th32ParentProcessID;
            }
            while (iParentPid == 0 && Process32Next(oHnd, ref oProcInfo));

            if (iParentPid > 0)
                return Process.GetProcessById(iParentPid);
            else
                return null;
        }

        static uint TH32CS_SNAPPROCESS = 2;

        [StructLayout(LayoutKind.Sequential)]
        public 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;
        };

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);

        [DllImport("kernel32.dll")]
        static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);

        [DllImport("kernel32.dll")]
        static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
    }

I took this code snippet and improved upon it and made myself the following static class. This class more easily exposes:

  • Parent Process Id
  • Parent Process name
  • Parent process executable name
  • Full path to parent process executable
  • Directory name where the parent process executable resides
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Runtime.InteropServices;

namespace ParentProcess
{
    public class ParentProcess
    {
        public static String ProcessName
        {
            get { return GetParentProcess().ProcessName; }
        }

        public static int ProcessId
        {
            get { return GetParentProcess().Id; }
        }

        public static String FullPath
        {
            get
            {
                return GetParentProcess().MainModule.FileName;
            }
        }

        public static String FileName
        {
            get
            {
                return System.IO.Path.GetFileName(GetParentProcess().MainModule.FileName);
            }
        }

        public static String DirectoryName
        {
            get
            {
                return System.IO.Path.GetDirectoryName(GetParentProcess().MainModule.FileName);
            }
        }

        private static Process GetParentProcess()
        {
            int iParentPid = 0;
            int iCurrentPid = Process.GetCurrentProcess().Id;

            IntPtr oHnd = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

            if (oHnd == IntPtr.Zero)
                return null;

            PROCESSENTRY32 oProcInfo = new PROCESSENTRY32();

            oProcInfo.dwSize =
            (uint)System.Runtime.InteropServices.Marshal.SizeOf(typeof(PROCESSENTRY32));

            if (Process32First(oHnd, ref oProcInfo) == false)
                return null;

            do
            {
                if (iCurrentPid == oProcInfo.th32ProcessID)
                    iParentPid = (int)oProcInfo.th32ParentProcessID;
            }
            while (iParentPid == 0 && Process32Next(oHnd, ref oProcInfo));

            if (iParentPid > 0)
                return Process.GetProcessById(iParentPid);
            else
                return null;
        }

        static uint TH32CS_SNAPPROCESS = 2;

        [StructLayout(LayoutKind.Sequential)]
        public 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;
        };

        [DllImport("kernel32.dll", SetLastError = true)]
        static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);

        [DllImport("kernel32.dll")]
        static extern bool Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);

        [DllImport("kernel32.dll")]
        static extern bool Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
    }
}

This makes it easier for me to simply include the class above in my code and make simple calls:

String exename = ParentProcess.FileName;
String FullPathToExe = ParentProcess.FullPath;
String DirectoryInWhichExeResides= ParentProcess.DirectoryName;

…and the pid and process name, etc…

I hope this helps you.

References
http://www.facebook.com/note.php?note_id=73447531256
http://www.debugging.com/bug/6657
http://www.eggheadcafe.com/software/aspnet/35541264/how-to-get-the-parent-pro.aspx


No Copyright.

Advertisements

2 Comments »

  1. This works OK, but I wish that there were some comments for n00bies like me.

    Also, copying the text results in line numbers, which is unpleasant.

    Thanks for the code though (wish I understood it better!)

    Comment by 0xG — November 25, 2010 @ 1:48 pm | Reply

    • OxG,

      On wordpress, code is displayed with line numbers and if you copy and paste directly from the post, you get line numbers. However, when your cursor is over the code block, you get buttons on the right, two which allow for copying. One opens the code without line numbers so you can copy and paste, one is a flash tool that puts the code without line numbers into your clipboard.

      Comments are definitely in order. I’ll see what I can do.

      Comment by rhyous — November 26, 2010 @ 11:31 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: