Raymond has blogged about程序如何通过使用RegisterHotkey
获取/窃取“前景爱”,在调用时,它会将前景转移到您的应用程序。
尝试手动执行此操作失败(例如使用SetForegroundWindow
,SwitchToWindow
等),因为应用程序必须无法从用户那里窃取焦点(因此按键不会到了错误的地方)。
麻烦的是,今天我发现了一些奇怪的事情:
我尝试安全删除外置硬盘。
暂停约7秒钟。
暂停期间,我正在窗口内大力打字。
突然,一个消息框从我的应用程序窃取了前景 - 而我的输入则进入了消息框。
显然,这不是使用热键机制 - 然而,Windows能够从我的应用程序中窃取焦点。
我真的怀疑有什么像“后门”只是为了这个特殊目的而使用(虽然如果我错了请纠正我),所以,假设情况并非如此,那么必须要有办法正确地执行此操作,不使用使用热键机制。
所以问题是,这是如何实现的?
汉斯指出,“后门”是AttachInputThread
,但我并不是真的相信这里发生了什么 - 特别是自Raymond says that method can cause hangs以来。想法?
答案 0 :(得分:1)
我做了一些实验,从我所看到的情况发生这种情况,当且仅当新窗口属于Windows资源管理器时才会发生。例如,某些控制面板在Explorer中或作为Explorer插件实现。通过从“开始”菜单打开“操作中心”(配置“开始”菜单以在菜单中显示“控制面板”项目),我可以轻松地重现它。
我怀疑,这种行为是因为Windows资源管理器拥有桌面窗口这一事实的结果,GUI将其视为一种特殊情况。
唯一有点奇怪的是,我无法使用您正在讨论的USB对话重现此行为,(当我尝试它时)是由一个单独的进程(一个实例)生成的of rundll32.exe)。但这可能取决于其他因素。
答案 1 :(得分:1)
我想不出一种方法来测试这个并不比我现在有时间复杂,但仔细查看SetForegroundWindow文档,http://msdn.microsoft.com/en-us/library/ms633539(VS.85).aspx,备注下列出的条件之一关于可以设置前景的进程是:
除非我弄错了,否则Windows资源管理器会收到所有输入事件,以检查热键,其他此类焦点窃听按键,以及当前窗口范围之外的鼠标点击等。
由于它的永久“收到最后一个输入事件”状态,资源管理器有资格作为可以设置前景的东西,因此可以导致它导致显示为没有任何特殊功能或未记录的行为的前景的消息框。
答案 2 :(得分:0)
如前所述,不同线程的窗口输入是独立处理的。 AttachThreadInput
API允许共享线程状态,特别是:
通过使用AttachThreadInput函数,线程可以附加其输入 处理机制到另一个线程。 [...]这也允许线程 分享他们的输入状态,以便他们可以调用SetFocus函数 将键盘焦点设置为不同线程的窗口。
现在,当您看到当前处于前景的窗口时,如果您与前台窗口线程共享线程状态,则SetFocus
将从那里窃取焦点。
CWindow Window = GetForegroundWindow();
if(Window)
{
const DWORD nWindowThreadIdentifier = Window.GetWindowThreadID();
const DWORD nThreadIdentifier = GetCurrentThreadId();
AttachThreadInput(nThreadIdentifier, nWindowThreadIdentifier, TRUE);
GetDlgItem(IDC_EDIT).SetFocus(); // This succeeds now as we are sharing thread state with foreground window
AttachThreadInput(nThreadIdentifier, nWindowThreadIdentifier, FALSE);
m_sAction = _T("Done");
} else
m_sAction = _T("Nothing to do");