确定进程何时完成初始化

时间:2014-09-17 03:27:17

标签: c# python ironpython

我正在构建一个初始化AutoCAD实例的IronPython模块,我需要在 AutoCAD 完成初始化之后将<1>返回到模块,进入其消息循环并进入稳定(不加载依赖/任何东西)状态。我尝试过使用System.Diagnostics.Process.WaitForInputIdle()但没有运气。

这是我到目前为止所拥有的:

import System.Diagnostics as sysdiag

def start_autocad(self):
    print("\"C:\\Program Files\\Autodesk\\Autodesk AutoCAD Civil 3D 2014\\acad.exe\" /b \"C:\\Temp\\C3DAutoScript.scr\"")
    for process in sysdiag.Process.GetProcessesByName("acad"):
        process.Kill()
    try:
        acad_process = sysdiag.Process.Start("C:\\Program Files\\Autodesk\\Autodesk AutoCAD Civil 3D 2014\\acad.exe", " /b \"C:\\Temp\\C3DAutoScript.scr\"")
        acad_process.WaitForInputIdle()
        return 1
    except:
        return 0

不幸的是,这个功能一旦流程开始打开就会返回,而不是在它完成之后。有没有人知道在经典的cPython,IronPython或C#中处理这个问题的方法(不使用过度杀戮睡眠功能来等待它)?

2 个答案:

答案 0 :(得分:1)

进程可以在启动后几乎立即开始处理消息。在完成此操作之前,不要求显示主窗口。这可以做到避免显示为悬挂,以防加载缓慢。

您可以尝试在WaitForInputIdle返回后尝试与流程进行交互 - 即使在“加载”时它也可能最终响应。如果它不起作用,请等待主窗口出现(使用FindWindow)。如果应用程序是COM服务器,则尝试建立COM连接。

P.S。杀死进程不是最好的主意,可能会导致数据或配置损坏。尝试正确关闭应用程序将close事件发送到其主窗口。

答案 1 :(得分:0)

在你的问题的标题中,你要求“一个过程”。在您的问题文本中,您专门询问Autocad。

我可以告诉你如何为一般的过程做这件事,而不是专门针对Autocad。

我遇到了同样的问题并找到了使用API​​的解决方案

GetModuleFileNameEx(HANDLE h_Process, ....)

MSDN说:

  

如果目标进程中的模块列表已损坏或尚未   初始化,或者如果模块列表在函数调用期间更改为   加载或卸载DLL的结果,GetModuleFileNameEx可能   失败或返回不正确的信息。

当你尝试使用此函数获取进程的可执行路径时,当进程仍在加载它的DLL时,函数失败并且GetLastError()返回ERROR_INVALID_HANDLE。这并不意味着传递给函数的进程句柄无效。但这是当进程仍在启动时得到的错误代码。

我用几个应用程序测试了它。它运作得很好。

int WaitForProcess(HANDLE h_Process, int Timeout)
{
    for (int T=0; T<=Timeout; T+=50)
    {
       if (GetModuleFileNameEx(h_Process, NULL, ...) > 0)
           return 0;

       int Err = GetLastError();
       if (Err != ERROR_INVALID_HANDLE) // = 6
           return Err;

       Sleep(50);
    }
    return ERROR_TIMEOUT;
}

为什么会这样? GetModuleFileNameEx()在内部执行的操作是读取进程的内存(为此必须使用访问权限PROCESS_VM_READ打开进程)。但是当进程在加载程序锁定时,这是不允许的。当进程加载DLL时,加载程序锁定处于活动状态。

此代码是通用的,适用于任何应用程序。它等待应用程序准备好进行基本初始化。如果这还不够,我建议等待应用程序的主窗口出现。