2012-01-17 15 views
16

Questo codice viene eseguito come previsto su un numero elevato di macchine. Tuttavia su una macchina particolare, la chiamata a WaitForExit() sembra essere ignorata e in effetti segna il processo come uscito.Process.WaitForExit incoerente su diverse macchine

static void Main(string[] args) 
{ 
    Process proc = Process.Start("notepad.exe"); 
    Console.WriteLine(proc.HasExited); //Always False 
    proc.WaitForExit(); //Blocks on all but one machines 
    Console.WriteLine(proc.HasExited); //**See comment below 
    Console.ReadLine(); 
} 

noti che diversamente una similar question su SO, il procedimento essendo chiamato è notepad.exe (per motivi di test), quindi è improbabile la colpa è esso - cioè esso non sta generando un secondo sottoprocesso e chiusura. Anche così, non spiegherebbe perché funziona su tutte le altre macchine.

Sulla macchina con problemi, la seconda chiamata a Console.WriteLine(proc.HasExited)) restituisce true anche se il blocco note è ancora chiaramente aperto, sia sullo schermo sia nel task manager.

La macchina esegue Windows 7 e .NET 4.0.

La mia domanda è; quali condizioni su quella particolare macchina potrebbe causare questo? Cosa dovrei controllare?

Edit - Le cose che ho provato finora/Aggiornamenti/info Forse rilevanti:

  • .NET reinstallati.
  • Chiude tutti i processi che non conosco nel task manager.
  • Windows non è stato ancora attivato su questa macchina.
  • Seguendo i commenti nei commenti, ho provato a ottenere l'ID del processo "esistente" utilizzando GetProcessesByName ma che restituisce semplicemente un array vuoto sul computer con problemi. Pertanto, è difficile dire che il problema è anche con WaitForExit, in quanto il processo non viene restituito chiamando GetProcessesByName anche prima di chiamare WaitForExit.
  • Sul computer del problema, il ParentID del processo del blocco note risultante è l'ID del processo del blocco note che il codice avvia manualmente, o in altre parole, il blocco note genera un processo secondario e termina automaticamente.
+1

È possibile che sia stato aperto un altro blocco note in precedenza? Quindi ne crei uno, ne uccidi uno, ma vedi ancora il vecchio Blocco note? 'proc.WaitForExit()' può tornare immediatamente, se non è stato possibile creare il processo o è stato terminato immediatamente a causa di alcuni motivi, ad esempio la mancanza di privilegi del codice originale per creare nuovi processi. – oleksii

+0

@oleskii, no mi sono assicurato di questo. Blocco note viene utilizzato solo qui come un processo "che tutti sanno", questo problema si verifica indipendentemente dal file utilizzato per il processo. – Rotem

+0

@oleskii "proc.WaitForExit() può restituire immediatamente, se non è stato possibile creare il processo o è stato interrotto immediatamente a causa di alcuni motivi" - il processo non sarebbe effettivamente terminato in questo caso? – Rotem

risposta

7

Il problema è che per default Process.StartInfo.UseShellExecute è impostata su true. Con questa variabile impostata su true, piuttosto che avviare il processo autonomamente, stai chiedendo alla shell di avviarla per te. Ciò può essere molto utile: ti permette di fare cose come "eseguire" un file HTML (la shell utilizzerà l'applicazione predefinita appropriata).

Non è così buono quando si desidera monitorare l'applicazione dopo averla eseguita (come è stato trovato), perché l'applicazione di avvio può talvolta confondersi su quale istanza deve essere tracciata.

I dettagli interni qui del motivo per cui questo accade sono probabilmente oltre le mie capacità di risposta- so che quando UseShellExecute == true, il framework utilizza l'API di Windows ShellExecuteEx, e quando UseShellExecute == false, utilizza CreateProcessWithLogonW, ma perché uno conduce a processi tracciabili e l'altro no, non lo so, poiché entrambi sembrano restituire l'ID del processo.

EDIT: Dopo un po 'di scavo:

This question mi ha segnalato alla bandiera SEE_MASK_NOCLOSEPROCESS, anzi che non sembra essere impostata quando si utilizza ShellExecute. La documentazione per gli stati di valore maschera:

In alcuni casi, come ad esempio quando l'esecuzione è soddisfatta attraverso un DDE conversazione, senza maniglia verrà restituito. L'applicazione chiamante è responsabile della chiusura dell'handle quando non è più necessaria.

Quindi suggerisce che restituire l'handle di processo non è affidabile. Non sono ancora arrivato abbastanza in profondità da sapere quale particolare caso limite potresti colpire qui però.

+0

Grazie! Mentre la soluzione risolve il mio problema, mi piacerebbe trovare il motivo per cui sembrava avere un effetto solo su una macchina di un gruppo di circa 50. – Rotem

+0

Spero che @EricLippert entri qui e campi "Perché questo succede " parte. Non sono così acuto. –

+2

Non ne ho la più pallida idea. Sono un esperto di progettazione e implementazione del linguaggio C# e del suo compilatore. Non conosco praticamente nulla su come Windows gestisce i processi. –

1

Una causa potrebbe essere un virus che ha sostituito notepad.exe per nascondersi. Se eseguito, genera il blocco note ed esce (solo una supposizione).

provare questo codice:

 var process = Process.Start("notepad.exe"); 
     var process2 = Process.GetProcessById(process.Id); 
     while (!process2.HasExited) 
     { 
      Thread.Sleep(1000); 
      try 
      { 
       process2 = Process.GetProcessById(process.Id); 
      } 
      catch (ArgumentException) 
      { 

       break; 
      } 

     } 

     MessageBox.Show("done"); 

Dopo Process.Start() controlla l'id processo notepad.exe con l'agenda e verificare che sia lo stesso di process.Id;

Oh, e si dovrebbe davvero utilizzare il percorso completo a notepad.exe

var notepad = Path.Combine(Environment.GetFolderPath(
        Environment.SpecialFolder.Windows), "notepad.exe"); 
Process.Start(notepad); 
Problemi correlati