我正在编写一个应用程序来启动和监视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毫秒总是足够的。
答案 0 :(得分:8)
现在,我需要稍后检查一下,但我确信有一个方法告诉线程等待它准备输入。您是否仅监控GUI流程?
Process.WaitForInputIdle对你没有任何帮助吗?或者我错过了这一点? :)
在Twitter(或推文推文?)与门德尔聊天之后,我想我应该更新我的答案,以便社区充分了解..
WaitForInputIdle
仅适用于具有GUI的应用程序。希望有所帮助:)
答案 1 :(得分:4)
我认为增强对_process.Responding的检查可能会更好,这样如果Responding属性返回false超过5秒(例如),你只会尝试停止/终止进程。
我认为你可能会发现,在他们进行更密集的处理时,应用程序可能会在一瞬间“没有响应”。
我相信一种更宽松的方法会更好地工作,允许一个过程在短时间内“没有响应”,只有在几秒钟内(或者你想要多长时间)反复“没有响应”时才采取行动
进一步说明:Microsoft文档表明Responding属性与用户界面特别相关,这就是新启动的进程可能没有立即响应UI的原因。
答案 2 :(得分:3)
感谢您的回答。此
_process.Start();
_process.WaitForInputIdle();
似乎解决了这个问题。它仍然很奇怪,因为Responding和WaitForInputIdle都应该使用相同的win32 api调用。
更多背景信息
GUI应用程序有一个带有消息队列的主窗口。 Responding和WaitForInputIdle通过检查进程是否仍处理来自此消息队列的消息来工作。这就是他们只使用GUI应用程序的原因。不知怎的,似乎调用Responding太快会干扰让Process获取该消息队列的句柄。调用WaitForInputIdle似乎可以解决这个问题。
我将不得不潜入反射器,看看我是否能理解这一点。
更新
似乎在启动后检索与进程关联的窗口句柄足以触发奇怪的行为。像这样:
_process.Start();
IntPtr mainWindow = _process.MainWindowHandle;
我使用Reflector进行了检查,这就是Responding在幕后所做的事情。似乎如果你太快得到MainWindowHandle,你会得到错误的一个,并且它会在进程的剩余生命周期中使用这个错误的句柄,或直到你调用Refresh();
更新
调用WaitForInputIdle()只能在某些时候解决问题。每次阅读Responding属性时调用Refresh()似乎都会更好。
答案 3 :(得分:1)
我在大约两年前的一个项目中也注意到了这一点。在请求某些道具值之前,我调用了.Refresh()。当我需要调用.Refresh()时,这是一种试错法。