6

我创建了一个小程序,它在新桌面中启动。

HDESK hDesktop = ::CreateDesktop(strDesktopName.c_str(),
                                    NULL, // Reserved
                                    NULL, // Reserved
                                    0, // DF_ALLOWOTHERACCOUNTHOOK
                                    GENERIC_ALL,
                                    NULL); // lpSecurity
::SetThreadDesktop(hDesktop);

稍后,使用以下行在该桌面上启动另一个应用程序:

PROCESS_INFORMATION pi = { 0 };
STARTUPINFO         si = { 0 };

si.cb = sizeof(si);
si.lpDesktop = &strDesktop[0];
if (FALSE == ::CreateProcess(pathModuleName.file_string().c_str(), L"abc def", NULL, NULL,      FALSE, 0, NULL, NULL, &si, &pi))
    return false;

DWORD dwWaitRes = ::WaitForSingleObject(pi.hProcess, INFINITE);

pathModuleName是由 获得的自身位置GetModuleFileName(NULL)

新创建的应用程序获取到另一个窗口的 HWND 并使用以下命令发送窗口消息:

// bring window to front
::SetForegroundWindow(hwnd);

// set focus so keyboard inputs will be caught
::SetFocus(hwnd);
::keybd_event(VK_MENU, 0x45, KEYEVENTF_EXTENDEDKEY | 0, 0);
...

所以基本上A桌面 DEFAULT 上的应用程序是B在桌面 X 上启动应用程序,它会获得一个 HWND 到C在同一个桌面 X 上启动的另一个应用程序。

我的问题是来自B桌面 X 上的应用程序的键盘事件没有在应用程序中触发C。只有当我使用SwitchDesktop(B)时,才会触发事件并正确执行代码。

我错过了什么?

4

1 回答 1

7

您正在尝试在物理控制台(屏幕、鼠标、键盘)上未激活的桌面上模拟用户输入,这不太可能工作,以及为什么SwitchDesktop()让它工作。根据文档:

切换桌面功能

使指定的桌面可见并激活它。这使桌面能够接收来自用户的输入。

keybd_event(), mouse_event(), SendInput(), 它们都简单地生成输入消息并将其存储到物理鼠标/键盘将消息发布到的相同输入队列中。在将输入消息分派给应用程序时,输入系统不知道用户输入和合成输入之间的区别。

Raymond Chen 在他的博客中谈到了这一点:

如何在没有 SendInput 的情况下模拟输入?

SendInput 在输入堆栈的底层运行。它只是进入键盘和鼠标驱动程序用来告诉窗口管理器用户已生成输入的相同输入机制的后门。SendInput 函数不知道输入会发生什么。这由窗口管理器的更高级别处理,例如命中测试鼠标输入以查看消息最初应传递到哪个窗口的组件。

他还在另一篇博客文章中发布了一个漂亮的小图表,显示SendInput()了与输入队列相关的位置:

当某些东西被添加到队列中时,它需要一些时间才能排在队列的前面

图表

于 2015-01-08T18:08:14.127 回答