8

C#で他のアプリケーションを起動および監視するためのアプリケーションを作成しています。System.Diagnostics.Processクラスを使用してアプリケーションを起動し、Process.Respondingプロパティを使用してアプリケーションを監視して、100ミリ秒ごとにアプリケーションの状態をポーリングしています。Process.CloseMainWindowを使用してアプリケーションを停止するか、Process.Killを使用して、応答しない場合はアプリケーションを強制終了します。

基になるプロセスがループでハングし、CloseMainWindowに応答しない場合でも、プロセスオブジェクトが応答プロパティが常にtrueを返す状態になることがあるという奇妙な動作に気づきました。

これを再現する1つの方法は、プロセスインスタンスを開始した直後にRespondingプロパティをポーリングすることです。だから例えば

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

エラー状態を再現します

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

動作します。スリープ期間を500に短縮すると、エラー状態が再び発生します。

開始後の_process.Respondingの応答が速すぎると、オブジェクトが適切なWindowsメッセージキューハンドラーを取得できなくなるようです。_process.Startが非同期作業を終了するのを待つ必要があると思います。Thread.Sleepを呼び出すよりも、これを待つためのより良い方法はありますか?1000ミリ秒で常に十分だとは確信していません。

4

4 に答える 4

8

これは後で確認する必要がありますが、入力の準備ができるまで待機するようにスレッドに指示するメソッドがあると確信しています。GUI プロセスのみを監視していますか?

Process.WaitForInputIdleは役に立ちませんか? それとも私は要点を逃していますか?:)

アップデート

メンデルトとの Twitter (またはツイート-ツイート?) でのおしゃべりの後、コミュニティが完全に認識できるように、回答を更新する必要があると考えました..

  • WaitForInputIdleGUI を持つアプリケーションでのみ動作します。
  • 待機する時間を指定すると、その時間枠内にプロセスがアイドル状態に達した場合、メソッドは bool を返します。これを使用して、必要に応じてループしたり、適切に処理したりできます。

それが役立つことを願っています:)

于 2008-09-24T08:19:46.700 に答える
4

_process.Responding のチェックを強化して、Responding プロパティが 5 秒以上 false を返す場合にのみプロセスを停止/強制終了しようとする方がよいと思います (たとえば)。

アプリケーションが集中的な処理を行っているときに、一瞬「応答しない」ことがよくあると思います。

より寛大なアプローチがよりうまく機能し、プロセスが短時間「応答しない」ことを許可し、数秒間(または必要なだけ)繰り返し「応答しない」場合にのみアクションを実行できると思います。

詳細な注意: Microsoft のドキュメントでは、Responding プロパティが特にユーザー インターフェイスに関連していることを示しています。これが、新しく開始されたプロセスの UI がすぐに応答しない可能性がある理由です。

于 2008-09-24T08:08:20.737 に答える
3

答えてくれてありがとう。これ

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

問題を解決しているようです。RespondingとWaitForInputIdleの両方が内部で同じwin32api呼び出しを使用する必要があるため、それはまだ奇妙です。

その他の背景情報
GUIアプリケーションには、メッセージキューのあるメインウィンドウがあります。RespondingとWaitForInputIdleは、プロセスがこのメッセージキューからのメッセージをまだ処理しているかどうかを確認することで機能します。これが、GUIアプリでのみ機能する理由です。どういうわけか、Respondingの呼び出しが速すぎると、プロセスがそのメッセージキューへのハンドルを取得するのを妨げるようです。WaitForInputIdleを呼び出すと、その問題が解決するようです。

これを理解できるかどうかを確認するには、リフレクターに飛び込む必要があります。

update
開始直後にプロセスに関連付けられたウィンドウハンドルを取得するだけで、奇妙な動作を引き起こすことができるようです。このような:

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

私はReflectorに確認しましたが、これはRespondingが内部で行うことです。MainWindowHandleを取得するのが早すぎると、間違ったものを取得し、プロセスの残りの期間、またはRefresh()を呼び出すまで、この間違った処理を使用するようです。

update
WaitForInputIdle()を呼び出すと、問題が解決する場合があります。Respondingプロパティを読み取るたびにRefresh()を呼び出すと、うまく機能するようです。

于 2008-09-24T09:08:04.870 に答える
1

私も約2年前のプロジェクトでそれに気づきました。特定の prop 値を要求する前に .Refresh() を呼び出しました。IT は、いつ .Refresh() を呼び出す必要があるかを見つけるための試行錯誤のアプローチでした。

于 2008-10-18T01:50:11.160 に答える