หากคุณเคยขุด BCL คุณจะพบว่ามีการหลีกเลี่ยงวิธีการค้นหากระบวนการหลักโดยเจตนาให้ใช้ตัวอย่างนี้:
https://referencesource.microsoft.com/#System/services/monitoring/system/diagnosticts/ProcessManager.cs,327
ดังที่คุณเห็นในซอร์สโค้ดประกอบด้วยโครงสร้างที่ครอบคลุมและวิธีการดั้งเดิมที่นำเข้าซึ่งเพียงพออย่างยิ่งที่จะทำให้งานสำเร็จ อย่างไรก็ตามแม้ว่าคุณจะเข้าถึงผ่านการสะท้อนกลับ (เป็นไปได้) คุณจะไม่พบวิธีการทำโดยตรง ฉันไม่สามารถตอบได้ว่าทำไม แต่ปรากฏการณ์นี้ทำให้เกิดคำถามเช่นคุณถามซ้ำ ๆ ตัวอย่างเช่น:
ฉันจะรับ PID ของกระบวนการหลักของแอปพลิเคชันของฉันได้อย่างไร
เนื่องจากไม่มีคำตอบพร้อมกับโค้ดบางส่วนที่ใช้CreateToolhelp32Snapshotในเธรดนี้ฉันจะเพิ่ม - เป็นส่วนหนึ่งของคำจำกัดความโครงสร้างและชื่อที่ฉันขโมยมาจากแหล่งอ้างอิงของ MS :)
รหัส
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);
}
}
และเราสามารถใช้มันเช่น:
สำหรับทางเลือกตอนจบ ..
ตามเอกสารนี้มีวิธีการวนซ้ำสองวิธีต่อประเภทของรายการเช่นProcess32First
และProcess32Next
สำหรับการวนซ้ำของกระบวนการ แต่ฉันพบว่าวิธีการ `` xxxxFirst 'นั้นไม่จำเป็นและฉันก็คิดว่าทำไมไม่ใส่วิธีการวนซ้ำด้วยประเภทรายการที่เกี่ยวข้อง มันจะง่ายกว่าที่จะนำไปใช้และเป็นที่เข้าใจ (ฉันเดาว่าอย่างนั้น .. )
เช่นเดียวToolhelp32
กับคำต่อท้ายด้วยความช่วยเหลือฉันคิดว่าคลาสผู้ช่วยแบบคงที่นั้นเหมาะสมดังนั้นเราจึงสามารถมีชื่อที่ตรงตามคุณสมบัติที่ชัดเจนเช่นToolhelp32.Snapshot
หรือToolhelp32.IEntry
แม้ว่าจะไม่เกี่ยวข้องที่นี่ ..
เมื่อได้รับกระบวนการหลักแล้วหากคุณต้องการรับข้อมูลรายละเอียดเพิ่มเติมคุณสามารถขยายได้อย่างง่ายดายตัวอย่างเช่นทำซ้ำในโมดูลจากนั้นเพิ่ม:
รหัส - 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;
}
และแบบทดสอบ ..
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;
}
}
ในกรณีที่ต้องการตัวอย่างโค้ด ..