.NET/Win32 - 检测属于另一个应用程序的窗口何时获得焦点的事件

Posted

技术标签:

【中文标题】.NET/Win32 - 检测属于另一个应用程序的窗口何时获得焦点的事件【英文标题】:.NET/Win32 - event to detect when a window belonging to another app gets focus 【发布时间】:2011-08-22 17:02:42 【问题描述】:

我有一个 .NET 应用程序,它需要能够检测特定窗口何时获得和失去焦点。我感兴趣的特定窗口属于另一个我无法控制的应用程序,尽管我确实有窗口句柄。

我真的在寻找解决这个问题的最佳方法。到目前为止,我可以看到两种可能性:

    在计时器上使用 Win32 调用来监视状态的任何变化。不太好,因为它存在丢失状态更改的风险,例如如果窗口变为活动状态,则在计时器间隔内不活动 使用钩子 (SetWindowsHookEx) 拦截到窗口的消息。听起来它应该可以工作,但担心 a) 全局级别的钩子不能在 .NET 代码中工作,所以需要是本地的,b) 这可能被认为是病毒/键盘记录器类型的活动,因此被操作系统阻止了吗?李>

我相信还有其他选择,如果有的话,我很想听听!

【问题讨论】:

【参考方案1】:

最简单的方法可能是使用SetWinEventHook,监听EVENT_SYSTEM_FOREGROUND 事件。您需要将它与 WINEVENT_OUTOFCONTEXT 标志一起使用以在 .net 中使用它:当您使用此标志时,Windows 会将通知路由回您自己的进程,因此您不需要单独的非托管 DLL。但请注意,调用此方法的代码必须运行消息循环。

快速说明这与另一个答案中提到的文章有何关系:该文章侧重于 SetWindowsHook API。 SetWinEventHook 是一个单独的 API,但您使用相同的技术来设置 P/Invoke 调用,并为回调设置委托 - 但请注意,这两个 API 在 API 调用本身和回调中使用不同的参数. SetWinEventHook 相对于 SetWindowsHook 的主要优势在于,对于某些类型的挂钩,SetWindowsHook 需要使用单独的非托管 DLL,而您不能直接在 .net 中执行此操作。然而,SetWinEventHook 允许任一类型的回调,使用单独的非托管 DLL 或通知原始进程而不需要 DLL,因此对 .net 更友好。

【讨论】:

完美——这几乎正是我想要的。似乎存在一种极端情况,即(有时)最大化先前最小化的窗口不会为该窗口触发 EVENT_SYSTEM_FOREGROUND - 因此监听 EVENT_SYSTEM_MINIMIZEEND 也可以解决这个问题。谢谢,很棒的答案 消息循环约束对我来说不是问题,因为我正在运行 WPF 应用程序。对于任何想要做同样事情的人,但使用控制台应用程序(默认情况下没有消息循环),这篇文章很好(如果链接断开,请搜索“处理控制台应用程序中的消息”“Stephen Toub”)-msdn.microsoft.com/en-us/magazine/cc163417.aspx跨度> 【参考方案2】:

这是一篇来自 MSDN 杂志的关于在 .NET 中实现 windows 挂钩的精彩文章:Windows Hooks in the .NET Framework。

至于您的第二个问题,我从未听说过防病毒软件将这些 api 调用检测为间谍软件行为。

希望对你有帮助!

【讨论】:

以上是关于.NET/Win32 - 检测属于另一个应用程序的窗口何时获得焦点的事件的主要内容,如果未能解决你的问题,请参考以下文章

如何检测在另一个进程中弹出的消息框?

检测目标程序ELF bit是32还是64

用于检测系统是 32 位还是 64 位的 Shell 脚本 [重复]

Net-Worm/Win32.Kido.bg 病毒

Win32线程调度

Swift 检测 UICollectionViewCell 是不是被拖到另一个 UICollectionViewCell 之上