Wie kann ich feststellen, ob ein Prozess ausgeführt wird?

155

System.Diagnostics.ProcessWie kann ich feststellen, ob gerade ein Prozess ausgeführt wird, wenn ich einen Verweis auf a erhalte ?

reshefm
quelle

Antworten:

252

Dies ist eine Möglichkeit, dies mit dem Namen zu tun:

Process[] pname = Process.GetProcessesByName("notepad");
if (pname.Length == 0)
  MessageBox.Show("nothing");
else
  MessageBox.Show("run");

Sie können alle Prozesse in einer Schleife ausführen, um die ID für eine spätere Bearbeitung zu erhalten:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}
Patrick Desjardins
quelle
Genau das habe ich gesucht. Auch wenn dies ein sehr alter Beitrag ist, würden Sie mir erklären, wie dies gültig ist C #. Ich bezweifle es nicht, ich sehe, dass es funktioniert, aber ich habe nie gesehen, ob sonst ohne {}.
MatthewD
4
@MatthewD: C # -Anweisungen if/else, die nur eine Zeile lang sind, müssen keine geschweiften Klammern haben, um die Blockanweisung anzugeben. Dies gilt auch für foreachund forAussagen. Es läuft auf den Codierungsstil hinaus.
Hallmanac
Ich habe auch darüber recherchiert, diese Informationen gefunden, aber ich habe die forInformationen nicht gesehen . Jahre von c # .net dev und ich haben diesen Stil noch nie gesehen. Wie sie sagen: "Du lernst jeden Tag etwas Neues". Vielen Dank für den Beitrag und die Antwort ..
MatthewD
3
@MatthewD Ja, das gilt eigentlich für die meisten Sprachen (wie Java). Es ist im Allgemeinen eine gute Praxis, solche Einzeiler zu vermeiden und immer geschweifte Klammern zu setzen, da es in Zukunft immer möglich ist, dass Sie dort weitere Anweisungen hinzufügen müssen. In diesem Fall sind die Klammern bereits vorhanden, wenn Sie sie benötigen. Wenn Sie jedoch zu 100% sicher sind, dass Sie nur eine Anweisung benötigen, ist dies in Ordnung und syntaktisch gültig.
David Mordigal
1
Wenn Sie den Prozess nicht finden können, entfernen Sie die Erweiterung. (Beispiel: .exe)
DxTx
28

Dies ist der einfachste Weg, den ich nach der Verwendung eines Reflektors gefunden habe. Ich habe dafür eine Erweiterungsmethode erstellt:

public static class ProcessExtensions
{
    public static bool IsRunning(this Process process)
    {
        if (process == null) 
            throw new ArgumentNullException("process");

        try
        {
            Process.GetProcessById(process.Id);
        }
        catch (ArgumentException)
        {
            return false;
        }
        return true;
    }
}

Die Process.GetProcessById(processId)Methode ruft die ProcessManager.IsProcessRunning(processId)Methode auf und ArgumentExceptionlöst aus, falls der Prozess nicht existiert. Aus irgendeinem Grund ist die ProcessManagerKlasse intern ...

reshefm
quelle
Dies war eine wirklich gute Antwort; Sie sollten jedoch nicht durch das Argument null Ausnahme gehen (da eine Nullreferenzausnahme ohnehin ausgelöst worden wäre und Sie nichts mit der Ausnahme gemacht haben. Außerdem erhalten Sie eine InvalidOperationException, wenn Sie Start () nicht aufgerufen haben.) Methode oder Sie haben die close () -Methode aufgerufen. Ich habe eine weitere Antwort gepostet, um diese beiden Situationen zu berücksichtigen.
Aelphaeis
16

Synchrone Lösung:

void DisplayProcessStatus(Process process)
{
    process.Refresh();  // Important


    if(process.HasExited)
    {
        Console.WriteLine("Exited.");
    }
    else
    {
        Console.WriteLine("Running.");
    } 
}

Asynchrone Lösung:

void RegisterProcessExit(Process process)
{
    // NOTE there will be a race condition with the caller here
    //   how to fix it is left as an exercise
    process.Exited += process_Exited;
}

static void process_Exited(object sender, EventArgs e)
{
   Console.WriteLine("Process has exited.");
}
Münze
quelle
6
Für die erste Option: Wie kann ich wissen, ob der Prozess überhaupt gestartet wurde?
Reshefm
8

reshefm hatte eine ziemlich nette Antwort; Es berücksichtigt jedoch keine Situation, in der der Prozess nie begonnen hat.

Hier ist eine modifizierte Version von dem, was er gepostet hat.

    public static bool IsRunning(this Process process)
    {
        try  {Process.GetProcessById(process.Id);}
        catch (InvalidOperationException) { return false; }
        catch (ArgumentException){return false;}
        return true;
    }

