Если вы когда-либо копали 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;
//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);
}
}
И мы можем использовать его как:
Для альтернативного окончания ..
Согласно документации, для каждого типа записей существует пара итерационных методов, например Process32First
и Process32Next
для итерации процессов; но я обнаружил, что методы `xxxxFirst 'не нужны, а затем я подумал, почему бы не поместить метод итерации с соответствующим ему типом записи? Это было бы легче реализовать и понять (я так думаю ..).
Так же, как Toolhelp32
с суффиксом help , я думаю, что статический вспомогательный класс является правильным, так что мы можем иметь четкие квалифицированные имена, такие как Toolhelp32.Snapshot
или Toolhelp32.IEntry
, хотя это будет не имеет значения здесь ..
Как только родительский процесс получен, если вы хотите получить более подробную информацию, вы можете легко расширить его, например, выполнить итерации по его модулям, а затем добавить:
Код - 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;
}
и немного теста ..
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;
}
}
Если вам нужен пример кода ..