Domanda

Sto scrivendo un'applicazione per avviare e monitorare altre applicazioni in C #. Sto usando la classe System.Diagnostics.Process per avviare le applicazioni e quindi monitorare le applicazioni utilizzando la proprietà Process.Responding per eseguire il polling dello stato dell'applicazione ogni 100 milisecs. Uso Process.CloseMainWindow per interrompere l'applicazione o Process.Kill per ucciderlo se non risponde.

Ho notato un comportamento strano in cui a volte l'oggetto processo entra in uno stato in cui la proprietà rispondente ritorna sempre vera anche quando il processo sottostante si blocca in un ciclo e dove non risponde a CloseMainWindow.

Un modo per riprodurlo è eseguire il polling della proprietà Responding subito dopo aver avviato l'istanza del processo. Quindi, ad esempio

_process.Start();
bool responding = _process.Responding;

riprodurrà lo stato di errore mentre

_process.Start();
Thread.Sleep(1000);
bool responding = _process.Responding;

funzionerà. Riducendo il periodo di sospensione a 500, verrà nuovamente introdotto lo stato di errore.

Qualcosa nel chiamare _process.Rispondere troppo velocemente dopo l'avvio sembra impedire all'oggetto di ottenere il giusto gestore della coda dei messaggi di Windows. Immagino di dover aspettare _process.Start per finire di fare il suo lavoro asincrono. C'è un modo migliore per aspettare questo che chiamare Thread.Sleep? Non sono troppo sicuro che i 1000 ms saranno sempre sufficienti.

È stato utile?

Soluzione

Ora, devo verificarlo più tardi, ma sono sicuro che esiste un metodo che dice al thread di attendere fino a quando non è pronto per l'input. Stai monitorando solo i processi della GUI?

Process.WaitForInputIdle non ti è di aiuto? O mi manca il punto? :)

Aggiornamento

Dopo una chiacchierata su Twitter (o un tweet-tweet?) con Mendelt, ho pensato di aggiornare la mia risposta in modo che la community sia pienamente consapevole.

  • WaitForInputIdle funzionerà solo su applicazioni che hanno una GUI.
  • Specifica il tempo di attesa e il metodo restituisce un valore booleano se il processo raggiunge uno stato inattivo entro tale intervallo di tempo, puoi ovviamente utilizzarlo per eseguire il ciclo se necessario o gestirlo nel modo appropriato.

Spero che aiuti :)

Altri suggerimenti

Penso che potrebbe essere meglio migliorare il controllo per _process.Risposta in modo da provare a interrompere / terminare il processo solo se la proprietà Responding restituisce false per più di 5 secondi (ad esempio).

Penso che potresti scoprire che abbastanza spesso, le applicazioni potrebbero non "rispondere". per una frazione di secondo mentre eseguono un'elaborazione più intensiva.

Credo che un approccio più indulgente funzionerà meglio, consentendo a un processo di "non rispondere". per un breve lasso di tempo, intervenendo solo se ripetutamente "non risponde" per alcuni secondi (o per quanto tempo desideri).

Nota aggiuntiva: la documentazione di Microsoft indica che la proprietà Responding si riferisce specificamente all'interfaccia utente, motivo per cui un processo appena avviato potrebbe non avere la sua UI che risponde immediatamente.

Grazie per le risposte. Questo

_process.Start();
_process.WaitForInputIdle();

Sembra risolvere il problema. È ancora strano perché Responding e WaitForInputIdle dovrebbero entrambi usare la stessa chiamata api win32 sotto le copertine.

Altre informazioni di base
Le applicazioni della GUI hanno una finestra principale con una coda di messaggi. Responding e WaitForInputIdle funzionano controllando se il processo elabora ancora i messaggi da questa coda di messaggi. Ecco perché funzionano solo con le app GUI. In qualche modo sembra che chiamare la risposta troppo velocemente interferisca con il processo che ottiene un handle per quella coda di messaggi. Chiamare WaitForInputIdle sembra risolvere questo problema.

Dovrò tuffarmi nel riflettore per vedere se riesco a dare un senso a questo.

update
Sembra che il recupero dell'handle della finestra associato al processo subito dopo l'avvio sia sufficiente per innescare lo strano comportamento. In questo modo:

_process.Start();
IntPtr mainWindow = _process.MainWindowHandle;

Ho controllato con Reflector e questo è ciò che fa Rispondere sotto le copertine. Sembra che se si ottiene MainWindowHandle troppo presto, si ottiene quello sbagliato e si utilizza questo errore gestirlo per il resto della vita del processo o fino a quando si chiama Refresh ();

update
Chiamare WaitForInputIdle () risolve il problema solo qualche volta. Chiamare Refresh () ogni volta che leggi la proprietà Responding sembra funzionare meglio.

Anch'io l'ho notato in un progetto circa 2 anni fa. Ho chiamato .Refresh () prima di richiedere determinati valori di prop. L'IT era un approccio di prova ed errore da trovare quando avevo bisogno di chiamare .Refresh ().

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top