Ich habe seine ArgumentNullException entfernt, da es sich tatsächlich um eine Nullreferenzausnahme handelt und sie trotzdem vom System ausgelöst wird. Außerdem habe ich die Situation berücksichtigt, in der der Prozess nie gestartet wurde oder die Methode close () zum Schließen der verwendet wurde Prozess.

Aelphaeis
quelle
Persönlich würde ich beim Überprüfen einer protokollierten Ausnahme lieber eine ArgumentNullException als eine NullReferenceException sehen, da ArgumentNullException viel expliziter darüber ist, was schief gelaufen ist.
Sean
1
@ Sean Ich würde Ihnen normalerweise zustimmen, aber dies ist eine Erweiterungsmethode. Ich denke, es ist angemessener, angesichts der Syntax eine Nullzeigerausnahme auszulösen. Es fühlt sich einfach konsistenter an, Methoden von Nullobjekten aufzurufen.
Aelphaeis
Dies löst jedes Mal den FirstHandledException-Ereignishandler aus. Weg, um Ihre Protokolle dort zu spammen Kumpel.
Latenz
6

Dies sollte ein Einzeiler sein:

public static class ProcessHelpers {
    public static bool IsRunning (string name) => Process.GetProcessesByName(name).Length > 0;
}
Guneysos
quelle
3

Dies hängt davon ab, wie zuverlässig diese Funktion sein soll. Wenn Sie wissen möchten, ob die von Ihnen verwendete Prozessinstanz noch ausgeführt wird und mit 100% iger Genauigkeit verfügbar ist, haben Sie kein Glück. Der Grund dafür ist, dass es vom verwalteten Prozessobjekt aus nur zwei Möglichkeiten gibt, den Prozess zu identifizieren.

Die erste ist die Prozess-ID. Leider sind Prozess-IDs nicht eindeutig und können recycelt werden. Wenn Sie die Prozessliste nach einer passenden ID durchsuchen, werden Sie nur darüber informiert, dass ein Prozess mit derselben ID ausgeführt wird, dies ist jedoch nicht unbedingt Ihr Prozess.

Der zweite Punkt ist der Prozessgriff. Es hat jedoch das gleiche Problem wie die ID und es ist schwieriger, damit zu arbeiten.

Wenn Sie eine mittlere Zuverlässigkeit suchen, ist es ausreichend, die aktuelle Prozessliste auf einen Prozess mit derselben ID zu überprüfen.

JaredPar
quelle
1

Process.GetProcesses()ist der Weg zu gehen. Je nachdem, wie er ausgeführt wird, müssen Sie möglicherweise ein oder mehrere unterschiedliche Kriterien verwenden, um Ihren Prozess zu finden (dh als Dienst oder normale App, unabhängig davon, ob er über eine Titelleiste verfügt oder nicht).

Jeff Kotula
quelle
Wenn Sie diese Methode in eine Schleife einfügen, kostet dies viele CPU-Zyklen. Ich empfehle GetProcessByName () oder GetProcessByID () zu verwenden.
Hao Nguyen
0

Vielleicht (wahrscheinlich) lese ich die Frage falsch, aber suchen Sie nach der HasExited-Eigenschaft, die Ihnen mitteilt, dass der von Ihrem Process-Objekt dargestellte Prozess beendet wurde (entweder normal oder nicht).

Wenn der Prozess, auf den Sie verweisen, eine Benutzeroberfläche hat, können Sie mithilfe der Eigenschaft "Antworten" bestimmen, ob die Benutzeroberfläche derzeit auf Benutzereingaben reagiert oder nicht.

Sie können auch EnableRaisingEvents festlegen und das Ereignis Exited (das asychron gesendet wird) behandeln oder WaitForExit () aufrufen, wenn Sie blockieren möchten.


quelle
0

Sie können eine Prozessinstanz einmal für den gewünschten Prozess instanziieren und den Prozess mit diesem .NET-Prozessobjekt weiter verfolgen (es wird so lange verfolgt, bis Sie Close für dieses .NET-Objekt explizit aufrufen, selbst wenn der Prozess, den es verfolgt hat, abgestorben ist [Dies soll Ihnen Zeit geben, den Prozess zu beenden, auch bekannt als ExitTime usw.])

Zitieren von http://msdn.microsoft.com/en-us/library/fb4aw7b8.aspx :

Wenn ein zugeordneter Prozess beendet wird (dh wenn er vom Betriebssystem durch eine normale oder abnormale Beendigung heruntergefahren wird), speichert das System Verwaltungsinformationen über den Prozess und kehrt zu der Komponente zurück, die WaitForExit aufgerufen hat. Die Prozesskomponente kann dann auf die Informationen zugreifen, einschließlich der ExitTime, indem sie das Handle für den beendeten Prozess verwendet.

