Come posso sapere se un processo è in esecuzione?


155

Quando ricevo un riferimento a a System.Diagnostics.Process, come posso sapere se un processo è attualmente in esecuzione?

Risposte:


252

Questo è un modo per farlo con il nome:

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

È possibile eseguire il ciclo di tutto il processo per ottenere l'ID per successive manipolazioni:

Process[] processlist = Process.GetProcesses();
foreach(Process theprocess in processlist){
   Console.WriteLine("Process: {0} ID: {1}", theprocess.ProcessName, theprocess.Id);
}

Questo e 'esattamente quello che stavo cercando. Anche se questo è un post molto vecchio, mi spiegheresti come questo è C # valido. Non ne dubito, vedo che funziona, ma non ho mai visto se non senza {}.
Matteo,

4
@MatthewD: le if/elseistruzioni C # che sono lunghe solo una riga non devono avere parentesi graffe per indicare l'istruzione di blocco. Questo vale anche per foreache fordichiarazioni. Si riduce allo stile di programmazione.
Hallmanac,

Ho fatto qualche ricerca anche su questo, ho trovato quelle informazioni, ma non le ho viste for. Anni di sviluppo di c # .net e non ho mai visto questo stile. Come si suol dire, "impari qualcosa di nuovo ogni giorno". Grazie per il post e la risposta ..
MatthewD

3
@MatthewD sì, questo vale per la maggior parte delle lingue (come Java). In genere è buona norma evitare una linea come questa e mettere sempre parentesi graffe, poiché c'è sempre la possibilità che potresti dover aggiungere altre dichiarazioni lì in futuro, nel qual caso le parentesi graffe saranno già lì quando ne avrai bisogno. Ma per cose come questa, se sei sicuro al 100% di aver bisogno di una sola istruzione, va bene farlo e sintatticamente valido.
David Mordigal,

1
Se non riesci a trovare il processo, prova a rimuovere l'estensione. (Es .: .exe)
DxTx il

28

Questo è il modo più semplice che ho trovato dopo aver usato il riflettore. Ho creato un metodo di estensione per questo:

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;
    }
}

Il Process.GetProcessById(processId)metodo chiama il ProcessManager.IsProcessRunning(processId)metodo e genera ArgumentExceptionnel caso in cui il processo non esista. Per qualche motivo la ProcessManagerclasse è interna ...


Questa è stata davvero una buona risposta; tuttavia, non dovresti avere tramite l'argomento un'eccezione nulla (Poiché un'eccezione riferimento null sarebbe stata generata comunque e non avresti fatto nulla con l'eccezione. Inoltre, otterrai InvalidOperationException se non avessi richiamato Start () o hai invocato il metodo close (). Ho pubblicato un'altra risposta per spiegare queste due situazioni.
Aelphaeis

16

Soluzione sincrona:

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


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

Soluzione asincrona:

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.");
}

6
Per la prima opzione: come posso sapere se il processo è stato avviato in primo luogo?
reshefm,

8

reshefm ebbe una bella risposta; tuttavia, non tiene conto di una situazione in cui il processo non è mai stato avviato.

Ecco una versione modificata di ciò che ha pubblicato.

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

Ho rimosso la sua ArgumentNullException perché in realtà si suppone che sia un'eccezione di riferimento null e viene comunque generata dal sistema e ho anche tenuto conto della situazione in cui il processo non è mai stato avviato o il metodo close () è stato utilizzato per chiudere il processi.


Personalmente, preferirei di gran lunga vedere ArgumentNullException durante la revisione di un'eccezione registrata rispetto a NullReferenceException, poiché ArgumentNullException è molto più esplicito su ciò che è andato storto.
Sean,

1
@Sean Normalmente sono d'accordo con te ma questo è un metodo di estensione. Penso che sia più appropriato lanciare un'eccezione puntatore null data la sintassi, sembra solo più coerente con i metodi di chiamata di oggetti null.
Aelphaeis,

Ciò attiverà ogni volta il gestore eventi FirstHandledException. Modo di spammare i tuoi registri lì amico.
Latenza

6

Questo dovrebbe essere un liner:

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

3

Dipende da quanto affidabile vuoi che questa funzione sia. Se vuoi sapere se la particolare istanza del processo che hai è ancora in esecuzione e disponibile con un'accuratezza del 100%, sei sfortunato. Il motivo è che dall'oggetto processo gestito ci sono solo 2 modi per identificare il processo.

Il primo è l'ID processo. Sfortunatamente, gli ID di processo non sono univoci e possono essere riciclati. La ricerca nell'elenco di processi per un ID corrispondente ti dirà solo che esiste un processo con lo stesso ID in esecuzione, ma non è necessariamente il tuo processo.

Il secondo elemento è la maniglia di processo. Ha lo stesso problema dell'ID ed è più complicato lavorare con lui.

Se stai cercando un'affidabilità di livello medio, è sufficiente controllare l'elenco dei processi corrente per un processo con lo stesso ID.


1

Process.GetProcesses()è la strada da percorrere. Ma potrebbe essere necessario utilizzare uno o più criteri diversi per trovare il processo, a seconda di come è in esecuzione (ad esempio come servizio o app normale, indipendentemente dal fatto che abbia o meno una barra del titolo).


Se si inserisce questo metodo in un ciclo, costa molti cicli della CPU. Consiglio di usare GetProcessByName () o GetProcessByID ().
Hao Nguyen,

