System.Diagnostics.Process.Start奇怪的行为

时间:2020-03-06 14:38:54  来源:igfitidea点击:

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

我注意到一种奇怪的行为,有时流程对象进入一种状态,即使基础流程挂起且循环不响应CloseMainWindow,响应属性也始终返回true。

重现它的一种方法是在启动流程实例后立即轮询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毫秒总是足够的。

解决方案

我认为最好增强_process.Responding的检查,以便仅在Responding属性返回false超过5秒的情况下才尝试停止/终止该进程。

我认为我们可能会发现,当应用程序执行更密集的处理时,它们可能会瞬间"不响应"。

我认为,更宽容的方法会更好,可以让流程在短时间内"不响应",只有在重复"不响应"几秒钟(或者所需时间长)时才采取措施。

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

现在,我需要稍后进行检查,但是我确定有一种方法告诉线程等待,直到准备好输入为止。我们是否仅监视GUI进程?

Process.WaitForInputIdle对我们没有任何帮助吗?还是我错过了重点? :)

更新

在与Mendelt在Twitter上进行聊天(或者发送推文吗?)之后,我认为我应该更新我的答案,以便社区充分了解。

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

希望能有所帮助:)

感谢回答。这

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

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

一些其他背景信息
GUI应用程序有一个带有消息队列的主窗口。响应和WaitForInputIdle通过检查进程是否仍在处理来自此消息队列的消息来工作。这就是为什么它们仅与GUI应用程序一起使用的原因。似乎以某种方式调用Responding太快会干扰使Process获取该消息队列的句柄。调用WaitForInputIdle似乎可以解决该问题。

我必须深入研究反射器,看看我是否可以理解这一点。

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

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

我与Reflector进行了核对,这就是"响应"在幕后所做的。看来,如果过早得到MainWindowHandle,则会得到错误的结果,并且在该过程的整个生命周期的剩余时间内或者调用Refresh()之前,它将使用此错误的句柄。

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

我也注意到大约2年前的一个项目。在请求某些属性值之前,我调用了.Refresh()。 IT是一种反复试验的方法,可用于查找何时需要调用.Refresh()。