https://learn.microsoft.com/zh-cn/windows/win32/winmsg/about-hooks
挂钩是应用程序截获消息、鼠标操作和击键等事件的机制。 截获特定类型的事件的函数称为 挂钩过程。 挂钩过程可以对其接收的每个事件执行操作,然后修改或放弃该事件。
挂钩是系统消息处理机制中的一个点,其中应用程序可以安装子例程来监视系统中的消息流量,并在某些类型的消息到达目标窗口过程之前对其进行处理。
以下一些示例使用 挂钩:
将应用程序定义的挂钩过程安装到挂钩链中。 你将安装挂钩过程来监视系统的某些类型的事件。 这些事件与特定线程或与调用线程位于同一桌面中的所有线程相关联。
HHOOK SetWindowsHookExA(
[in] int idHook,
[in] HOOKPROC lpfn,
[in] HINSTANCE hmod,
[in] DWORD dwThreadId
);
HHOOK SetWindowsHookExW(
[in] int idHook,
[in] HOOKPROC lpfn,
[in] HINSTANCE hmod,
[in] DWORD dwThreadId
);
LRESULT CALLBACK KeyboardProc(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
LRESULT CALLBACK LowLevelKeyboardProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// 其中lParam指向 KBDLLHOOKSTRUCT 结构的指针。
LRESULT CALLBACK MouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
LRESULT CALLBACK LowLevelMouseProc(
_In_ int nCode,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
// 其中lParam指向 MSLLHOOKSTRUCT 结构的指针。
删除 SetWindowsHookEx 函数安装在挂钩链中的挂钩过程。
BOOL UnhookWindowsHookEx(
[in] HHOOK hhk
);
将挂钩信息传递给当前挂钩链中的下一个挂钩过程。 挂钩过程可以在处理挂钩信息之前或之后调用此函数。
LRESULT CallNextHookEx(
[in, optional] HHOOK hhk,
[in] int nCode,
[in] WPARAM wParam,
[in] LPARAM lParam
);
包含有关低级别键盘输入事件的信息。
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
包含有关低级别鼠标输入事件的信息。
typedef struct tagMSLLHOOKSTRUCT {
POINT pt;
DWORD mouseData;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
} MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
// process event
...
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
SetWindowsHookEx 函数始终在挂钩链的开头安装挂钩过程。 当发生由特定类型的挂钩监视的事件时,系统会在与挂钩关联的挂钩链的开头调用过程。 链中的每个挂钩过程确定是否将事件传递给下一个过程。 挂钩过程通过调用 CallNextHookEx 函数将事件传递给下一过程。
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;
hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll"));
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
hhookSysMsg = SetWindowsHookEx(
WH_SYSMSGFILTER,
hkprcSysMsg,
hinstDLL,
0);
可以通过调用 UnhookWindowsHookEx 函数来释放特定于线程的挂钩过程, (从挂钩链) 中删除其地址,并指定要释放的挂钩过程的句柄。 一旦应用程序不再需要挂钩过程,就立即释放它。
#include "pch.h"
#include <Windows.h>
#include <iostream>
std::string get_time()
{
SYSTEMTIME sys;
GetLocalTime(&sys);
char time[255] = { 0 };
sprintf_s(time, "[%4d/%02d/%02d %02d:%02d:%02d]", sys.wYear, sys.wMonth, sys.wDay, sys.wHour, sys.wMinute, sys.wSecond);
return std::string(time);
}
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
/*
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode; // 按键代号
DWORD scanCode; // 硬件扫描代号,同 vkCode 也可以作为按键的代号。
DWORD flags; // 事件类型,一般按键按下为 0 抬起为 128。
DWORD time; // 消息时间戳
ULONG_PTR dwExtraInfo; // 消息附加信息,一般为 0。
}KBDLLHOOKSTRUCT,*LPKBDLLHOOKSTRUCT,*PKBDLLHOOKSTRUCT;
*/
KBDLLHOOKSTRUCT* ks = (KBDLLHOOKSTRUCT*)lParam; // 包含低级键盘输入事件信息
char buffer[255];
DWORD code = ks->vkCode;
std::string t = get_time();
char state[20];
if (wParam == WM_KEYDOWN)
{
strcpy_s(state, "按下");
}
else if (wParam == WM_KEYUP)
{
strcpy_s(state, "抬起");
}
sprintf_s(buffer, "[键盘]%s 键代码:%d %s", t.c_str(), code, state);
std::cout << buffer << std::endl;
//return 1; // 拦截消息
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
/*
typedef struct tagMOUSEHOOKSTRUCT {
POINT pt; // Point数据
HWND hwnd; // 接收鼠标消息的窗体的句柄
UINT wHitTestCode; // 指定点击测试值
ULONG_PTR dwExtraInfo; // 指定和该消息相关联的附加信息。
} MOUSEHOOKSTRUCT, FAR* LPMOUSEHOOKSTRUCT, * PMOUSEHOOKSTRUCT;
*/
MOUSEHOOKSTRUCT* ms = (MOUSEHOOKSTRUCT*)lParam;
POINT pt = ms->pt;
std::string time = get_time();
char buffer[1024];
char state[20] = "未知";
if (wParam == WM_LBUTTONDOWN)
{
strcpy_s(state, "左键按下");
}
else if (wParam == WM_LBUTTONUP)
{
strcpy_s(state, "左键抬起");
}
else if (wParam == WM_RBUTTONDOWN)
{
strcpy_s(state, "右键按下");
}
else if (wParam == WM_RBUTTONUP)
{
strcpy_s(state, "右键抬起");
}
else if (wParam == WM_MOUSEMOVE)
{
strcpy_s(state, "移动");
}
sprintf_s(buffer, "[鼠标]%s 键代码:x:%d y:%d %s", time.c_str(), pt.x, pt.y, state);
std::cout << buffer << std::endl;
//return 1; // 拦截消息
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main()
{
HINSTANCE hM = GetModuleHandle(NULL), hK = GetModuleHandle(NULL);
HHOOK g_Hook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, hK, 0);
HHOOK g_Hook2 = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, hM, 0);
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(g_Hook);
return 0;
}
如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;
╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地
//(ㄒoㄒ)//,就在评论处留言,作者继续改进;
o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;
(????)
感谢各位大佬童鞋们的支持!
( ′ ▽′ )ノ ( ′ ▽′)っ!!!