Da der zugeordnete Prozess beendet wurde, verweist die Handle-Eigenschaft der Komponente nicht mehr auf eine vorhandene Prozessressource. Stattdessen kann das Handle nur verwendet werden, um auf die Informationen des Betriebssystems über die Prozessressource zuzugreifen. Das System kennt Handles für beendet Prozesse, die nicht von Prozesskomponenten freigegeben wurden, und speichert daher die ExitTime- und Handle-Informationen im Speicher, bis die Prozesskomponente die Ressourcen spezifisch freigibt. Aus diesem Grund rufen Sie jedes Mal, wenn Sie Start für eine Prozessinstanz aufrufen, Close auf, wenn der zugehörige Prozess beendet wurde und Sie keine administrativen Informationen mehr dazu benötigen. Durch Schließen wird der dem beendeten Prozess zugewiesene Speicher freigegeben.

George Birbilis
quelle
0

Ich habe die Lösung von Coincoin ausprobiert:
Bevor ich eine Datei verarbeite, kopiere ich sie als temporäre Datei und öffne sie.
Wenn ich fertig bin, schließe ich die Anwendung, wenn sie noch geöffnet ist, und lösche die temporäre Datei:
Ich verwende einfach eine Prozessvariable und überprüfe sie anschließend:

private Process openApplication;  
private void btnOpenFile_Click(object sender, EventArgs e) {  
    ...
    // copy current file to fileCache  
    ...  
    // open fileCache with proper application
    openApplication = System.Diagnostics.Process.Start( fileCache );  
}

Später schließe ich die Anwendung:

 ...   
openApplication.Refresh(); 

// close application if it is still open       
if ( !openApplication.HasExited() ) {
    openApplication.Kill();  
}

// delete temporary file  
System.IO.File.Delete( fileCache );

Es funktioniert (soweit)

Jack Griffin
quelle
3
Bei openApplication.HasExited()ist HasExited keine Funktion. Der richtige Weg wäre openApplication.HasExited.
caiosm1005
0

Trotz der unterstützten API von .Net-Frameworks zur Überprüfung des vorhandenen Prozesses anhand der Prozess-ID sind diese Funktionen sehr langsam. Die Ausführung von Process.GetProcesses () oder Process.GetProcessById / Name () kostet sehr viele CPU-Zyklen.

Eine viel schnellere Methode zum Überprüfen eines laufenden Prozesses anhand der ID ist die Verwendung der nativen API OpenProcess () . Wenn das Rückgabehandle 0 ist, ist der Prozess nicht vorhanden. Wenn sich das Handle von 0 unterscheidet, wird der Prozess ausgeführt. Es gibt keine Garantie dafür, dass diese Methode aufgrund der Erlaubnis jederzeit zu 100% funktioniert.

Hao Nguyen
quelle
0

Damit sind viele Probleme verbunden, wie andere anscheinend teilweise angesprochen haben:

  • Es wird nicht garantiert, dass Instanzmitglieder threadsicher sind. Das heißt, es gibt Race-Bedingungen, die während der Lebensdauer des Snapshots auftreten können, wenn versucht wird, die Eigenschaften des Objekts zu bewerten.
  • Das Prozesshandle löst Win32Exception für ACCESS DENIED aus, wenn Berechtigungen zum Auswerten dieser und anderer solcher Eigenschaften nicht zulässig sind.
  • Für den Status ISN'T RUNNING wird auch eine ArgumentException ausgelöst, wenn versucht wird, einige seiner Eigenschaften zu bewerten.

Unabhängig davon, ob die von anderen genannten Eigenschaften intern sind oder nicht, können Sie Informationen durch Reflexion erhalten, wenn die Erlaubnis dies zulässt.

var x = obj.GetType().GetProperty("Name", BindingFlags.NonPublic | BindingFlags.Instance);

Sie können Win32-Code für Snapshot aufrufen oder WMI verwenden, das langsamer ist.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Eine andere Option wäre OpenProcess / CloseProcess, aber Sie werden immer noch auf dieselben Probleme stoßen, mit Ausnahmen, die wie zuvor ausgelöst werden.

Für WMI - OnNewEvent.Properties ["?"]:

  • "ParentProcessID"
  • "Prozess ID"
  • "Prozessname"
  • "SECURITY_DESCRIPTOR"
  • "Session-ID"
  • "Sid"
  • "TIME_CREATED"
Latenz
quelle
0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

Sie können auch einen Timer verwenden, um den Vorgang jedes Mal zu überprüfen

Berkay
quelle
3
Wäre das nicht umgekehrt? Wenn Länge == 0, bedeutet das, dass es nicht funktioniert?
Jay Jacobs
Die Antwort ist die gleiche wie von Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino
Umgekehrt bedeutet Länge> 0, dass Prozesse gefunden werden.
HaseeB Mir
Dies könnte einen Fehler haben ( length == 0sollte angezeigt werden Not Working), erledigt aber trotzdem die Arbeit.
Momoro