Rowland Shaw
Rowland Shaw

Reputation: 38130

How do I discover how my process was started

We've got a winforms LOB application, which under normal circumstances should be started from a launcher that should do basic version checks and download any updated components, before spawning the main process.

One problem we're seeing is that some members of staff have found it loads faster by not running the update application, however this can lead to people not having the latest features and causes all manner of headache to support.

What I'd like to be able to do is to throw up a warning if they haven't gone in through the initialise application. Ideally, I'd like to be able to do this without having to change the update application (as that means going and installing a new MSI on each client), and the approach that springs out is to find some way of finding information about the process that started "me" and check against a white/black list, forever I can't seem to find a way to do this?


Aside: Of course, if I did resort to changing the update application, I'd probably change it to either pass a pre-shared secret as a command line argument, or better still, change the application such that I could just load it as a class library and instantiate the relevant class via reflection. ClickOnce has been ruled out as it does not support being installed for multiple users

Upvotes: 5

Views: 735

Answers (4)

Simon P Stevens
Simon P Stevens

Reputation: 27499

See here: How to get parent process in .NET in managed way

From the link:

using System.Diagnostics;
PerformanceCounter pc = new PerformanceCounter("Process",
"Creating Process ID", Process.GetCurrentProcess().ProcessName);
return Process.GetProcessById((int)pc.NextValue());

[Edit: Also see the System.Diagnostics FAQ for some more information about this. Thanks to Justin for the link.]

Upvotes: 4

Chris Marasti-Georg
Chris Marasti-Georg

Reputation: 34650

You can use PInvoke with a Kernel32 method to find the parent process and check to see if it matches your updater. Source. Code, in case it goes away:

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
static class myProcessEx
{  
    //inner enum used only internally
    [Flags]
    private enum SnapshotFlags : uint
    {
    HeapList = 0x00000001,
    Process = 0x00000002,
    Thread = 0x00000004,
    Module = 0x00000008,
    Module32 = 0x00000010,
    Inherit = 0x80000000,
    All = 0x0000001F
    }
    //inner struct used only internally
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    private struct PROCESSENTRY32
    {
    const int MAX_PATH = 260;
    internal UInt32 dwSize;
    internal UInt32 cntUsage;
    internal UInt32 th32ProcessID;
    internal IntPtr th32DefaultHeapID;
    internal UInt32 th32ModuleID;
    internal UInt32 cntThreads;
    internal UInt32 th32ParentProcessID;
    internal Int32 pcPriClassBase;
    internal UInt32 dwFlags;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
    internal string szExeFile;
    }

    [DllImport("kernel32", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    static extern IntPtr CreateToolhelp32Snapshot([In]UInt32 dwFlags, [In]UInt32 th32ProcessID);

    [DllImport("kernel32", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    static extern bool Process32First([In]IntPtr hSnapshot, ref PROCESSENTRY32 lppe);

    [DllImport("kernel32", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
    static extern bool Process32Next([In]IntPtr hSnapshot, ref PROCESSENTRY32 lppe);

    // get the parent process given a pid
    public static Process GetParentProcess(int pid)
    {

    Process parentProc = null;
    try
    {
        PROCESSENTRY32 procEntry = new PROCESSENTRY32();
        procEntry.dwSize = (UInt32)Marshal.SizeOf(typeof(PROCESSENTRY32));
        IntPtr handleToSnapshot = CreateToolhelp32Snapshot((uint)SnapshotFlags.Process, 0);
        if (Process32First(handleToSnapshot, ref procEntry))
        {
        do
        {
            if (pid == procEntry.th32ProcessID)
            {
            parentProc = Process.GetProcessById((int)procEntry.th32ParentProcessID);
            break;

            }
        } while (Process32Next(handleToSnapshot, ref procEntry));
        }
        else
        {
        throw new ApplicationException(string.Format("Failed with win32 error code {0}", Marshal.GetLastWin32Error()));
        }
    }
    catch (Exception ex)
    {
        throw new ApplicationException("Can't get the process.", ex);
    }
    return parentProc;
    }

    // get the specific parent process
    public static Process CurrentParentProcess
    {
    get
    {
        return GetParentProcess(Process.GetCurrentProcess().Id);
    }
    }

    static void Main()
    {
    Process pr = CurrentParentProcess;

    Console.WriteLine("Parent Proc. ID: {0}, Parent Proc. name: {1}", pr.Id, pr.ProcessName);
    }
}

Upvotes: 0

Treb
Treb

Reputation: 20271

First, if your staff has people smart enough to figure out that the launcher is slow and how to get around it, I bet they will find out some 'secret' command line switch, too. I would consider that approach a waste of time.

Second, I think the answer form Chris Marasti-Georg goes into the rigth direction: You have to figure out the name of the parent process, i.e. the process that launched your app. I have no specific idea on how to do this, but WMI seems like a good place to start. Edit: Simon P Stevens answered that part.

Third, I suppose you are aware of this, but I will say it anyway: Your problem is the launcher. If it is so slow that normal users find a way to get around it, it is just too slow. Your best solution is not ti fix the main app, but to fix the launcher. Edit: See Anders Karlsson's answer for a better mechanism.

Upvotes: 0

AndersK
AndersK

Reputation: 36082

I find if your process - which I assume you have control over - checks its version number vs the latest released version number (placed somewhere central db/ftp wherever u look for the update) , then you have all that logic in one place. I think that would be a simpler solution.

Upvotes: 3

Related Questions