我试图打开“mspaint”并在初始化后立即找到它的句柄。但FindWindow
回报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;
}
等待输入空闲有效,但不是你想象的那样。这很大程度上是因为文档具有误导性(或者至少没有应有的那么明确):
等待,直到指定进程完成处理其初始输入并等待用户输入且没有待处理的输入,或者直到超时间隔已过。
这几乎是不准确的。虽然Remarks节指出,WaitForInputIdle
每个进程最多等待一次,它从不提及重要的细节。具体来说:
-
WaitForInputIdle
一旦初始启动到达某个点,进程中的任何线程都准备好处理消息,就会返回。这些消息不需要是用户输入。
-
WaitForInputIdle
was invented to allow a process to communicate with a child process using a message-based protocol. The specific scenario addressed was DDE, which no one1) uses anymore.
WaitForInputIdle
不能用作解决您的问题的可靠解决方案:等待子进程的 UI 显示。您确实需要等待用户界面出现。
该系统提供了两种可供您使用的解决方案:
- 一个全球性的CBT hook,并等待
HCBT_CREATEWND
回调。您可以检查创建结构体's lpsz类 and/or lpszName会员筛选出您感兴趣的窗口。
- Use 赢奖活动并回应
EVENT_OBJECT_CREATE
event.
每当要创建窗口时,都会调用全局 CBT 挂钩。内核结构HWND
引用已完全填充,但客户端调用CreateWindow[Ex]
仍可能终止窗口创建。相反,WinEvent 在窗口完全构造之后发出,并准备好进行交互。
一般来说,当应用程序需要在调用者之前更新窗口的某些方面时,会使用基于 CBT 挂钩的解决方案。CreateWindowEx
可以看到HWND
首次。相反,WinEvents 通常是实现辅助功能或 UI 自动化解决方案时的首选工具。
Additional resources:
- WaitForInputIdle 实际上应该称为 WaitForProcessStartupComplete
- WaitForInputIdle 等待任何线程,该线程可能不是您关心的线程
1) Yes, I know, some applications might still use DDE. But if Raymond Chen suggested in 2007, that we should feel free to stop using DDE, I'll just pass that on as authoritative guidance.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)