✨博客主页:何曾参静谧的博客
📌文章专栏:「Win」Windows程序设计
相关术语
HOOK技术:
是一种在Windows系统中常用的技术,它可以截获并修改操作系统或应用程序的行为。通过使用Hook技术,我们可以实现以下功能:
- 监视和记录系统和应用程序的行为。
- 修改系统和应用程序的行为,以满足特定需求。
- 在系统和应用程序的行为发生时,执行自定义代码。
全局钩子(Global Hook):
是指在整个系统中
安装的钩子。全局钩子可以截获并修改所有应用程序的行为。全局钩子通常用于实现系统级别的功能,如监视和记录用户输入、拦截和修改系统消息等。
局部钩子(Local Hook):
是指在特定应用程序中
安装的钩子。局部钩子只能截获并修改特定应用程序的行为。局部钩子通常用于实现应用程序级别的功能,如拦截和修改应用程序消息、增强用户体验等。(在使用时需要指定应用程序的句柄)
钩子类型 | 对应ID |
---|---|
消息钩子 | WH_GETMESSAGE(全局) |
键盘钩子 | WH_KEYBOARD(局部) WH_KEYBOARD_LL(全局) |
鼠标钩子 | WH_MOUSE(局部) WH_MOUSE_LL(全局) |
线程钩子 | WH_CALLWNDPROC(全局) |
进程钩子 | WH_CBT(全局) |
一、全局钩子和局部钩子
#include <Windows.h>
#include <iostream>using namespace std;// 全局钩子回调函数
LRESULT CALLBACK GlobalKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode == HC_ACTION){KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN){// 按下键盘键cout << "Global Key down: " << pKeyboard->vkCode << endl;}else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP){// 松开键盘键cout << "Global Key up: " << pKeyboard->vkCode << endl;}}return CallNextHookEx(NULL, nCode, wParam, lParam);
}// 局部钩子回调函数
LRESULT CALLBACK LocalKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode == HC_ACTION){KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN){// 按下键盘键cout << "Local Key down: " << pKeyboard->vkCode << endl;}else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP){// 松开键盘键cout << "Local Key up: " << pKeyboard->vkCode << endl;}}return CallNextHookEx(NULL, nCode, wParam, lParam);
}int main()
{// 安装全局钩子HHOOK hGlobalHook = SetWindowsHookEx(WH_KEYBOARD_LL, GlobalKeyboardProc, GetModuleHandle(NULL), 0);// 安装局部钩子HHOOK hLocalHook = SetWindowsHookEx(WH_KEYBOARD, LocalKeyboardProc, GetModuleHandle(NULL), GetCurrentThreadId());// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}// 卸载全局钩子和局部钩子UnhookWindowsHookEx(hGlobalHook);UnhookWindowsHookEx(hLocalHook);return 0;
}
二、消息钩子
实现现一个消息钩子回调函数
MessageProc
,用于拦截窗口消息。然后,在main
函数中,我们使用SetWindowsHookEx
函数安装了一个 WH_GETMESSAGE 消息钩子,并在消息循环中等待消息的到来。在消息钩子回调函数中,我们判断收到的消息是否为键盘消息,如果是则打印出消息类型。最后,在消息循环结束时,我们调用UnhookWindowsHookEx
函数卸载消息钩子。
#include <Windows.h>
#include <iostream>using namespace std;// 消息钩子回调函数
LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode == HC_ACTION){MSG* pMsg = (MSG*)lParam;if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP){// 拦截键盘消息cout << "Message Hook: " << pMsg->message << endl;}}return CallNextHookEx(NULL, nCode, wParam, lParam);
}int main()
{// 安装消息钩子HHOOK hHook = SetWindowsHookEx(WH_GETMESSAGE, MessageProc, GetModuleHandle(NULL), 0);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}// 卸载消息钩子UnhookWindowsHookEx(hHook);return 0;
}
三、键盘钩子
首先定义了一个全局的键盘钩子句柄
g_hHook
,并在main
函数中通过SetWindowsHookEx
函数安装了一个全局键盘钩子。然后,在键盘钩子回调函数KeyboardProc
中,我们捕获并处理了键盘事件,并在控制台上显示了按下或松开的键盘键。最后,在消息循环结束时,我们调用UnhookWindowsHookEx
函数卸载全局键盘钩子。
#include <Windows.h>
#include <iostream>using namespace std;// 定义全局的键盘钩子句柄
HHOOK g_hHook = NULL;// 键盘钩子回调函数
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode == HC_ACTION){KBDLLHOOKSTRUCT* pKeyboard = (KBDLLHOOKSTRUCT*)lParam;if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN){// 按下键盘键cout << "Key down: " << pKeyboard->vkCode << endl;}else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP){// 松开键盘键cout << "Key up: " << pKeyboard->vkCode << endl;}}return CallNextHookEx(g_hHook, nCode, wParam, lParam);
}int main()
{// 安装全局键盘钩子g_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardProc, GetModuleHandle(NULL), 0);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}// 卸载全局键盘钩子UnhookWindowsHookEx(g_hHook);return 0;
}
四、鼠标钩子
代码实现了一个鼠标钩子回调函数
MouseProc
,用于拦截鼠标事件。然后,在main
函数中,我们使用SetWindowsHookEx
函数安装了一个WH_MOUSE_LL
鼠标钩子,并在消息循环中等待消息的到来。在鼠标钩子回调函数中,我们判断收到的消息类型并打印出鼠标位置。最后,在消息循环结束时,我们调用UnhookWindowsHookEx
函数卸载鼠标钩子。
#include <Windows.h>
#include <iostream>using namespace std;// 鼠标钩子回调函数
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{if (nCode == HC_ACTION){MOUSEHOOKSTRUCT* pMouseStruct = (MOUSEHOOKSTRUCT*)lParam;if (wParam == WM_MOUSEMOVE){// 拦截鼠标移动事件cout << "Mouse Hook: WM_MOUSEMOVE, x=" << pMouseStruct->pt.x << ", y=" << pMouseStruct->pt.y << endl;}else if (wParam == WM_LBUTTONDOWN){// 拦截鼠标左键按下事件cout << "Mouse Hook: WM_LBUTTONDOWN, x=" << pMouseStruct->pt.x << ", y=" << pMouseStruct->pt.y << endl;}else if (wParam == WM_RBUTTONDOWN){// 拦截鼠标右键按下事件cout << "Mouse Hook: WM_RBUTTONDOWN, x=" << pMouseStruct->pt.x << ", y=" << pMouseStruct->pt.y << endl;}}return CallNextHookEx(NULL, nCode, wParam, lParam);
}int main()
{// 安装鼠标钩子HHOOK hHook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, GetModuleHandle(NULL), 0);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)){TranslateMessage(&msg);DispatchMessage(&msg);}// 卸载鼠标钩子UnhookWindowsHookEx(hHook);return 0;
}
注意事项
需要注意的是,使用消息钩子需要谨慎,因为它可以拦截窗口消息,可能会对应用程序的正常运行产生影响。因此,在使用消息钩子时,应该根据实际需求选择合适的钩子类型,并谨慎对待其中的风险和安全问题。