Wenn Sie jemals die BCL ausgegraben haben, werden Sie feststellen, dass die Wege zum Auffinden des übergeordneten Prozesses absichtlich vermieden werden. Nehmen Sie zum Beispiel Folgendes:
https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/ProcessManager.cs,327
Wie Sie im Quellcode sehen können, enthält es umfassende Strukturen und importierte native Methoden, die absolut ausreichen, um die Aufgabe zu erledigen. Selbst wenn Sie über Reflektion darauf zugreifen (dies ist möglich), würden Sie keine Methode finden, um dies direkt zu tun. Ich kann nicht beantworten, warum, aber dieses Phänomen führt dazu, dass Fragen wie Ihre etwas wiederholt gestellt werden. beispielsweise:
Wie kann ich die PID des übergeordneten Prozesses meiner Anwendung ermitteln?
Da es in diesem Thread keine Antwort zusammen mit Code gibt, der CreateToolhelp32Snapshot verwendet , würde ich ihn hinzufügen - Teil der Strukturdefinitionen und Namen, die ich aus der Referenzquelle der MS stehle :)
Code
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;
//byte fileName[260];
//public const int sizeofFileName = 260;
}
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);
}
}
Und wir können es verwenden wie:
Für alternatives Ende ..
Gemäß der Dokumentation gibt es ein Paar von Iterationsmethoden pro Typ der Einträge, wie z. B. Process32First
und Process32Next
für die Iteration von Prozessen; Aber ich fand, dass die xxxxFirst-Methoden unnötig sind, und dachte dann, warum nicht die Iterationsmethode mit dem entsprechenden Eintragstyp versehen? Es wäre einfacher zu implementieren und zu verstehen (ich denke schon ..).
Genauso wie Toolhelp32
mit Hilfe angehängt , denke ich, dass eine statische Hilfsklasse richtig ist, damit wir die eindeutigen qualifizierten Namen haben können, wie Toolhelp32.Snapshot
oder Toolhelp32.IEntry
obwohl es hier irrelevant wäre.
Sobald der übergeordnete Prozess erhalten ist und Sie weitere detaillierte Informationen erhalten möchten, können Sie diese problemlos erweitern, z. B. die Module iterieren und dann Folgendes hinzufügen:
Code - WinModuleEntry
[StructLayout(LayoutKind.Sequential)]
public struct WinModuleEntry:Toolhelp32.IEntry { // MODULEENTRY32
[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;
//byte moduleName[256];
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string moduleName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string fileName;
//byte fileName[260];
//public const int sizeofModuleName = 256;
//public const int sizeofFileName = 260;
}
und einige test ..
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;
}
}
Falls Sie ein Codebeispiel wünschen ..