CWinHook.h
#pragma once
#include <windows.h>
class CWinHook
{
public:
CWinHook();
~CWinHook();
// WH_CALLWNDPROC
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nc-winuser-hookproc
// 安装一个挂钩过程,用于在系统将消息发送到目标窗口过程之前监视消息
static LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_CALLWNDPROCRET
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/api/winuser/nc-winuser-hookproc
// 安装一个挂钩过程,该过程在目标窗口过程处理消息后监视消息
static LRESULT CALLBACK CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_CBT
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/cbtproc
// 安装用于接收对 CBT 应用程序有用的通知的挂钩过程
static LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_DEBUG
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/debugproc
// 安装可用于调试其他挂钩过程的挂钩过程
static LRESULT CALLBACK DebugProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_SHELL
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/debugproc
// 安装一个挂钩过程,用于接收对 shell 应用程序有用的通知
static LRESULT CALLBACK ShellProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_FOREGROUNDIDLE
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/foregroundidleproc
// 安装将在应用程序的前台线程变为空闲状态时调用的挂钩过程。 此挂钩可用于在空闲时间执行低优先级任务
static LRESULT CALLBACK ForegroundIdleProc(int nCode, DWORD wParam, LONG lParam);
// WH_GETMESSAGE
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/getmsgproc
// 每当 GetMessage 或 PeekMessage 函数从应用程序消息队列中检索消息时,系统都调用此函数
// GetMsgProc 钩子过程可以查看或修改消息
static LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_KEYBOARD
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/keyboardproc
// 安装用于监视击键消息的挂钩过程
static LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_KEYBOARD_LL
// 仅限全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/keyboardproc
// 安装用于监视击键消息的挂钩过程
static LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_MOUSE
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/messageproc
// 安装监视鼠标消息的挂钩过程
static LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_MOUSE_LL
// 仅限全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/messageproc
// 安装用于监视低级别鼠标输入事件的挂钩过程
static LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_MSGFILTER
// 线程或全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/messageproc
// 安装用于监视低级别鼠标输入事件的挂钩过程
static LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam);
// WH_SYSMSGFILTER
// 仅限全局
// https://learn.microsoft.com/zh-cn/windows/win32/winmsg/sysmsgproc
// 安装用于监视低级别鼠标输入事件的挂钩过程
static LRESULT CALLBACK SysMsgProc(int nCode, WPARAM wParam, LPARAM lParam);
private:
static HHOOK m_hHook; //钩子句柄
};
CWinHook.cpp
#include "CWinHook.h"
HHOOK CWinHook::m_hHook;
CWinHook::CWinHook()
{
}
CWinHook::~CWinHook()
{
}
LRESULT CALLBACK CWinHook::CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 指定消息是否由当前进程发送
BOOL fCurThreadSend = wParam;
// 有关消息的详细信息
LPCWPSTRUCT pStruct = (LPCWPSTRUCT)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::CallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 指定消息是否由当前进程发送
BOOL fCurThreadSend = wParam;
// 有关消息的详细信息
LPCWPRETSTRUCT pStruct = (LPCWPRETSTRUCT)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 即将移动窗口或调整其大小
if(HCBT_MOVESIZE == nCode)
{
//指定要移动或调整大小的窗口的句柄
HWND hWnd = (HWND)wParam;
LPRECT pRect = (LPRECT)lParam;
}
// 窗口即将最小化或最大化
if(HCBT_MINMAX == nCode)
{
//指定要最小化或最大化的窗口的句柄
HWND hWnd = (HWND)wParam;
int nCmdShow = lParam;
}
// 系统已从 系统消息队列 中检索WM_QUEUESYNC消息,将忽略返回值
if(HCBT_QS == nCode)
{
}
// 即将创建一个窗口
if (HCBT_CREATEWND == nCode)
{
//指定新窗口的句柄
HWND hWndNew = (HWND)wParam;
LPCBT_CREATEWND pStruct = (LPCBT_CREATEWND)lParam;
}
// 一个窗口即将被销毁
if (HCBT_DESTROYWND == nCode)
{
//指定要销毁的窗口的句柄
HWND hWndDestroy = (HWND)wParam;
}
// 系统即将激活窗口
if (HCBT_ACTIVATE == nCode)
{
//指定要激活的窗口的句柄
HWND hWndActivate = (HWND)wParam;
LPCBTACTIVATESTRUCT pStruct = (LPCBTACTIVATESTRUCT)lParam;
}
// 系统已从系统消息队列中删除鼠标消息,将忽略返回值
if (HCBT_CLICKSKIPPED == nCode)
{
}
// 系统已从系统消息队列中删除键盘消息,将忽略返回值
if (HCBT_KEYSKIPPED == nCode)
{
WORD wVk = wParam;
}
// 即将执行系统命令
if (HCBT_SYSCOMMAND == nCode)
{
}
// 窗口即将接收键盘焦点
if (HCBT_SETFOCUS == nCode)
{
HWND hWndFocusGaining = (HWND)wParam;
HWND hWndFocusLosing = (HWND)lParam;
}
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::DebugProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 即将调用的挂钩类型
int idHook = wParam;
// 要传递给目标挂钩过程的参数
LPDEBUGHOOKINFO pStruct = (LPDEBUGHOOKINFO)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 已创建顶级的无所有者窗口。
if (HSHELL_WINDOWCREATED == nCode)
{
}
// 一个顶级的、无所有者的窗口即将被销毁。
if (HSHELL_WINDOWDESTROYED == nCode)
{
}
// shell 应激活其main窗口
if (HSHELL_ACTIVATESHELLWINDOW == nCode)
{
}
// 激活已更改为其他顶级的无所有者窗口
if (HSHELL_WINDOWACTIVATED == nCode)
{
HWND hWnd = (HWND)wParam;
BOOL fFullScreen = lParam;
}
// 窗口正在最小化或最大化。 系统需要窗口的最小化矩形的坐标
if (HSHELL_GETMINRECT == nCode)
{
HWND hWnd = (HWND)wParam;
LPRECT pRect = (LPRECT)lParam;
}
// 任务栏中窗口的标题已重绘
if (HSHELL_REDRAW == nCode)
{
HWND hWnd = (HWND)wParam;
BOOL fFlashing = lParam;
}
// 用户已选择任务列表
if (HSHELL_TASKMAN == nCode)
{
}
// 键盘语言已更改或加载了新的键盘布局
if (HSHELL_LANGUAGE == nCode)
{
HWND hWnd = (HWND)wParam;
}
//
if (HSHELL_SYSMENU == nCode)
{
}
if (HSHELL_ENDTASK == nCode)
{
}
// 辅助功能状态已更改
if (HSHELL_ACCESSIBILITYSTATE == nCode)
{
}
// 用户完成了输入事件
if (HSHELL_APPCOMMAND == nCode)
{
HWND hWnd = (HWND)wParam;
}
// 正在替换顶级窗口
if (HSHELL_WINDOWREPLACED == nCode)
{
HWND hWnd = (HWND)wParam;
HWND hWndNew = (HWND)lParam;
}
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::ForegroundIdleProc(int nCode, DWORD wParam, LONG lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 消息尚未从队列中删除
if (PM_NOREMOVE == wParam)
{
}
// 消息已从队列中删除
if (PM_REMOVE == wParam)
{
}
LPMSG pMsg = (LPMSG)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
WORD wVkCode = wParam;
// https://learn.microsoft.com/zh-cn/windows/win32/inputdev/about-keyboard-input
typedef struct _KEYSTATUS
{
DWORD wRepeat : 16; //重复计数, 该值是用户按住键后重复击键的次数
DWORD wScan : 8; //扫描代码, 此值取决于 OEM
DWORD fExtended : 1; //指示键是扩展键,例如功能键还是数字键盘上的键。 如果键是扩展键,则值为 1;否则为 0
DWORD Reserved : 4; //保留
DWORD fContext : 1; //上下文代码。 如果 Alt 键关闭,则值为 1;否则为 0
DWORD fPrevious : 1; //上一个键状态。 如果在发送消息之前键关闭,则值为 1;如果键已打开,则为 0
DWORD fTransition : 1; //转换状态。 如果按下键,则值为 0;如果释放键,则值为 1
}KEYSTATUS;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
switch (wParam)
{
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
break;
}
LPKBDLLHOOKSTRUCT pStruct = (LPKBDLLHOOKSTRUCT)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// wParam 和 lParam 参数包含有关鼠标消息的信息,并且鼠标消息尚未从消息队列中删除
if (HC_NOREMOVE == nCode)
{
}
LPMOUSEHOOKSTRUCT pStruct = (LPMOUSEHOOKSTRUCT)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
switch (wParam)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MBUTTONUP:
case WM_RBUTTONDOWN:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
break;
}
LPMSLLHOOKSTRUCT pStruct = (LPMSLLHOOKSTRUCT)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 当动态数据交换管理库 (DDEML) 等待同步事务完成时发生输入事件
if (MSGF_DDEMGR == nCode)
{
}
// 输入事件发生在消息框或对话框中
if (MSGF_DIALOGBOX == nCode)
{
}
// 输入事件发生在菜单中
if (MSGF_MENU == nCode)
{
}
// 输入事件发生在滚动条中
if (MSGF_SCROLLBAR == nCode)
{
}
UNREFERENCED_PARAMETER(wParam);
LPMSG pMsg = (LPMSG)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
LRESULT CALLBACK CWinHook::SysMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < HC_ACTION)
{
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}
// 输入事件发生在消息框或对话框中
if (MSGF_DIALOGBOX == nCode)
{
}
// 输入事件发生在菜单中
if (MSGF_MENU == nCode)
{
}
// 输入事件发生在滚动条中
if (MSGF_SCROLLBAR == nCode)
{
}
UNREFERENCED_PARAMETER(wParam);
LPMSG pMsg = (LPMSG)lParam;
return ::CallNextHookEx(m_hHook, nCode, wParam, lParam);
}