WaitForInputIdle 不适用于以编程方式启动 mspaint

WaitForInputIdle doesn't work for starting mspaint programmatically

我正在尝试打开 "mspaint" 并在它初始化后立即找到它的句柄。但是 FindWindow returns NULL 如果我调用 WaitForInputIdle。如果我尝试使用函数 Sleep(1000) 它会起作用。但我不认为等待程序准备好是正确的方法。此代码有解决方案吗?

    CString strWindowDirectory;
    GetSystemDirectory(strWindowDirectory.GetBuffer(MAX_PATH), MAX_PATH);
    SHELLEXECUTEINFO sei = { 0 };
    sei.cbSize = sizeof(SHELLEXECUTEINFO);
    sei.fMask =  SEE_MASK_NOCLOSEPROCESS;
    sei.lpVerb = L"open";
    sei.lpFile = L"mspaint";
    sei.lpDirectory = strWindowDirectory;
    sei.nShow = SW_SHOWNORMAL;

    HWND    hPaint = NULL;
    if(ShellExecuteEx(&sei))
    {
        int r = ::WaitForInputIdle(sei.hProcess, INFINITE);
        ATLTRACE(L"WaitForInputIdle %d\n", r);

        if (sei.hProcess == NULL)       return;

        hPaint = ::FindWindow(L"MSPaintApp", NULL); 

        ATLTRACE(L"Handle %d\n", hPaint);
        if (!hPaint) return;
    }
    else
    {
        MessageBox(L"Couldn't find mspaint program");
        return;
    }

WaitForInputIdle 有效,但不是您假设的那样。这主要是因为文档具有误导性(或者至少没有像它应该的那样明确):

Waits until the specified process has finished processing its initial input and is waiting for user input with no input pending, or until the time-out interval has elapsed.

这在犯罪上几乎是不准确的。虽然 Remarks 部分指出 WaitForInputIdle 每个进程最多等待一次,但它从未提及重要细节。具体来说:

  • WaitForInputIdle returns,一旦初始启动到达某个点,进程中的任何线程都准备好处理消息。这些消息不需要用户输入。
  • WaitForInputIdle 的发明是为了允许进程使用基于消息的协议与子进程进行通信。解决的具体场景是DDE,没有人1)再使用它。

WaitForInputIdle 不能用作您问题的可靠解决方案:等待子进程' UI 出现。你真的需要等待 UI 出现。

系统提供两种方案供您使用:

  1. 全局CBT hook, and wait for the HCBT_CREATEWND callback. You can inspect the CREATESTRUCTlpszClassand/orlpszName成员过滤掉window 你有兴趣
  2. 使用WinEvents and respond to the EVENT_OBJECT_CREATE event.

每当要创建 window 时,都会调用全局 CBT 挂钩。 HWND 引用的内核结构已完全填充,但调用 CreateWindow[Ex] 的客户端可能仍会终止 window 创建。相比之下,WinEvent 是在 window 已完全构建并准备好进行交互后发出的。

通常,当应用程序需要在 CreateWindowEx 的调用者看到 [=16= 之前更新 window 的某些方面时,使用基于 CBT 挂钩的解决方案】 第一次。相反,WinEvents 通常是实施辅助功能或 UI 自动化解决方案时的首选工具。


其他资源:


1) 是的,我知道,一些 应用程序可能仍在使用 DDE。但是如果陈峰在2007年建议我们应该feel free to stop using DDE,我就把它作为权威的指导传递下去。