代码之家  ›  专栏  ›  技术社区  ›  Mendelt

system.diagnostics.process.start怪异行为

  •  8
  • Mendelt  · 技术社区  · 16 年前

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

    我注意到了一个奇怪的行为,在这种情况下,进程对象有时会进入一种状态,在这种状态下,即使底层进程挂起一个循环,并且它不响应closeMainWindow,响应属性也总是返回true。

    复制它的一种方法是在启动流程实例后立即轮询响应的属性。例如

    _process.Start();
    bool responding = _process.Responding;
    

    将在

    _process.Start();
    Thread.Sleep(1000);
    bool responding = _process.Responding;
    

    会工作。 将睡眠时间缩短到500将再次引入错误状态。

    在启动后调用_process.response的速度过快,似乎会阻止对象获得正确的Windows消息队列处理程序。我想我需要等待进程。开始完成它的异步工作。有没有比调用线程更好的方法来等待这个。睡眠?我不太相信1000毫秒就足够了。

    4 回复  |  直到 16 年前
        1
  •  8
  •   Rob Cooper    16 年前

    现在,我需要稍后检查这个问题,但是我确信有一个方法告诉线程等待它准备好输入。您只监视GUI进程吗?

    不是 Process.WaitForInputIdle 有什么帮助吗?或者我错过了要点?:)

    更新

    在twitter上聊天(或tweet tweet?)有了门德尔特,我想我应该更新我的答案,这样社区才能充分意识到……

    • WaitForInputIdle 只能在具有GUI的应用程序上工作。
    • 指定等待时间,如果进程在该时间段内达到空闲状态,该方法将返回一个bool,显然可以使用它在需要时循环,或者根据需要进行处理。

    希望有帮助:)

        2
  •  4
  •   Jarod Elliott    16 年前

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

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

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

    进一步注意:Microsoft文档指出响应属性专门与用户界面相关,这就是为什么新启动的进程的UI可能没有立即响应的原因。

        3
  •  3
  •   Mendelt    16 年前

    谢谢你的回答。这个

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

    似乎解决了问题。这仍然很奇怪,因为响应和waitForInputIdle都应该在封面下使用相同的win32 api调用。

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

    我得潜入反射镜看看我能不能理解这一点。

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

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

    我检查了反射镜,这是什么反应下的封面。如果您过早地获得了主窗口句柄,那么您可能会得到错误的主窗口句柄,并且它在进程的剩余生命周期内或直到您调用refresh()时使用了错误的主窗口句柄;

    更新
    调用waitForInputIdle()有时只能解决问题。每次读取响应属性时调用refresh()似乎效果更好。

        4
  •  1
  •   GregUzelac    16 年前

    我也注意到在两年前的一个项目中。我在请求某些属性值之前调用了.refresh()。当我需要调用.refresh()时,这是一种反复尝试的方法。