我创建了一个小程序,可以在新桌面上启动。
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);
...
因此,桌面DEFAULT上的应用程序A
基本上是在桌面X上启动应用程序B
,它获取在同一桌面X上启动的另一个应用程序C
的HWND。
我的问题是来自桌面X上的应用程序B
的键盘事件未在应用程序C
中触发。只有当我使用SwitchDesktop(B)
时,才会触发事件并正确执行代码。
我错过了什么?
答案 0 :(得分:7)
您正试图在物理控制台(屏幕,鼠标,键盘)上未激活的桌面上模拟用户输入,这可能不起作用,以及SwitchDesktop()
使其工作的原因。根据文件:
使指定的桌面可见并激活它。 这使桌面能够接收用户的输入。
keybd_event()
,mouse_event()
,SendInput()
,它们都只是生成输入消息并将其存储到物理鼠标/键盘发布消息的同一输入队列中。在将输入消息分派给应用程序时,输入系统不知道用户输入和合成输入之间的区别。
Raymond Chen在他的博客中谈到了这一点:
How do I simulate input without SendInput?
SendInput在输入堆栈的底层运行。 这只是键盘和鼠标驱动程序用来告诉窗口管理器用户已生成输入的相同输入机制的后门。 SendInput函数不知道输入会发生什么。这是由更高级别的窗口管理器处理的,就像点击测试鼠标输入以查看消息最初应该传递到哪个窗口的组件一样。
他还在另一篇博客文章中发布了一个漂亮的小图,显示了SendInput()
与输入队列相关的位置:
When something gets added to a queue, it takes time for it to come out the front of the queue