web-dev-qa-db-ja.com

アプリケーションの親プロセスのPIDを取得するにはどうすればよいですか?

私のwinformアプリケーションは別のアプリケーション(親)によって起動されます。c#を使用してアプリケーションを起動するアプリケーションのpidを決定する必要があります。

27
Salvador

WMIは、C#でこれを行う簡単な方法です。 Win32_ProcessクラスにはParentProcessIdプロパティがあります。次に例を示します。

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();
    }
}

Visual Studioから実行した場合の出力:

私はdevenvによって始められました

61
Hans Passant

Brian R. Bondyの回答、PInvoke.netの内容、およびいくつかのReflector出力を使用して、LinqPad MyExtensionsで使用するためにこれを作成しました。

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);
}
8
Mark Hurd

親アプリケーションを制御できる場合は、プロセスの起動時にPIDを子に渡すように親を変更できます。

6
Doug

CreateToolhelp32Snapshot列挙体のth32ParentProcessIDメンバーを確認してください。

これを行う方法の例については ここに私の投稿を参照してください

C#を使用しているため、DllImportsを使用する必要があります。リンクされた投稿には、必要な機能ごとにそれぞれのMSDNページがあります。各MSDNページの下部には、C#用のDllImportのコードがあります。

マネージコードを使用するより簡単な方法 コードのみもありますが、異なるアプリケーションによって複数のプロセス名が開始されている場合は機能しません。

2
Brian R. Bondy