无法设置WH_KEYBOARD挂钩。 WH_KEYBOARD_LL有效

时间:2017-09-17 05:04:13

标签: winapi

这是适用于我的WH_KEYBOARD_LL代码。

#include <Windows.h>
#include <iostream>

using namespace std;

HHOOK _hook;
KBDLLHOOKSTRUCT kbdStruct;
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam) {
    cout << nCode;
    return CallNextHookEx(_hook, nCode, wParam, lParam);
}

void SetHook() {
    if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0))) {
        cout << "SetWindowsHookEx Fail";
    }
}

void ReleaseHook() {
    UnhookWindowsHookEx(_hook);
}

int main() {
    SetHook();

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        // do something here
    }
    return 0;
}

但是,当我将SetWindowsHookEx行更改为if (!(_hook = SetWindowsHookEx(WH_KEYBOARD, HookCallback, NULL, GetCurrentThreadId())))时,它不起作用。

我有3个问题。

  1. 如何让WH_KEYBOARD挂机工作?

  2. 如果我用cout替换循环内的注释,我就看不到任何控制台输出。所以我很困惑,循环的主体是否完全执行?

  3. 我还在GetMessage的循环中读到,我应该添加对DispatchMessage的调用。 DispatchMessageCallNextHookEx之间的区别是什么?我阅读了关于它们的文档,但无法理解。

2 个答案:

答案 0 :(得分:1)

GetMessage()永远不会返回,因为如果没有与进程关联的窗口句柄,则没有关联的消息队列,也不会发生消息处理魔法(除非您手动发布消息)。这很疯狂,但我想它解释了操作系统的名称。引自GetMessage()

  

GetMessage函数检索与窗口关联的消息   由hWnd参数或其任何子项

标识

您可以WH_KEYBOARD_LL工作,因为无论GetMessage()如何都会调用它。您不会接听WH_KEYBOARD次来电,因为仅在GetMessage()正常运作时才会调用。

引自Hooks Overview

  

<强> WH_KEYBOARD_LL

     

WH_KEYBOARD_LL挂钩使您可以监视键盘输入事件   即将发布在线程输入队列中。有关更多信息,请参阅   LowLevelKeyboardProc回调函数。

     

<强> WH_KEYBOARD

     

WH_KEYBOARD挂钩使应用程序能够监控消息流量   对于要返回的WM_KEYDOWN和WM_KEYUP消息   GetMessage或PeekMessage函数。您可以使用WH_KEYBOARD钩子   监控发布到消息队列的键盘输入

Q&安培; A:

  

如何让WH_KEYBOARD挂钩工作?

您需要创建一个窗口。即使是消息框也可以。甚至隐藏。

  

如果我用循环替换循环内的注释,我就不会看到任何控制台输出。所以我很困惑,循环的身体   执行完毕?

没有。因为GetMessage()永远阻止。因为没有收到的消息。

  

我还读到了在GetMessage循环中,我应该添加对DispatchMessage的调用。 DispatchMessage和CallNextHookEx之间的区别是什么?我阅读了关于他们两个的文档,但无法理解。

这两个功能是正交的。

使用GetMessage()从队列中删除邮件后,您需要调用DispatchMessage()将邮件传递给与该窗口关联的WindowProc。否则WindowProc没有收到它。

如果安装了多个挂钩,

CallNextHookEx会将消息传递给链中的下一个挂钩。

<子> 的此外:

<子>  (1)您不应将_hook传递给CallNextHookEx。无论如何,第一个参数被忽略。传递钩柄只是令人困惑。

<子>  (2)您应该始终执行适当的错误检查。

<子>  (3)不要忘记解开钩子。

答案 1 :(得分:1)

根据KeyboardProc callback function文档:

  

SetWindowsHookEx函数一起使用的应用程序定义或库定义的回调函数。 只要应用程序调用{​​{1}}或GetMessage函数并且有待处理的键盘消息(PeekMessageWM_KEYUP),系统就会调用此函数

您的WM_KEYDOWN回调无法正常工作,因为挂钩的线程正在调用WH_KEYBOARD但未收到任何GetMessage()WM_KEYUP条消息。这些是窗口消息,但是没有可视窗口供他们发布。

WM_KEYDOWN挂钩在较低级别运行,因此不需要挂钩线程调用WH_KEYBOARD_LL来接收窗口消息。根据{{​​3}}文档:

  

(Get|Peek)Message()函数一起使用的应用程序定义或库定义的回调函数。 每次新的键盘输入事件即将发布到线程输入队列时,系统都会调用此函数。