Question

J'écris une application pour démarrer et surveiller d'autres applications en C #. J'utilise la classe System.Diagnostics.Process pour démarrer des applications, puis pour surveiller les applications à l'aide de la propriété Process.Responding pour interroger l'état de l'application toutes les 100 millisecondes. J'utilise Process.CloseMainWindow pour arrêter l'application ou Process.Kill pour le tuer s'il ne répond pas.

J'ai remarqué un comportement étrange dans lequel l'objet de processus entrait parfois dans un état dans lequel la propriété répondante renvoyait toujours la valeur true, même lorsque le processus sous-jacent se bloquait dans une boucle et qu'il ne répondait pas à CloseMainWindow.

Une façon de la reproduire consiste à interroger la propriété Responding juste après le démarrage de l'instance de processus. Ainsi, par exemple

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

reproduira l'état d'erreur pendant que

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

travaillera. Réduire la période de sommeil à 500 introduira à nouveau l’état d’erreur.

Quelque chose dans l'appel de _process.Repondre trop rapidement après le démarrage semble empêcher l'objet d'obtenir le bon gestionnaire de file d'attente de messages Windows. Je suppose que je dois attendre _process.Start pour terminer son travail asynchrone. Existe-t-il un meilleur moyen d'attendre cela que d'appeler Thread.Sleep? Je ne suis pas convaincu que les 1000 ms suffiront toujours.

Était-ce utile?

La solution

Maintenant, j'ai besoin de vérifier cela plus tard, mais je suis sûr qu'il existe une méthode qui indique au thread d'attendre qu'il soit prêt à être entré. Surveillez-vous uniquement les processus de l'interface graphique?

Traiter.AttendrePourInputIdle ne vous aide pas? Ou est-ce que je manque le point? :)

Mettre à jour

Après un bavardage sur Twitter (ou tweet-tweet?) avec Mendelt, j'ai pensé que je devrais mettre à jour ma réponse pour que la communauté soit pleinement consciente.

  • WaitForInputIdle ne fonctionnera que sur les applications disposant d'une interface graphique.
  • Vous spécifiez le délai d'attente et la méthode renvoie une valeur booléenne si le processus atteint un état d'inactivité dans ce laps de temps. Vous pouvez évidemment l'utiliser pour effectuer une boucle si nécessaire ou gérer le cas échéant.

J'espère que cela vous aidera:)

Autres conseils

Je pense qu'il peut être préférable d'améliorer la vérification de _process.Responding afin que vous n'essayiez d'arrêter / de tuer le processus que si la propriété Responding renvoie false pendant plus de 5 secondes (par exemple).

Je pense que vous constaterez peut-être que très souvent, les applications risquent de "ne pas répondre". pendant une fraction de seconde pendant qu'ils effectuent un traitement plus intensif.

Je pense qu'une approche moins stricte fonctionnera mieux, permettant à un processus de "ne pas répondre". pendant un court laps de temps, ne prendre des mesures que s'il est répété "ne répond pas" pendant plusieurs secondes (ou aussi longtemps que vous le souhaitez).

Remarque supplémentaire: la documentation de Microsoft indique que la propriété Responding concerne spécifiquement l'interface utilisateur. C'est pourquoi un processus récemment démarré peut ne pas recevoir d'interface utilisateur immédiatement.

Merci pour les réponses. Cette

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

Semble résoudre le problème. Cela reste étrange, parce que Responding et WaitForInputIdle devraient tous deux utiliser le même appel API Win32 sous les couvertures.

Quelques informations de fond supplémentaires
Les applications graphiques ont une fenêtre principale avec une file de messages. La réponse et WaitForInputIdle fonctionnent en vérifiant si le processus traite toujours les messages de cette file d'attente. C'est pourquoi ils ne travaillent qu'avec des applications à interface graphique. D'une manière ou d'une autre, il semble que le fait d'appeler Répondre trop rapidement empêche le processus d'obtenir un identificateur pour cette file d'attente de messages. L'appel à WaitForInputIdle semble résoudre ce problème.

Je vais devoir plonger dans le réflecteur pour voir si je peux comprendre.

mise à jour
Il semble que récupérer le handle de fenêtre associé au processus juste après le démarrage suffit à déclencher le comportement étrange. Comme ceci:

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

J'ai vérifié avec Reflector et voici ce que fait Répondre sous les couvertures. Il semble que si vous obtenez le MainWindowHandle trop tôt, vous obtenez le mauvais et il utilise ce mauvais traitement pour le reste de la vie du processus ou jusqu'à ce que vous appeliez Refresh ();

mise à jour
L'appel de WaitForInputIdle () ne résout le problème que de temps en temps. Appeler Refresh () chaque fois que vous lisez la propriété Responding semble mieux fonctionner.

Je l’ai aussi remarqué dans un projet il ya environ 2 ans. J'ai appelé .Refresh () avant de demander certaines valeurs prop. C’était une approche par essais qui consistait à trouver le moment où je devais appeler .Refresh ().

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top