Windows的“安全删除硬件”对话框是如何获得“前台喜爱”的?

10

雷蒙德已经发表了博客文章,讲述了如何使用RegisterHotkey来获取或窃取“前台关注”,当调用时,将把焦点转移到您的应用程序。

尝试手动实现这一点会失败(例如使用SetForegroundWindowSwitchToWindow等),因为应用程序不能从用户那里窃取焦点(以便按键不会去到错误的位置)。

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

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

  2. 有一个大约7秒的暂停。

  3. 在暂停期间,我正在一个窗口里猛烈地打字。

  4. 突然,一个消息框从我的应用程序中窃取了焦点,并且我的打字进入了消息框中。

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

我真的怀疑这里有像“后门”这样的东西被用于特定目的(如果我错了,请纠正我),因此,假设不是这种情况,必须有一种方法可以正确地实现这一点,而无需使用热键机制。

因此问题是,如何完成这个过程?

注意:

Hans 指出,“后门”是AttachInputThread,但我真的不认为这是在这里发生的 -- 尤其是因为Raymond说,该方法可能导致挂起。我需要更多的想法。


我认为它是在与“安全移除驱动器”小程序交互后的宽限期内。 - Deanna
1
后门是AttachThreadInput()。 - Hans Passant
@HansPassant:哇,这真是令人惊讶……我没想到操作系统会做这样的事情。不过很有趣,谢谢你提供的信息! - user541686
@Cicada:这是一个消息框,告诉你该驱动器仍在使用中。 - user541686
@HansPassant:等一下,我刚刚看到了这篇文章。这篇文章不是说这种方法是无效的吗? - user541686
显示剩余7条评论
3个回答

1

我做了一些实验,从我的观察来看,只有当新窗口属于Windows资源管理器时才会发生这种情况。例如,某些控制面板是在资源管理器内部或作为资源管理器插件实现的。我最容易通过从开始菜单打开操作中心(将控制面板项配置为显示在菜单中)来重现它。

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

唯一稍微奇怪的是,我无法通过你所说的USB对话框来重现这种行为,而该对话框(在我尝试时)是由一个单独的进程(rundll32.exe的一个实例)生成的。不过这可能取决于其他因素。


我不认为GUI子系统将资源管理器视为特殊情况,但类似这样的事情发生也并非不可能... - user541686

1

我无法想到一种比现在更复杂的测试方法,但是仔细查看SetForegroundWindow文档http://msdn.microsoft.com/en-us/library/ms633539(VS.85).aspx,其中列出了关于可以设置前景的进程的备注条件之一是:

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

除非我弄错了,Windows资源管理器接收所有输入事件以检查热键、其他窃取焦点的按键和鼠标点击等。

由于其永久的“接收到最后一个输入事件”状态,资源管理器符合可以设置前景的内容,因此可以导致它引起的消息框成为前景,而不需要任何特殊功能或未记录的行为。


但是rundll32是从资源管理器启动的,对吗? - Harry Johnston

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");

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


这个方法是有效的吗?https://dev59.com/l2gv5IYBdhLWcg3wSe0f#z04EoYgBc1ULPQZFa3ad - user541686
1
抢占焦点本来就是无效的。Windows系统已经逐步增加了难度,使软件无法让用户选择哪个应用程序在前台运行。我宁愿选择一种不需要焦点技巧的不同方法来通知用户某些信息。 - Roman R.
所以你的意思是Windows正在进行无效行为? - user541686

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接