質問

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 ミリ秒で常に十分であるかどうかはあまり自信がありません。

役に立ちましたか?

解決

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

そうじゃない Process.WaitForInputIdle 何か役に立ちますか?それとも要点を見逃しているのでしょうか?:)

アップデート

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

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

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

他のヒント

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

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

私は、プロセスが短時間「応答しない」ことを許可し、数秒間 (または必要な期間) 繰り返し「応答しない」場合にのみアクションを実行する、より寛大なアプローチがより効果的であると信じています。

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

ご回答ありがとうございます。これ

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

問題は解決したようです。Responding と WaitForInputIdle の両方が内部で同じ win32 API 呼び出しを使用しているはずなので、それでも奇妙です。

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

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

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

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

Reflector で確認したところ、これは Responding が内部で行っていることです。MainWindowHandle を取得するのが早すぎると、間違ったハンドルを取得し、プロセスの存続期間中、または Refresh() を呼び出すまで、この間違ったハンドルが使用されるようです。

アップデート
WaitForInputIdle() を呼び出すと、問題が解決される場合があるだけです。Responding プロパティを読み取るたびに Refresh() を呼び出すと、うまく動作するようです。

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top