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 出现。
系统提供两种方案供您使用:
- 全局CBT hook, and wait for the
HCBT_CREATEWND
callback. You can inspect the CREATESTRUCT的lpszClassand/orlpszName成员过滤掉window 你有兴趣
- 使用WinEvents and respond to the
EVENT_OBJECT_CREATE
event.
每当要创建 window 时,都会调用全局 CBT 挂钩。 HWND
引用的内核结构已完全填充,但调用 CreateWindow[Ex]
的客户端可能仍会终止 window 创建。相比之下,WinEvent 是在 window 已完全构建并准备好进行交互后发出的。
通常,当应用程序需要在 CreateWindowEx
的调用者看到 [=16= 之前更新 window 的某些方面时,使用基于 CBT 挂钩的解决方案】 第一次。相反,WinEvents 通常是实施辅助功能或 UI 自动化解决方案时的首选工具。
其他资源:
- WaitForInputIdle should really be called WaitForProcessStartupComplete
- WaitForInputIdle waits for any thread, which might not be the thread you care about
1) 是的,我知道,一些 应用程序可能仍在使用 DDE。但是如果陈峰在2007年建议我们应该feel free to stop using DDE,我就把它作为权威的指导传递下去。
我正在尝试打开 "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 出现。
系统提供两种方案供您使用:
- 全局CBT hook, and wait for the
HCBT_CREATEWND
callback. You can inspect the CREATESTRUCT的lpszClassand/orlpszName成员过滤掉window 你有兴趣 - 使用WinEvents and respond to the
EVENT_OBJECT_CREATE
event.
每当要创建 window 时,都会调用全局 CBT 挂钩。 HWND
引用的内核结构已完全填充,但调用 CreateWindow[Ex]
的客户端可能仍会终止 window 创建。相比之下,WinEvent 是在 window 已完全构建并准备好进行交互后发出的。
通常,当应用程序需要在 CreateWindowEx
的调用者看到 [=16= 之前更新 window 的某些方面时,使用基于 CBT 挂钩的解决方案】 第一次。相反,WinEvents 通常是实施辅助功能或 UI 自动化解决方案时的首选工具。
其他资源:
- WaitForInputIdle should really be called WaitForProcessStartupComplete
- WaitForInputIdle waits for any thread, which might not be the thread you care about
1) 是的,我知道,一些 应用程序可能仍在使用 DDE。但是如果陈峰在2007年建议我们应该feel free to stop using DDE,我就把它作为权威的指导传递下去。