.NETで親プロセスを取得する方法をたくさん探していましたが、P / Invokeの方法しか見つかりませんでした。
Process.GetProcessById()
は、(現在)存在しないプロセスIDのIDで呼び出しているため、親プロセスが終了した場合は機能しません。ただし、その時点で親のプロセスIDを持っているので、必要に応じて、私と同じように使用できます。
.NETで親プロセスを取得する方法をたくさん探していましたが、P / Invokeの方法しか見つかりませんでした。
Process.GetProcessById()
は、(現在)存在しないプロセスIDのIDで呼び出しているため、親プロセスが終了した場合は機能しません。ただし、その時点で親のプロセスIDを持っているので、必要に応じて、私と同じように使用できます。
回答:
このコードは、親プロセスオブジェクトを見つけるための優れたインターフェイスを提供し、同じ名前の複数のプロセスの可能性を考慮に入れています。
使用法:
Console.WriteLine("ParentPid: " + Process.GetProcessById(6972).Parent().Id);
コード:
public static class ProcessExtensions {
private static string FindIndexedProcessName(int pid) {
var processName = Process.GetProcessById(pid).ProcessName;
var processesByName = Process.GetProcessesByName(processName);
string processIndexdName = null;
for (var index = 0; index < processesByName.Length; index++) {
processIndexdName = index == 0 ? processName : processName + "#" + index;
var processId = new PerformanceCounter("Process", "ID Process", processIndexdName);
if ((int) processId.NextValue() == pid) {
return processIndexdName;
}
}
return processIndexdName;
}
private static Process FindPidFromIndexedProcessName(string indexedProcessName) {
var parentId = new PerformanceCounter("Process", "Creating Process ID", indexedProcessName);
return Process.GetProcessById((int) parentId.NextValue());
}
public static Process Parent(this Process process) {
return FindPidFromIndexedProcessName(FindIndexedProcessName(process.Id));
}
}
float.As
定義されていますか?
これが解決策です。p / invokeを使用しますが、32または64cpuでうまく機能するようです。
/// <summary>
/// A utility class to determine a process parent.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct ParentProcessUtilities
{
// These members must match PROCESS_BASIC_INFORMATION
internal IntPtr Reserved1;
internal IntPtr PebBaseAddress;
internal IntPtr Reserved2_0;
internal IntPtr Reserved2_1;
internal IntPtr UniqueProcessId;
internal IntPtr InheritedFromUniqueProcessId;
[DllImport("ntdll.dll")]
private static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, ref ParentProcessUtilities processInformation, int processInformationLength, out int returnLength);
/// <summary>
/// Gets the parent process of the current process.
/// </summary>
/// <returns>An instance of the Process class.</returns>
public static Process GetParentProcess()
{
return GetParentProcess(Process.GetCurrentProcess().Handle);
}
/// <summary>
/// Gets the parent process of specified process.
/// </summary>
/// <param name="id">The process id.</param>
/// <returns>An instance of the Process class.</returns>
public static Process GetParentProcess(int id)
{
Process process = Process.GetProcessById(id);
return GetParentProcess(process.Handle);
}
/// <summary>
/// Gets the parent process of a specified process.
/// </summary>
/// <param name="handle">The process handle.</param>
/// <returns>An instance of the Process class.</returns>
public static Process GetParentProcess(IntPtr handle)
{
ParentProcessUtilities pbi = new ParentProcessUtilities();
int returnLength;
int status = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), out returnLength);
if (status != 0)
throw new Win32Exception(status);
try
{
return Process.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());
}
catch (ArgumentException)
{
// not found
return null;
}
}
}
2600657
。この答えはチェックします:8454
。
こちらです:
public static Process GetParent(this Process process)
{
try
{
using (var query = new ManagementObjectSearcher(
"SELECT * " +
"FROM Win32_Process " +
"WHERE ProcessId=" + process.Id))
{
return query
.Get()
.OfType<ManagementObject>()
.Select(p => Process.GetProcessById((int)(uint)p["ParentProcessId"]))
.FirstOrDefault();
}
}
catch
{
return null;
}
}
これがマネージドソリューションでの私の試みです。
すべてのプロセスのパフォーマンスカウンターをポーリングし、子PIDのディクショナリを親PIDに返します。次に、現在のPIDで辞書をチェックして、親、祖父母などを確認できます。
確かに、どれだけの情報を取得するかはやり過ぎです。自由に最適化してください。
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PidExamples
{
class ParentPid
{
static void Main(string[] args)
{
var childPidToParentPid = GetAllProcessParentPids();
int currentProcessId = Process.GetCurrentProcess().Id;
Console.WriteLine("Current Process ID: " + currentProcessId);
Console.WriteLine("Parent Process ID: " + childPidToParentPid[currentProcessId]);
}
public static Dictionary<int, int> GetAllProcessParentPids()
{
var childPidToParentPid = new Dictionary<int, int>();
var processCounters = new SortedDictionary<string, PerformanceCounter[]>();
var category = new PerformanceCounterCategory("Process");
// As the base system always has more than one process running,
// don't special case a single instance return.
var instanceNames = category.GetInstanceNames();
foreach(string t in instanceNames)
{
try
{
processCounters[t] = category.GetCounters(t);
}
catch (InvalidOperationException)
{
// Transient processes may no longer exist between
// GetInstanceNames and when the counters are queried.
}
}
foreach (var kvp in processCounters)
{
int childPid = -1;
int parentPid = -1;
foreach (var counter in kvp.Value)
{
if ("ID Process".CompareTo(counter.CounterName) == 0)
{
childPid = (int)(counter.NextValue());
}
else if ("Creating Process ID".CompareTo(counter.CounterName) == 0)
{
parentPid = (int)(counter.NextValue());
}
}
if (childPid != -1 && parentPid != -1)
{
childPidToParentPid[childPid] = parentPid;
}
}
return childPidToParentPid;
}
}
}
他のニュースでは、自分のマシンにパフォーマンスカウンターがいくつあるかを知りました:13401。聖なる牛。
P / Invokeを受け入れる場合は、NtQueryInformationProcessよりも文書化されたより良い方法があります。つまり、PROCESSENTRY32(CreateToolhelp32Snapshot、Process32First、Process32Next)です。それはこの投稿に示されています。
注意して微妙な細部 親PIDは必ずしもクリエーターPIDではないことや、ノート、実際にはこれらがでコミュニティのコメントで指示出しなど、全く無関係であり PROCESSENTRY32。
BCLを掘り下げたことがあれば、親プロセスを見つける方法が意図的に回避されていることに気付くでしょう。たとえば、次のようにします。
ソースコードでわかるように、それは仕事を成し遂げるのに絶対に十分である包括的な構造とインポートされたネイティブメソッドを含んでいます。ただし、リフレクションを介してアクセスしたとしても(これは可能です)、直接アクセスする方法は見つかりません。理由は答えられませんが、この現象により、あなたのような質問が何度か繰り返されます。例えば:
アプリケーションの親プロセスの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);
}
}
そして、次のように使用できます。
テスト
public class TestClass {
public static void TestMethod() {
var p = Process.GetCurrentProcess().Parent();
Console.WriteLine("{0}", p.Id);
}
}
代替エンディングについて..
ドキュメントによれば、エントリの種類ごとに反復方法のペアが存在するようなProcess32First
、およびProcess32Next
プロセスの反復のためのものです。しかし、 `xxxxFirst 'メソッドは不要であることがわかったので、対応するエントリタイプで反復メソッドを配置してみませんか?実装して理解する方が簡単でしょう(私はそう思います..)。
同じようにToolhelp32
接尾辞助け、私は、静的なヘルパークラスは、私たちのような明確な修飾名を持つことができるように、適切だと思う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;
}
}
コード例が必要な場合..