0

Forse (probabilmente) sto leggendo la domanda in modo errato, ma stai cercando la proprietà HasExited che ti dirà che il processo rappresentato dal tuo oggetto Process è uscito (normalmente o no).

Se il processo a cui si fa riferimento ha un'interfaccia utente, è possibile utilizzare la proprietà Responding per determinare se l'interfaccia utente sta attualmente rispondendo all'input dell'utente o meno.

È inoltre possibile impostare EnableRaisingEvents e gestire l'evento Exited (che viene inviato in modo asincrono) o chiamare WaitForExit () se si desidera bloccare.


0

È possibile creare un'istanza di un'istanza di processo una volta per il processo desiderato e continuare a tenere traccia del processo utilizzando l'oggetto .NET Process (continuerà a monitorare fino a quando non si chiama esplicitamente Chiudi su quell'oggetto .NET, anche se il processo che stava monitorando è morto [questo per darti il ​​tempo di chiudere il processo, ovvero ExitTime ecc.])

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

All'uscita di un processo associato (vale a dire quando viene arrestato dal sistema operativo attraverso una terminazione normale o anormale), il sistema memorizza le informazioni amministrative sul processo e ritorna al componente che aveva chiamato WaitForExit. Il componente Processo può quindi accedere alle informazioni, che include ExitTime, utilizzando l'handle per il processo uscito.

Poiché il processo associato è terminato, la proprietà Handle del componente non punta più a una risorsa di processo esistente. Al contrario, l'handle può essere utilizzato solo per accedere alle informazioni del sistema operativo sulla risorsa di processo. Il sistema è a conoscenza degli handle ai processi usciti che non sono stati rilasciati dai componenti Process, quindi mantiene le informazioni ExitTime e Handle in memoria fino a quando il componente Process non libera specificamente le risorse. Per questo motivo, ogni volta che si chiama Avvia per un'istanza di processo, chiamare Chiudi quando il processo associato è terminato e non sono più necessarie informazioni amministrative su di esso. Chiudi libera la memoria allocata al processo uscito.


0

Ho provato la soluzione di Coincoin:
prima di elaborare un file, lo copio come file temporaneo e lo apro.
Quando ho finito, chiudo l'applicazione se è ancora aperta ed elimino il file temporaneo:
utilizzo semplicemente una variabile di processo e la controllo in seguito:

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 );  
}

Più tardi chiudo l'applicazione:

 ...   
openApplication.Refresh(); 

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

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

Funziona (finora)


3
A openApplication.HasExited(), HasExited non è una funzione. Il modo corretto sarebbe openApplication.HasExited.
caiosm1005,

0

Nonostante l'API supportata dai framework .Net per quanto riguarda il controllo del processo esistente per ID processo, tali funzioni sono molto lente. Il costo per l'esecuzione di Process.GetProcesses () o Process.GetProcessById / Name () è enorme.

Un metodo molto più rapido per controllare un processo in esecuzione tramite ID è utilizzare l'API nativa OpenProcess () . Se l'handle di ritorno è 0, il processo non esiste. Se handle è diverso da 0, il processo è in esecuzione. Non è garantito che questo metodo funzioni sempre al 100% a causa dell'autorizzazione.


0

Ci sono molti problemi associati a questo, come altri sembrano aver affrontato parzialmente:

  • Non è garantito che tutti i membri dell'istanza siano thread-safe. Significa che ci sono condizioni di gara che possono verificarsi con la durata dell'istantanea mentre si cerca di valutare le proprietà dell'oggetto.
  • L'handle del processo genererà Win32Exception per ACCESS DENIED dove non sono consentite autorizzazioni per la valutazione di questa e altre proprietà simili.
  • Per lo stato ISUN'T RUNNING, verrà sollevata anche ArgumentException quando si tenta di valutare alcune delle sue proprietà.

Se le proprietà menzionate da altri sono interne o meno, è comunque possibile ottenere informazioni da esse tramite la riflessione se l'autorizzazione lo consente.

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

È possibile inserire il codice Win32 per Snapshot oppure utilizzare WMI che è più lento.

HANDLE CreateToolhelp32Snapshot(
  DWORD dwFlags,
  DWORD th32ProcessID
);

Un'altra opzione sarebbe OpenProcess / CloseProcess, ma continuerai gli stessi problemi con le eccezioni generate come prima.

Per WMI - OnNewEvent.Properties ["?"]:

  • "ParentProcessId"
  • "ProcessId"
  • "Nome del processo"
  • "SECURITY_DESCRIPTOR"
  • "SessionID"
  • "Sid"
  • "TIME_CREATED"

0
string process = "notepad";
if (Process.GetProcessesByName(process).Length == 0)
{
    MessageBox.Show("Working");
}
else
{
    MessageBox.Show("Not Working");
}

inoltre è possibile utilizzare un timer per controllare il processo ogni volta


3
Non sarebbe il contrario? se lunghezza == 0 significa che non funziona?
Jay Jacobs,

La risposta è la stessa da Patrick Desjardins: stackoverflow.com/a/262291/7713750
Rekshino

Al contrario, la lunghezza> 0 indica che sono stati trovati processi.
HaseeB Mir,

Questo potrebbe avere un errore, ( length == 0dovrebbe essere visualizzato Not Working), ma ottiene comunque il lavoro svolto.
Momoro,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.