8

我正在编写一个应用程序来启动和监视 C# 中的其他应用程序。我正在使用 System.Diagnostics.Process 类来启动应用程序,然后使用 Process.Responding 属性监视应用程序,以每 100 毫秒轮询一次应用程序的状态。如果应用程序没有响应,我使用 Process.CloseMainWindow 来停止应用程序或 Process.Kill 来杀死它。

我注意到一个奇怪的行为,有时进程对象进入响应属性始终返回 true 的状态,即使底层进程挂在循环中并且它不响应 CloseMainWindow。

重现它的一种方法是在启动流程实例后立即轮询 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 上与 Mendelt 闲聊(或 tweet-tweet?)后,我认为我应该更新我的答案,以便社区充分了解..

  • WaitForInputIdle仅适用于具有 GUI 的应用程序。
  • 您指定等待的时间,如果进程在该时间范围内达到空闲状态,则该方法返回一个布尔值,您显然可以在需要时使用它来循环,或根据需要进行处理。

希望有帮助:)

于 2008-09-24T08:19:46.700 回答
4

我认为增强对 _process.Responding 的检查可能会更好,以便仅在 Responding 属性返回 false 超过 5 秒时才尝试停止/终止进程(例如)。

我想您可能会经常发现,应用程序在进行更密集的处理时可能会在一瞬间“没有响应”。

我相信更宽松的方法会更好地工作,允许进程在短时间内“不响应”,只有在它反复“不响应”几秒钟(或多长时间)时才采取行动。

进一步说明:Microsoft 文档指出 Responding 属性专门与用户界面相关,这就是为什么新启动的进程可能不会让其 UI 立即响应的原因。

于 2008-09-24T08:08:20.737 回答
3

感谢您的回答。这

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

似乎可以解决问题。这仍然很奇怪,因为 Responding 和 WaitForInputIdle 应该都在幕后使用相同的 win32 api 调用。

一些更多的背景信息
GUI 应用程序有一个带有消息队列的主窗口。响应和 WaitForInputIdle 通过检查进程是否仍在处理来自此消息队列的消息来工作。这就是为什么它们只适用于 GUI 应用程序。不知何故,调用响应太快似乎会干扰进程获取该消息队列的句柄。调用 WaitForInputIdle 似乎可以解决这个问题。

我将不得不深入反射器,看看我是否能理解这一点。

更新
似乎在启动后检索与进程关联的窗口句柄足以触发奇怪的行为。像这样:

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

我检查了 Reflector,这就是 Responding 在幕后所做的。似乎如果您过早获得 MainWindowHandle,您会得到错误的句柄,并且它会在进程的剩余生命周期中使用这个错误的句柄,或者直到您调用 Refresh();

update
调用 WaitForInputIdle() 有时只能解决问题。每次阅读 Responding 属性时调用 Refresh() 似乎效果更好。

于 2008-09-24T09:08:04.870 回答
1

我也在大约 2 年前的一个项目中注意到了这一点。在请求某些道具值之前,我调用了 .Refresh() 。当我需要调用 .Refresh() 时,它是一种反复试验的方法。

于 2008-10-18T01:50:11.160 回答