我试图打开" 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;
}
答案 0 :(得分:7)
WaitForInputIdle有效,但不是你认为的方式。这在很大程度上是因为文档具有误导性(或者至少不是应该如此明确):
等待指定的进程完成处理其初始输入并等待没有输入待处理的用户输入,或等待超时间隔结束。
这几乎是犯罪上不准确的。虽然备注部分指出,WaitForInputIdle
每个进程最多等待一次,但它从未提及重要细节。具体做法是:
WaitForInputIdle
就会返回,此过程中的任何线程都准备好处理消息。这些消息不需要是用户输入。WaitForInputIdle
以允许进程使用基于消息的协议与子进程通信。解决的具体方案是DDE,没有人 1)再使用。 WaitForInputIdle
不能用作问题的可靠解决方案:等待子进程'UI显示。你真的需要等待UI显示。
系统提供两种可供您使用的解决方案:
HCBT_CREATEWND
回调。您可以检查CREATESTRUCT的 lpszClass 和/或 lpszName 成员,以过滤掉您感兴趣的窗口。EVENT_OBJECT_CREATE
event。每当要创建一个窗口时,都会调用全局CBT挂钩。 HWND
引用已完全填充的内核结构,但调用CreateWindow[Ex]
的客户端仍可终止窗口创建。相反,WinEvent是在完全构建窗口之后发布的,并且可以进行交互。
通常,当应用程序需要在CreateWindowEx
的调用者第一次看到HWND
之前更新窗口的某些方面时,使用基于CBT挂钩的解决方案。相反,WinEvents通常是实现可访问性或UI自动化解决方案时的首选工具。
<小时/> 其他资源:
<小时/> 1) 是的,我知道,某些应用程序可能仍然使用DDE。但是,如果雷蒙德·陈在2007年建议,我们应该feel free to stop using DDE,我将把它作为权威指导。