活动窗口更改时收到通知

Posted

技术标签:

【中文标题】活动窗口更改时收到通知【英文标题】:Getting notification when active window changes 【发布时间】:2017-06-09 12:21:48 【问题描述】:

我试图让我的程序在焦点更改时获取当前活动窗口标题。我有以下回调:

LRESULT CALLBACK windowChangeHook(int nCode, WPARAM wParam, LPARAM lParam)

    if (wParam == HCBT_SETFOCUS || lParam == HCBT_SETFOCUS)
        cout << GetActiveWindowTitle();

    return(CallNextHookEx(NULL, nCode, wParam, lParam));

我正在尝试按如下方式挂钩 WH_CBT:

HHOOK hhkWindowChange = SetWindowsHookEx(WH_CBT, windowChangeHook, 0, 0);

也许我只是愚蠢,但它没有按预期工作,有人知道为什么吗?

编辑: 程序似乎根本没有检测到窗口更改,我尝试将代码更改为此无济于事:

LRESULT CALLBACK windowChangeHook(int nCode, WPARAM wParam, LPARAM lParam)

    if (nCode == HCBT_ACTIVATE || nCode == HCBT_SETFOCUS)
        cout << "TEST";

    return(CallNextHookEx(NULL, nCode, wParam, lParam));

【问题讨论】:

"...但它没有按预期工作.." 什么不工作:钩子的设置;钩子被调用;没有检测到焦点变化?如果您想检测不属于您的应用程序的窗口,您是否需要在 DLL 中实现挂钩? 抱歉,Richard 应该更具体一些,它似乎没有检测到窗口变化。 当然不是。您正在猜测如何使用 API。那是行不通的。阅读documentation。 【参考方案1】:

你没有检查来自SetWindowsHookEx的返回值!

windowChangeHook 需要在一个 DLL 中,其 HMODULEhMod 参数中。

HCBT_* 值在 nCode 参数中传递!

您也可以尝试改用SetWinEventHook...

【讨论】:

【参考方案2】:

您没有正确处理WH_CBT 回调。

根据CBTProc callback function 文档:

nCode [输入] 类型:整数

钩子程序用来确定如何处理消息的代码。如果nCode小于零,钩子程序必须将消息传递给CallNextHookEx函数而不做进一步处理并且应该返回CallNextHookEx 返回的值。此参数可以是以下值之一。

...

HCBT_SETFOCUS 9 一个窗口即将获得键盘焦点。

wParam [输入] 类型:WPARAM

取决于nCode 参数。详情请参阅以下备注部分。

lParam [输入] 类型:LPARAM

取决于nCode 参数。有关详细信息,请参阅以下备注部分。

下表描述了每个HCBT_ 挂钩代码的wParamlParam 参数。

...

HCBT_SETFOCUS wParam:指定获得键盘焦点的窗口句柄。 lParam:指定失去键盘焦点的窗口句柄。

您正在寻找错误参数中的HCBT_SETFOCUS 值。您还在检索错误窗口的标题,因为输入焦点实际上还没有切换窗口。

您的回调应该看起来更像这样(假设您的回调是在 DLL 中实现的,这是检测全局事件所必需的,这也意味着您需要在 64 位系统上使用单独的 32 位和 64 位 DLL。这在 @ 987654322@文档):

LRESULT CALLBACK windowChangeHook(int nCode, WPARAM wParam, LPARAM lParam)

    if (nCode == HCBT_SETFOCUS)
    
        HWND hwnd = (HWND) wParam;
        // retreive and use the title of hwnd as needed...
    

    return CallNextHookEx(NULL, nCode, wParam, lParam);

话虽如此,您应该考虑改用SetWinEventHook(),如果您使用“上下文外”钩子,则它没有DLL要求:

回调函数没有映射到产生事件的进程的地址空间。因为钩子函数是跨进程边界调用的,所以系统必须对事件进行排队。尽管此方法是异步的,但可以保证事件是按顺序排列的。如需更多信息,请参阅Out-of-Context Hook Functions。

EVENT_OBJECT_FOCUS 0x8005

对象已获得键盘焦点。系统为以下用户界面元素发送此事件:列表视图控件、菜单栏、弹出菜单、切换窗口、选项卡控件、树视图控件和窗口对象。服务器应用程序为其可访问对象发送此事件。

WinEventProc回调函数的hwnd参数标识接收键盘焦点的窗口

例如:

void CALLBACK windowChangeHook(HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime)

    // retreive and use the title of hwnd as needed...


HWINEVENTHOOK hEventHook = SetWinEventHook(EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS, NULL, &windowChangeHook, 0, 0, WINEVENT_OUTOFCONTEXT);
...
UnhookWinEvent(hEventHook);

【讨论】:

以上是关于活动窗口更改时收到通知的主要内容,如果未能解决你的问题,请参考以下文章

如何在前台(顶部)活动(应用程序)更改时收到通知

如何在 Android 中的活动/任务更改时收到通知

Linux 获取有关重点 gui 窗口更改的通知

第一次通知活动显示时,第二次通知中未显示GCM通知活动

当非活动手表收到本地通知时如何触发触觉警报

在活动中存储/保存收到的推送通知[关闭]