Jeśli kiedykolwiek odkryłeś BCL, zauważysz, że celowo unika się sposobów znajdowania procesu rodzicielskiego, weź na przykład:
https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/ProcessManager.cs,327
Jak widać w kodzie źródłowym, zawiera kompleksowe struktury i importowane metody natywne, które są absolutnie wystarczające do wykonania zadania. Jednak nawet jeśli uzyskasz do nich dostęp poprzez refleksję (jest to możliwe), nie znajdziesz metody, aby zrobić to bezpośrednio. Nie potrafię odpowiedzieć dlaczego, ale to zjawisko powoduje, że pytania takie jak twoje są zadawane nieco wielokrotnie; na przykład:
Jak mogę uzyskać PID procesu nadrzędnego mojej aplikacji
Ponieważ nie ma odpowiedzi wraz z kodem używającym CreateToolhelp32Snapshot w tym wątku, dodałbym go - część definicji struktur i nazw, które kradnę ze źródła referencji MS :)
Kod
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System;
public static class Toolhelp32 {
public const uint Inherit = 0x80000000;
public const uint SnapModule32 = 0x00000010;
public const uint SnapAll = SnapHeapList|SnapModule|SnapProcess|SnapThread;
public const uint SnapHeapList = 0x00000001;
public const uint SnapProcess = 0x00000002;
public const uint SnapThread = 0x00000004;
public const uint SnapModule = 0x00000008;
[DllImport("kernel32.dll")]
static extern bool CloseHandle(IntPtr handle);
[DllImport("kernel32.dll")]
static extern IntPtr CreateToolhelp32Snapshot(uint flags, int processId);
public static IEnumerable<T> TakeSnapshot<T>(uint flags, int id) where T : IEntry, new() {
using(var snap = new Snapshot(flags, id))
for(IEntry entry = new T { }; entry.TryMoveNext(snap, out entry);)
yield return (T)entry;
}
public interface IEntry {
bool TryMoveNext(Toolhelp32.Snapshot snap, out IEntry entry);
}
public struct Snapshot:IDisposable {
void IDisposable.Dispose() {
Toolhelp32.CloseHandle(m_handle);
}
public Snapshot(uint flags, int processId) {
m_handle=Toolhelp32.CreateToolhelp32Snapshot(flags, processId);
}
IntPtr m_handle;
}
}
[StructLayout(LayoutKind.Sequential)]
public struct WinProcessEntry:Toolhelp32.IEntry {
[DllImport("kernel32.dll")]
public static extern bool Process32Next(Toolhelp32.Snapshot snap, ref WinProcessEntry entry);
public bool TryMoveNext(Toolhelp32.Snapshot snap, out Toolhelp32.IEntry entry) {
var x = new WinProcessEntry { dwSize=Marshal.SizeOf(typeof(WinProcessEntry)) };
var b = Process32Next(snap, ref x);
entry=x;
return b;
}
public int dwSize;
public int cntUsage;
public int th32ProcessID;
public IntPtr th32DefaultHeapID;
public int th32ModuleID;
public int cntThreads;
public int th32ParentProcessID;
public int pcPriClassBase;
public int dwFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public String fileName;
}
public static class Extensions {
public static Process Parent(this Process p) {
var entries = Toolhelp32.TakeSnapshot<WinProcessEntry>(Toolhelp32.SnapAll, 0);
var parentid = entries.First(x => x.th32ProcessID==p.Id).th32ParentProcessID;
return Process.GetProcessById(parentid);
}
}
I możemy to wykorzystać tak jak:
Alternatywne zakończenie ...
Zgodnie z dokumentacją istnieje para metod iteracji dla każdego typu wpisów, takich jak Process32First
iProcess32Next
służą do iteracji procesów; ale stwierdziłem, że metody `xxxxFirst 'są niepotrzebne, a potem pomyślałem, dlaczego nie umieścić metody iteracji z odpowiadającym jej typem wpisu? Byłoby łatwiejsze do wdrożenia i zrozumienia (chyba tak…).
Tak samo jak Toolhelp32
z dodatkiem help , myślę, że statyczna klasa pomocnicza jest właściwa, dzięki czemu możemy mieć jasne nazwy kwalifikowane, takie jak Toolhelp32.Snapshot
lub Toolhelp32.IEntry
gdyby nie miało to tutaj znaczenia.
Po uzyskaniu procesu nadrzędnego, jeśli chcesz dalej uzyskać szczegółowe informacje, możesz łatwo rozszerzyć o to, na przykład iterować na jego modułach, a następnie dodać:
Kod - WinModuleEntry
[StructLayout(LayoutKind.Sequential)]
public struct WinModuleEntry:Toolhelp32.IEntry {
[DllImport("kernel32.dll")]
public static extern bool Module32Next(Toolhelp32.Snapshot snap, ref WinModuleEntry entry);
public bool TryMoveNext(Toolhelp32.Snapshot snap, out Toolhelp32.IEntry entry) {
var x = new WinModuleEntry { dwSize=Marshal.SizeOf(typeof(WinModuleEntry)) };
var b = Module32Next(snap, ref x);
entry=x;
return b;
}
public int dwSize;
public int th32ModuleID;
public int th32ProcessID;
public int GlblcntUsage;
public int ProccntUsage;
public IntPtr modBaseAddr;
public int modBaseSize;
public IntPtr hModule;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string moduleName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string fileName;
}
i trochę testu ...
public class TestClass {
public static void TestMethod() {
var p = Process.GetCurrentProcess().Parent();
Console.WriteLine("{0}", p.Id);
var formatter = new CustomFormatter { };
foreach(var x in Toolhelp32.TakeSnapshot<WinModuleEntry>(Toolhelp32.SnapModule, p.Id)) {
Console.WriteLine(String.Format(formatter, "{0}", x));
}
}
}
public class CustomFormatter:IFormatProvider, ICustomFormatter {
String ICustomFormatter.Format(String format, object arg, IFormatProvider formatProvider) {
var type = arg.GetType();
var fields = type.GetFields();
var q = fields.Select(x => String.Format("{0}:{1}", x.Name, x.GetValue(arg)));
return String.Format("{{{0}}}", String.Join(", ", q.ToArray()));
}
object IFormatProvider.GetFormat(Type formatType) {
return typeof(ICustomFormatter)!=formatType ? null : this;
}
}
Jeśli potrzebujesz przykładowego kodu ...