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

我正在编写一个应用程序来启动和监视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毫秒总是足够的。

现在,我需要稍后检查一下,但我确信有一个方法告诉线程等待它准备输入。 您是否仅监控GUI流程?

是不是Process.WaitForInputIdle对你有任何帮助? 或者我错过了这一点? 🙂

更新

在Twitter(或推文推文?)与门德尔聊天之后,我想我应该更新我的答案,以便社区充分了解…

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

希望有所帮助:)

我认为增强对_process.Responding的检查可能会更好,这样如果Responding属性返回false超过5秒(例如),你只会尝试停止/终止进程。

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

我相信一种更宽松的方法会更好地工作,允许一个过程在短时间内“没有响应”,只有在几秒钟内(或者你想要多长时间)反复“没有响应”时才采取行动。

进一步说明:Microsoft文档表明Responding属性与用户界面特别相关,这就是新启动的进程可能没有立即响应UI的原因。

谢谢你的回答。 这个

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

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

更多背景信息
GUI应用程序有一个带有消息队列的主窗口。 Responding和WaitForInputIdle通过检查进程是否仍处理来自此消息队列的消息来工作。 这就是他们只使用GUI应用程序的原因。 不知怎的,似乎调用Responding太快会干扰让Process获取该消息队列的句柄。 调用WaitForInputIdle似乎解决了这个问题。

我将不得不潜入reflection器,看看我是否能理解这一点。

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

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

我检查了Reflector,这就是Responding在幕后做的事情。 看起来如果你太快得到MainWindowHandle就会得到错误的一个,并且它会在进程的剩余生命周期中使用这个错误的句柄,或者直到你调用Refresh();

更新
调用WaitForInputIdle()只能在某些时候解决问题。 每次读取Responding属性时调用Refresh()似乎都会更好。

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