WaitForInputIdle无法以编程方式启动mspaint [英] WaitForInputIdle doesn't work for starting mspaint programmatically
问题描述
我正在尝试打开"mspaint"并在初始化后立即找到它的句柄.但是,如果我呼叫WaitForInputIdle
,则FindWindow
返回NULL
.如果我尝试使用功能Sleep(1000)
,它将起作用.但是我认为等待程序准备就绪不是正确的方法.这段代码有解决方案吗?
I'm trying to open "mspaint" and find handle of it right after it has been initialized. But FindWindow
returns NULL
if I call WaitForInputIdle
. If I try to use the function Sleep(1000)
it works. But I don't think it's a right way to wait for the program to be ready. Is there a solution for this code?
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 works, but not the way you assume it does. This is largely, because the documentation is misleading (or at least not as explicit as it should be):
等待,直到指定的进程完成其初始输入的处理并等待没有输入待处理的用户输入为止,或者直到超时间隔过去.
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.
这在刑事上几乎是不准确的.尽管备注部分指出,WaitForInputIdle
每个进程最多等待一次,但它从未提及重要细节.具体来说:
This is almost criminally inaccurate. While the Remarks section notes, that WaitForInputIdle
waits at most once per process, it never mentions significant details. Specifically:
-
WaitForInputIdle
在初始启动完成后立即返回,该进程中的任何线程都已准备好处理消息.这些消息无需用户输入.
发明了 -
WaitForInputIdle
来允许进程使用基于消息的协议与子进程进行通信.解决的特定方案是 DDE ,没有人 1)已使用.
WaitForInputIdle
returns, as soon as the initial startup has come to a point, where any thread in the process is ready to process messages. Those messages need not be user input.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出现.您确实需要等待UI出现.
WaitForInputIdle
cannot be used as a reliable solution to your problem: Waiting for a child process' UI to show up. You really need to wait for the UI show up.
系统提供了两种可以使用的解决方案:
The system offers two solutions you can use:
- 全局 CBT钩,然后等待用于
HCBT_CREATEWND
回调.您可以检查 CREATESTRUCT 的 lpszClass 和/或 lpszName 成员可以过滤掉您感兴趣的窗口. - 使用 WinEvents 并响应
EVENT_OBJECT_CREATE
事件.
- A global CBT hook, and wait for the
HCBT_CREATEWND
callback. You can inspect the CREATESTRUCT's lpszClass and/or lpszName members to filter out the window you are interested in. - Use WinEvents and respond to the
EVENT_OBJECT_CREATE
event.
每当要创建窗口时,都会调用全局CBT挂钩. HWND
引用的内核结构已完全填充,但是调用CreateWindow[Ex]
的客户端仍可能终止窗口创建.相比之下,在完全构建窗口之后,便会发布WinEvent,并且可以进行交互了.
The global CBT hook is called, whenever a window is about to be created. The kernel structures that the HWND
references have been fully populated, but the client calling CreateWindow[Ex]
may still terminate window creation. In contrast, the WinEvent is issued, after the window has been fully constructed, and is ready for interaction.
通常,当应用程序需要在CreateWindowEx
的调用者首次看到HWND
之前更新窗口的某些方面时,将使用基于CBT挂钩的解决方案.相反,在实现可访问性或UI自动化解决方案时,通常选择WinEvents.
In general, a solution based on a CBT hook is used, when an application needs to update certain aspects of a window before the caller of CreateWindowEx
gets to see the HWND
for the first time. WinEvents, instead, are usually the tool of choice when implementing accessibility or UI automation solutions.
其他资源:
Additional resources:
- WaitForInputIdle should really be called WaitForProcessStartupComplete
- WaitForInputIdle waits for any thread, which might not be the thread you care about
1) 是的,我知道,某些应用程序可能仍在使用DDE.但是,如果Raymond Chen在2007年提出建议,我们应该随意停止使用DDE ,我将其作为权威性的指导.
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.
这篇关于WaitForInputIdle无法以编程方式启动mspaint的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!