Windows的"Safely Remove Hardware"对话框如何获得"foreground love"?



Raymond 在博客上写了关于程序如何使用 RegisterHotkey 来获取/窃取"前景之爱"的博客,当调用时,会将前景转移到您的应用程序。

手动执行此操作的尝试会惨遭失败(例如,使用 SetForegroundWindowSwitchToWindow 等(,因为应用程序一定无法从用户那里窃取焦点(这样按键就不会转到错误的位置(。

问题是,今天我注意到了一些奇怪的事情:

  1. 我尝试安全删除外部驱动器。

  2. 有 ~7 秒的停顿。

  3. 在暂停期间,我在窗口内大力打字。

  4. 突然,一个消息框从我的
  5. 应用程序中窃取了前景,我的键入内容改为进入消息框。

显然,这不是使用热键机制 - 然而,Windows能够从我的应用程序中窃取焦点。

真的怀疑是否有类似"后门"之类的东西仅用于此特定目的(尽管如果我错了,请纠正我(,因此,假设情况并非如此,必须有一种方法可以正确执行此操作,而无需使用热键机制。

那么问题来了,这是怎么做到的?

注意:

汉斯指出"后门"是AttachInputThread,但我真的不相信这就是这里发生的事情 - 特别是因为雷蒙德说这种方法会导致挂起。想法?

我已经做了一些实验,从我所看到的,当且仅当新窗口属于 Windows 资源管理器时,才会发生这种情况。 例如,某些控制面板在资源管理器中实现或作为资源管理器插件实现。 我可以通过从"开始"菜单打开"操作中心"(将"开始"菜单配置为在菜单中显示控制面板项(来最轻松地重现它。

因此,我怀疑这种行为是Windows资源管理器拥有桌面窗口的结果,GUI将其视为特殊情况。

唯一有点奇怪的是,我无法使用您正在谈论的 USB 对话框重现这种行为,该对话框(当我尝试时(是由一个单独的进程(rundll32.exe 的实例(生成的。 不过,这可能取决于其他因素。

我想

不出一种不比我现在有时间更复杂的方法来测试它,但仔细查看 SetForegroundWindow 文档,http://msdn.microsoft.com/en-us/library/ms633539(VS.85(.aspx ,备注下列出的有关可以设置前景的进程的条件之一是:

  • 进程收到最后一个输入事件。

除非我弄错了,否则Windows资源管理器接收所有输入事件,以检查热键,其他此类焦点窃取按键以及当前窗口边界之外的鼠标单击等。

由于其永久的"收到最后一个输入事件"状态,资源管理器有资格设置为可以设置前台的东西,因此可以使它导致的消息框显示为前台,而没有任何特殊功能或未记录的行为。

如前所述,不同线程的窗口的输入是独立处理的。 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");

另请参阅:源代码片段,二进制

最新更新