Was passiert, wenn mehrere Instanzen Ihres Prozesses ausgeführt werden, da alle denselben Prozessnamen haben?
Michael Burr
1
Für den Fall, dass es jemand anderem hilft: Ich persönlich brauchte nur die übergeordnete Prozess-ID. Die folgenden Lösungen von Michael Hale und Simon Mourier funktionieren nicht, wenn der übergeordnete Prozess beendet wurde, da sie Process.GetProcessById()mit einer ID einer (jetzt) nicht vorhandenen Prozess-ID anrufen . Aber zu diesem Zeitpunkt haben Sie die Prozess-ID des Elternteils, sodass Sie diese verwenden können, wenn Sie sie wie ich benötigen.
Wie wäre es, wenn Sie die übergeordnete Prozess-ID als Befehlszeilenargument senden? :)
John Demetriou
Antworten:
60
Dieser Code bietet eine schöne Schnittstelle zum Auffinden des übergeordneten Prozessobjekts und berücksichtigt die Möglichkeit mehrerer Prozesse mit demselben Namen:
Das sind einige erstaunlich schlecht benannte Methoden.
Mark
4
In meinen Tests ist dies viel langsamer als die Lösung von Simon Mourier. Außerdem gibt es leider eine Art "Prozess nach vorne bringen" -Mechanismus. Ich bin mir nicht sicher warum. Hat das noch jemand erlebt? Der Test, den ich dafür ausführe, ist eine von Visual Studio erstellte Setup-Bootstrapper-EXE, die das Windows-Installationsprogramm MSIEXEC.exe startet.
Tyler Collier
6
Leider funktioniert es nicht, wenn der Name der Leistungsindikatorkategorie lokalisiert ist (z. B. unter nicht englischem Windows).
LukeSw
5
Ich würde Simons Version vorschlagen, es sei denn, es gibt einen dringenden Grund, dies nicht zu tun, da der Leistungsunterschied erheblich ist.
David Burton
150
Hier ist eine Lösung. Es verwendet p / invoke, scheint aber gut zu funktionieren, 32 oder 64 CPU:
/// <summary>/// A utility class to determine a process parent./// </summary>[StructLayout(LayoutKind.Sequential)]publicstructParentProcessUtilities{// These members must match PROCESS_BASIC_INFORMATIONinternalIntPtrReserved1;internalIntPtrPebBaseAddress;internalIntPtrReserved2_0;internalIntPtrReserved2_1;internalIntPtrUniqueProcessId;internalIntPtrInheritedFromUniqueProcessId;[DllImport("ntdll.dll")]privatestaticexternintNtQueryInformationProcess(IntPtr processHandle,int processInformationClass,refParentProcessUtilities processInformation,int processInformationLength,outint returnLength);/// <summary>/// Gets the parent process of the current process./// </summary>/// <returns>An instance of the Process class.</returns>publicstaticProcessGetParentProcess(){returnGetParentProcess(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>publicstaticProcessGetParentProcess(int id){Process process =Process.GetProcessById(id);returnGetParentProcess(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>publicstaticProcessGetParentProcess(IntPtr handle){ParentProcessUtilities pbi =newParentProcessUtilities();int returnLength;int status =NtQueryInformationProcess(handle,0,ref pbi,Marshal.SizeOf(pbi),out returnLength);if(status !=0)thrownewWin32Exception(status);try{returnProcess.GetProcessById(pbi.InheritedFromUniqueProcessId.ToInt32());}catch(ArgumentException){// not foundreturnnull;}}}
Es wird tatsächlich verwaltet, ist aber auf einem anderen Betriebssystem als Windows nicht portierbar. Sie haben Recht. Der Begriff eines übergeordneten Prozesses ist jedoch auch nicht portierbar, da er nicht in .NET Framework selbst enthalten ist. Daher halte ich ihn nicht für ein großes Problem.
Simon Mourier
10
Toll! Keine langsamen Leistungsindikatoren. Ich hasse die "nicht verwalteten" Kommentare wirklich. Wie wird die Abfrage eines Perf-Zählers besser verwaltet als mit P / Invoke?
Jabe
5
Leider ist diese Funktion nur intern. MSDN sagt Folgendes: "[NtQueryInformationProcess ist möglicherweise in zukünftigen Windows-Versionen geändert oder nicht verfügbar. Anwendungen sollten die in diesem Thema aufgeführten alternativen Funktionen verwenden.]" Msdn.microsoft.com/en-us/library/windows/desktop/…
justin. m.chase
21
@ justin.m.chase - Es ist seit fast 20 Jahren dort, daher bezweifle ich, dass es morgen entfernt wird, und es gibt keine altenate NT-Funktionen, die den übergeordneten Prozess meines Wissens geben, aber ja, sicher, auf eigenes Risiko verwenden .
Simon Mourier
4
Diese Methode ist mindestens zehnmal schneller, wenn ich die Leistung dieser Methode mit anderen Methoden vergleiche. Die akzeptierte Antwort tickt : 2600657. Diese Antwort tickt : 8454.
Funktioniert, aber WMI kann sehr langsam sein (Sekunden). Pinvoke ist der richtige Weg.
Alastair Maw
4
Hier ist mein Versuch einer verwalteten Lösung.
Es fragt die Leistungsindikatoren für alle Prozesse ab und gibt ein Wörterbuch der untergeordneten PID an die übergeordnete PID zurück. Dann können Sie das Wörterbuch mit Ihrer aktuellen PID überprüfen, um Ihre Eltern, Großeltern usw. zu sehen.
Es ist übertrieben, wie viele Informationen es sicher bekommt. Fühlen Sie sich frei zu optimieren.
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace PidExamples{classParentPid{staticvoidMain(string[] args){var childPidToParentPid =GetAllProcessParentPids();int currentProcessId =Process.GetCurrentProcess().Id;Console.WriteLine("Current Process ID: "+ currentProcessId);Console.WriteLine("Parent Process ID: "+ childPidToParentPid[currentProcessId]);}publicstaticDictionary<int,int>GetAllProcessParentPids(){var childPidToParentPid =newDictionary<int,int>();var processCounters =newSortedDictionary<string,PerformanceCounter[]>();var category =newPerformanceCounterCategory("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());}elseif("Creating Process ID".CompareTo(counter.CounterName)==0){
parentPid =(int)(counter.NextValue());}}if(childPid !=-1&& parentPid !=-1){
childPidToParentPid[childPid]= parentPid;}}return childPidToParentPid;}}}
In anderen Nachrichten erfuhr ich, wie viele Leistungsindikatoren sich auf meiner Maschine befanden: 13401. Heilige Kuh.
Diese Methode funktioniert, scheint aber extrem langsam zu sein. In meiner Maschine dauerte es über 10 Sekunden.
Karsten
3
Wenn Sie P / Invoke akzeptieren, gibt es einen besseren Weg, der besser dokumentiert ist als NtQueryInformationProcess: PROCESSENTRY32 (CreateToolhelp32Snapshot, Process32First, Process32Next). Es wird in diesem Beitrag gezeigt .
Achten Sie auf die subtilen Details
und beachten Sie, dass die übergeordnete PID nicht unbedingt die Ersteller-PID ist. Tatsächlich können diese völlig unabhängig sein, wie in den Community-Kommentaren unter
PROCESSENTRY32 hervorgehoben .
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:
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:
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;
publicclassTestClass{publicstaticvoidTestMethod(){var p =Process.GetCurrentProcess().Parent();Console.WriteLine("{0}", p.Id);}}
Für alternatives Ende ..
Gemäß der Dokumentation gibt es ein Paar von Iterationsmethoden pro Typ der Einträge, wie z. B. Process32Firstund Process32Nextfü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 Toolhelp32mit Hilfe angehängt , denke ich, dass eine statische Hilfsklasse richtig ist, damit wir die eindeutigen qualifizierten Namen haben können, wie Toolhelp32.Snapshotoder Toolhelp32.IEntryobwohl 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)]publicstructWinModuleEntry:Toolhelp32.IEntry{// MODULEENTRY32[DllImport("kernel32.dll")]publicstaticexternboolModule32Next(Toolhelp32.Snapshot snap,refWinModuleEntry entry);publicboolTryMoveNext(Toolhelp32.Snapshot snap,outToolhelp32.IEntry entry){var x =newWinModuleEntry{ dwSize=Marshal.SizeOf(typeof(WinModuleEntry))};var b =Module32Next(snap,ref x);
entry=x;return b;}publicint dwSize;publicint th32ModuleID;publicint th32ProcessID;publicintGlblcntUsage;publicintProccntUsage;publicIntPtr modBaseAddr;publicint modBaseSize;publicIntPtr hModule;//byte moduleName[256];[MarshalAs(UnmanagedType.ByValTStr,SizeConst=256)]publicstring moduleName;[MarshalAs(UnmanagedType.ByValTStr,SizeConst=260)]publicstring fileName;//byte fileName[260];//public const int sizeofModuleName = 256;//public const int sizeofFileName = 260;}
und einige test ..
publicclassTestClass{publicstaticvoidTestMethod(){var p =Process.GetCurrentProcess().Parent();Console.WriteLine("{0}", p.Id);var formatter =newCustomFormatter{};foreach(var x inToolhelp32.TakeSnapshot<WinModuleEntry>(Toolhelp32.SnapModule, p.Id)){Console.WriteLine(String.Format(formatter,"{0}", x));}}}publicclassCustomFormatter:IFormatProvider,ICustomFormatter{StringICustomFormatter.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)));returnString.Format("{{{0}}}",String.Join(", ", q.ToArray()));}objectIFormatProvider.GetFormat(Type formatType){returntypeof(ICustomFormatter)!=formatType ?null:this;}}
Process.GetProcessById()
mit einer ID einer (jetzt) nicht vorhandenen Prozess-ID anrufen . Aber zu diesem Zeitpunkt haben Sie die Prozess-ID des Elternteils, sodass Sie diese verwenden können, wenn Sie sie wie ich benötigen.Antworten:
Dieser Code bietet eine schöne Schnittstelle zum Auffinden des übergeordneten Prozessobjekts und berücksichtigt die Möglichkeit mehrerer Prozesse mit demselben Namen:
Verwendung:
Code:
quelle
float.As
definiert?Hier ist eine Lösung. Es verwendet p / invoke, scheint aber gut zu funktionieren, 32 oder 64 CPU:
quelle
2600657
. Diese Antwort tickt :8454
.Diesen Weg:
quelle
Hier ist mein Versuch einer verwalteten Lösung.
Es fragt die Leistungsindikatoren für alle Prozesse ab und gibt ein Wörterbuch der untergeordneten PID an die übergeordnete PID zurück. Dann können Sie das Wörterbuch mit Ihrer aktuellen PID überprüfen, um Ihre Eltern, Großeltern usw. zu sehen.
Es ist übertrieben, wie viele Informationen es sicher bekommt. Fühlen Sie sich frei zu optimieren.
In anderen Nachrichten erfuhr ich, wie viele Leistungsindikatoren sich auf meiner Maschine befanden: 13401. Heilige Kuh.
quelle
Wenn Sie P / Invoke akzeptieren, gibt es einen besseren Weg, der besser dokumentiert ist als NtQueryInformationProcess: PROCESSENTRY32 (CreateToolhelp32Snapshot, Process32First, Process32Next). Es wird in diesem Beitrag gezeigt .
Achten Sie auf die subtilen Details und beachten Sie, dass die übergeordnete PID nicht unbedingt die Ersteller-PID ist. Tatsächlich können diese völlig unabhängig sein, wie in den Community-Kommentaren unter PROCESSENTRY32 hervorgehoben .
quelle
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
Und wir können es verwenden wie:
Prüfung
Für alternatives Ende ..
Gemäß der Dokumentation gibt es ein Paar von Iterationsmethoden pro Typ der Einträge, wie z. B.
Process32First
undProcess32Next
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, wieToolhelp32.Snapshot
oderToolhelp32.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
und einige test ..
Falls Sie ein Codebeispiel wünschen ..
quelle