Hooks
本文翻译自 MSDN。
Hook 是系统消息处理机制中的一个点,在这个点上,程序可以装载一个子程序。利用这个子程序,程序可以监控消息在系统中的传输,对于某些种类的消息,还可以在这些消息被投递到窗口过程函数前先对消息做一些处理。
本文讲述了一下几个话题:
- Hooks Overview 介绍 Hook 的用途
- Using Hook 演示如何执行关联到 hook 上的任务
- Hook Reference hook 相关的 API
Hooks Overview
hook 是一种机制,程序可以利用它来拦截事件,比如消息、鼠标动作、键盘按键。拦截事件的函数被称为 hook procedure。每拦截到一个事件,hook procedure 会被调用,然后对这个事件进行修改或直接丢弃。
以下是使用 hook 的一些例子:
- 出于调试的目的监听消息;
- 用于记录、回放宏;
- 用于 help key(F1);
- 模拟鼠标和键盘输入;
- 实现 computer-based training (CBT) 程序;
注意 Hook 可能会拖慢系统,因为它会增加系统对每个消息的处理时间。你应该只在必要的时候去 hook,用完之后尽快移除它。
这一章节讨论了如下几个话题:
- Hook Chains
- Hook procedure
- Hook Types
- WH_CALLWNDPROC and WH_CALLWNDPROCRET
- WH_CBT
- WH_DEBUG
- WH_FOREGROUNDIDLE
- WH_GETMESSAGE
- WH_JOURNALPLAYBACK
- WH_JOURNALRECORD
- WH_KEYBOARD_LL
- WH_KEYBOARD
- WH_MOUSE_LL
- WH_MOUSE
- WH_MSGFILTER and WH_SYSMSGFILTER
- WH_SHELL
Hook Chains
系统提供了很多不懂类型的 hook;不同的类型用于应对不同 消息处理机制 的不同方面。例如,程序可以使用 WH_MOUSE hook 来监视鼠标消息的传递。
对于每种类型的 hook, 系统中都有一个独立的 hook 链与之对应。hook chains 是一个函数列表,每个函数都是由程序定义的 hook procedure。当与某类型 hook 相关联的消息被触发时,系统会将消息一个接一个传递到 hook chains 的每个 hook procedure 中。hook procedure 所能采取的操作决定于 hook 的类型。某些类型的 hook 中,hook procedure 只能监听消息,另外一些可以修改消息或者停止消息在 hook chain 中的传递,从而阻止消息被其它 hook procedure 或者目的窗口接收到。
Hook Procedures
为了使用某种 hook,开发者需要提供一个 hook procedure, 然后用 SetWindowHookEx 函数将它添加到 hook chain 中。hook procedure 必须按照以下格式来声明:
LRESULT CALLBACK HookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
// process event
...
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
nCode 参数, hook procedure 通过它来判断要执行哪些操作。 nCode 参数的值跟 hook type 有关;每种 hook type 都有它自己的 hook code 集合。
wParam 和 lParam 参数,这两个参数依赖于 nCode,但通常情况下这两个参数的值都用表示所拦截消息的一些额外信息。
SetWindowHookEx 总会将 hook procedure 添加到 hook chain 的头部。当监听的事件被触发的时候,hook chain 头部的 procedure 会先被调用。每个 procedure 都有权决定是否将事件传递给下一个 procedure。hook procedure 可以调用 CallNextHookEx 函数来将事件传递下去。
注意 某些 hook type 对应的 hook procedure 只能监听消息,对这些类型的 hook, 系统会把消息传递给 hook chain 中的每个 procedure, 不管这些 procedure 是否调用了 CallNextHookEx 函数
global hook 监视同一桌面上所有线程的消息。thread-specific hook 监视某个单独线程的消息。global hook procedure 可以在任意程序的上下文中被调用,所以它必须是一个单独的 DLL 模块。thread-specific hook procedure 仅仅在关联线程的上下文中被调用,因此,如果程序把 hook 安装在自己的线程里面,那么 hook procedure 可以在同一个模块的代码中,也可以在另一个 DLL 模块中。如果程序把 hook 安装到了别的程序的线程里,那 hook procedure 必须在一个单独的 DLL 模块里。要了解更多相关信息,可以参考 Dynamic-Link Libraries
注意 你应该只在调试的情况下使用 global hook。 Global hook 会降低系统的性能,并且可能与其它实现了相同类型 hook 的程序产生冲突。
Hook Types
每种类型的 hook 都可以让程序监视系统消息处理机制的某个方面。以下几个小节介绍了可用的 hook 类型:
- WH_CALLWNDPROC and WH_CALLWNDPROCRET
- WH_CBT
- WH_DEBUG
- WH_FOREGROUNDIDLE
- WH_GETMESSAGE
- WH_JOURNALPLAYBACK
- WH_JOURNALRECORD
- WH_KEYBOARD_LL
- WH_KEYBOARD
- WH_MOUSE_LL
- WH_MOUSE
- WH_MSGFILTER and WH_SYSMSGFILTER
- WH_SHELL
WH_CALLWNDPROC and WH_CALLWNDPROCRET
WH_CALLWNDPROC and WH_CALLWNDPROCRET 这两个 hook 可以让你监视发往窗口过程函数的消息。系统会在消息传递给窗口过程函数之前调用 WH_CALLWNDPROC, 在窗口过程函数处理完消息之后调用 WH_CALLWNDPROCRET hook。
WH_CALLWNDPROCRET hook 会将一个 CWPRETSTRUCE 结构体的指针传递给 hook procedure. 这个结构体里包含了窗口过程函数的返回值,消息,消息参数。相较于窗口子类化技术,在不同进程间时,子类化无法做到这一点,而 hook 可以。
要了解更多信息,请参考 CallWndProc 和 CallWndRetProc 回调函数
WH_CBT
WH_CBT hook 主要用来实现 computer-based training (CBT) 程序。在 激活、创建、销毁、最小化、最大化、移动、修改窗口大小 前; 在鼠标和键盘事件从系统消息队列中移除前;在设定输入焦点前;在同步系统消息队列前, 系统会调用 WH_CBT hook。hook procedure 的返回值将决定系统是否阻止这些操作。
要了解更多信息,请参考 CBTProc 回调函数
要了解更多信息,请参考 WinEvents
WH_DEBUG
在系统调用任何其它类型的 hook procedure 之前,系统会先调用 WH_DEBUG hook procedure。你可以用这个 hook 来决定是否允许系统调用 其它类型 hook 的 procedure。
要了解更多信息,请参考 DebugProc 回调函数
WH_FOREGROUNDIDEL
WH_FOREGROUNDIDEL hook 能够让你在前端线程空闲的时候执行低优先级任务。系统会在程序的前端线程即将变为空闲时调用 WH_FOREGROUNDIDEL hook procedure。
要了解更多信息,请参考 ForegroundIdleProc 回调函数。
WH_GETMESSAGE
WH_GETMESSAGE hook 能够让程序监视 GetMessage 和 PeekMessage 函数返回的消息。例如,你可以用 WH_GETMESSAGE hook 来监视鼠标键盘输入等要被投递到消息队列里的消息。
要了解更多信息,请参考 GetMsgProc
WH_JOURNALPLAYBACK
WH_JOURNALPLAYBACK hook 能够让程序插入消息到系统消息队列中。因此,你可以利用这个 hook 来回放 WH_JOURNALRECORD 所记录的鼠标键盘事件。当 WH_JOURNALPLAYBACK hook 被安装后,鼠标和键盘输入会经常变为不可用状态。WH_JOURNALPLAYBACK hook 是一个全局 hook——它不能被用作 thread-specific hook。
WH_JOURNALPLAYBACK hook 会返回一个超时值。这个超时值告诉系统在处理 playback hook 回放的消息 前 要等待多久时间。这种机制使得 hook 可以控制它回放事件的时间。
要了解更多信息,请参考 JournalPlaybackProc 回调函数。
WH_KEYBOARD_LL
WH_KEYBOARD_LL hook 能够让你监视即将 post 到线程输入队列的键盘事件。
要了解更多信息,请参考 LowLevelKeyboardProc 回调函数。
WH_KEYBOARD
WH_KEYBOARD hook 能够让程序监视即将被 GetMessage 和 PeekMessage 函数返回的 WM_KEYDOWN 和 WM_KEYUP 消息的传输。你可以用 WH_KEYBOARD hook 来监视传递到消息队列后的键盘输入事件。
要了解更多信息,请参考KeyboardProc
WH_MOUSE_LL
WH_MOUSE_LL hook 能够让你监视即将 post 到线程输入队列的鼠标事件。
要了解更多信息,请参考 LowLevelMouseProc 回调函数。
WH_MOUSE
WH_MOUSE hook 能够让程序监视即将被 GetMessage 和 PeekMessage 函数返回的鼠标消息的传输。你可以用 WH_MOUSE hook 来监视传递到消息队列后的鼠标输入事件。
要了解更多信息,请参考MouseProc
WH_MSGFILTER and WH_SYSMSGFILTER
WH_MSGFILTER and WH_SYSMSGFILTER hook 能够让你监视即将被菜单、滚动条、MessageBox、对话框等处理的消息,并且能够监听到另外一个窗口即将因为用户按下 ALT+TAB 或 ALT+ESC 键而被激活这样的事件。WM_MSGFILTER 仅能够监视安装 hook 的当前程序所发出的消息,而 WM_SYSMSGFILTER 可以监听所有程序的这些消息。
WH_MSGFILTER and WH_SYSMSGFILTER 能够让你在模态框消息循环中执行消息过滤操作。这相当于主消息循环中所执行的过滤操作。例如,程序经常会检查一个新消息从收到消息开始到消息被分发所用的时间,从而进行一些特殊处理。然而,在模态框消息循环中,系统在接收和分发消息时不允许程序在它的主消息循环中进行过滤。如果程序安装了 WH_MSGFILTER 或 WH_SYSMSGFILTER hook procedure, 系统会在模态框消息循环中调用这些 procedure。
程序可以用 CallMsgFilter 函数直接调用 WH_MSGFILTER hook。通过这个函数,程序可以用类似主消息循环中的代码来过滤模态框消息循环。要做到这一点,需要先封装一个 WM_MSGFILTER hook procedure,然后在 GetMessage 和 DispatchMessage 函数之间调用 CallMsgFilter 函数。
while (GetMessage(&msg, (HWND) NULL, 0, 0))
{
if (!CallMsgFilter(&qmsg, 0))
DispatchMessage(&qmsg);
}
CallMsgFilter 函数的最后一个参数会传递给 hook procedure,你可以输入任何值。例如定义一个 MSGF_MAINLOOP 常量然后传进去, hook procedure 就能通过这个常量判断出调用方来自哪里。
要了解更多信息,请参考 MessageProc 和 SysMsgProc 回调函数。
WH_SHELL
shell 程序可以利用 WH_SHELL hook 来接收重要通知。程序会在 shell 程序即将被激活 或 顶层窗口被创建或销毁完成后 调用 WH_SHELL hook procedure。
注意 常规 shell 程序并不会收到 WH_SHELL 消息。任何将自己注册为默认 shell 的程序都必须在它或者其它程序可以收到 WH_SHELL 消息前调用 SystemParametersInfo 函数。这个函数被调用时必须传入 SPI_SETMINIMIZEDMETRICS and MINIMIZEDMETRICS 结构体。并设定结构体的 iArrange 成员为 ARW_HIDE。
要了解更多信息,请参考 ShellProc 回调函数。
Using Hooks
以下代码示例说明了如何执行与 hook 相关的如下操作:
- Installing and Releasing Hook Procedures
- Monitoring System Events
Installing and Releasing Hook Procedures
你可以通过 SetWindowsHookEx 函数来安装 hook procedure。并指定调用 procedure 的 hook type,及 procedure 应该跟所有线程还是某个特定线程进行关联,及 procedure 函数的入口点。
对于 global hook 你必须将 procedure 放到一个单独的 DLL 中,而不能直接放到安装 hook 的那个程序模块里。在安装 hook 之前,程序必须先持有上述 DLL 模块的实例句柄。你可以通过 GetProcAddress 来获取 DLL 中 hook procedure 函数的指针。最后,使用 SetWindowsHookEx 函数将 procedure 地址安装到感兴趣的 hook chain 里。SetWindowsHookEx 函数需要传入 模块句柄、procedure 函数指针、一个 0 用于标识 hook 将被安装到当前桌面的所有线程中,这些步骤如下所示:
HOOKPROC hkprcSysMsg;
static HINSTANCE hinstDLL;
static HHOOK hhookSysMsg;
// 装载 DLL,得到 DLL 句柄、 procedure 函数地址
hinstDLL = LoadLibrary(TEXT("c:\\myapp\\sysmsg.dll"));
hkprcSysMsg = (HOOKPROC)GetProcAddress(hinstDLL, "SysMessageProc");
// 安装全局 hook,并返回 hook procedure 的句柄
hhookSysMsg = SetWindowsHookEx(
WH_SYSMSGFILTER,
hkprcSysMsg,
hinstDLL,
0);
thread-specific hook 的使用方法更上面的代码类似,但你要在最后一个函数中传入线程 id。
你可以使用 UnhookWindowsHookEx 函数将 thread-specific hook procedure 的地址从 hook chain 中移除,调用此函数时需要传入 hook procedure 的句柄。一旦你的程序不再需要 hook, 你就应该将它移除。
UnhookWindowsHookEx 同样可以用于移除 global hook procedure, 但它不会释放 hook procedure 所在的 DLL。这是因为 global hook procedure 会在当前桌面所有程序的上下文中被调用,这些进程对 LoadLibrary 的调用将与它发生冲突。并且 FreeLibrary 不能对另一个进程使用,因此你无法去主动卸载它。系统会在所有显式链接到 hook procedure DLL 的进程结束后 或者 这些进程主动调用了 FreeLibrary 之后释放 DLL。
安装 global hook 的另一种方法是在 DLL 中提供一个安装函数。通过这种方法,安装 hook 的那个程序不需要获取 DLL 的句柄,只要在链接到 DLL 之后,调用 DLL 中的安装函数就能进行安装。由于安装函数就在 DLL 中,它可以提供 SetWindowsHookEx 所需要的所有参数。DLL 也可以提供一个卸载函数,程序可以在终止的时候调用这个卸载函数来释放 global hook。
Monitoring System Events
以下代码示例使用几种不同的 thread-specific hook procedure 来监视线程中的事件。它说明了如何处理以下几种 hook type 事件。
- WH_CALLWNDPROC
- WH_CBT
- WH_DEBUG
- WH_GETMESSAGE
- WH_KEYBOARD
- WH_MOUSE
- WH_MSGFILTER
用户可以在菜单里安装或移除 hook。hook procedure 被安装后,一旦收到一个事件,它就会将事件信息答应到主窗口客户区中。
注意 下面的代码并不能直接运行,代码里没有窗口、没有菜单、没有实现 LookUpTheMessage 函数。你可以自己加上这些代码,也可以参考 这篇文章
#include <windows.h>
#include <strsafe.h>
#include "app.h"
#pragma comment( lib, "user32.lib")
#pragma comment( lib, "gdi32.lib")
#define NUMHOOKS 7
// Global variables
typedef struct _MYHOOKDATA
{
int nType;
HOOKPROC hkprc;
HHOOK hhook;
} MYHOOKDATA;
MYHOOKDATA myhookdata[NUMHOOKS];
HWND gh_hwndMain;
// Hook procedures
LRESULT WINAPI CallWndProc(int, WPARAM, LPARAM);
LRESULT WINAPI CBTProc(int, WPARAM, LPARAM);
LRESULT WINAPI DebugProc(int, WPARAM, LPARAM);
LRESULT WINAPI GetMsgProc(int, WPARAM, LPARAM);
LRESULT WINAPI KeyboardProc(int, WPARAM, LPARAM);
LRESULT WINAPI MouseProc(int, WPARAM, LPARAM);
LRESULT WINAPI MessageProc(int, WPARAM, LPARAM);
void LookUpTheMessage(PMSG, LPTSTR);
LRESULT WINAPI MainWndProc(HWND hwndMain, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static BOOL afHooks[NUMHOOKS];
int index;
static HMENU hmenu;
gh_hwndMain = hwndMain;
switch (uMsg)
{
case WM_CREATE:
// Save the menu handle
hmenu = GetMenu(hwndMain);
// Initialize structures with hook data. The menu-item identifiers are
// defined as 0 through 6 in the header file app.h. They can be used to
// identify array elements both here and during the WM_COMMAND message.
myhookdata[IDM_CALLWNDPROC].nType = WH_CALLWNDPROC;
myhookdata[IDM_CALLWNDPROC].hkprc = CallWndProc;
myhookdata[IDM_CBT].nType = WH_CBT;
myhookdata[IDM_CBT].hkprc = CBTProc;
myhookdata[IDM_DEBUG].nType = WH_DEBUG;
myhookdata[IDM_DEBUG].hkprc = DebugProc;
myhookdata[IDM_GETMESSAGE].nType = WH_GETMESSAGE;
myhookdata[IDM_GETMESSAGE].hkprc = GetMsgProc;
myhookdata[IDM_KEYBOARD].nType = WH_KEYBOARD;
myhookdata[IDM_KEYBOARD].hkprc = KeyboardProc;
myhookdata[IDM_MOUSE].nType = WH_MOUSE;
myhookdata[IDM_MOUSE].hkprc = MouseProc;
myhookdata[IDM_MSGFILTER].nType = WH_MSGFILTER;
myhookdata[IDM_MSGFILTER].hkprc = MessageProc;
// Initialize all flags in the array to FALSE.
memset(afHooks, FALSE, sizeof(afHooks));
return 0;
case WM_COMMAND:
switch (LOWORD(wParam))
{
// The user selected a hook command from the menu.
case IDM_CALLWNDPROC:
case IDM_CBT:
case IDM_DEBUG:
case IDM_GETMESSAGE:
case IDM_KEYBOARD:
case IDM_MOUSE:
case IDM_MSGFILTER:
// Use the menu-item identifier as an index
// into the array of structures with hook data.
index = LOWORD(wParam);
// If the selected type of hook procedure isn't
// installed yet, install it and check the
// associated menu item.
if (!afHooks[index])
{
myhookdata[index].hhook = SetWindowsHookEx(
myhookdata[index].nType,
myhookdata[index].hkprc,
(HINSTANCE) NULL, GetCurrentThreadId());
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_CHECKED);
afHooks[index] = TRUE;
}
// If the selected type of hook procedure is
// already installed, remove it and remove the
// check mark from the associated menu item.
else
{
UnhookWindowsHookEx(myhookdata[index].hhook);
CheckMenuItem(hmenu, index,
MF_BYCOMMAND | MF_UNCHECKED);
afHooks[index] = FALSE;
}
default:
return (DefWindowProc(hwndMain, uMsg, wParam,
lParam));
}
break;
//
// Process other messages.
//
default:
return DefWindowProc(hwndMain, uMsg, wParam, lParam);
}
return NULL;
}
/****************************************************************
WH_CALLWNDPROC hook procedure
****************************************************************/
LRESULT WINAPI CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szCWPBuf[256];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_CALLWNDPROC].hhook, nCode, wParam, lParam);
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
switch (nCode)
{
case HC_ACTION:
hResult = StringCchPrintf(szCWPBuf, 256/sizeof(TCHAR),
"CALLWNDPROC - tsk: %ld, msg: %s, %d times ",
wParam, szMsg, c++);
if (FAILED(hResult))
{
// TODO: writer error handler
}
hResult = StringCchLength(szCWPBuf, 256/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 15, szCWPBuf, cch);
break;
default:
break;
}
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_CALLWNDPROC].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_GETMESSAGE hook procedure
****************************************************************/
LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szMSGBuf[256];
CHAR szRem[16];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_GETMESSAGE].hhook, nCode,
wParam, lParam);
switch (nCode)
{
case HC_ACTION:
switch (wParam)
{
case PM_REMOVE:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR), "PM_REMOVE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case PM_NOREMOVE:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR), "PM_NOREMOVE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
default:
hResult = StringCchCopy(szRem, 16/sizeof(TCHAR), "Unknown");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
// Call an application-defined function that converts a
// message constant to a string and copies it to a
// buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szMSGBuf, 256/sizeof(TCHAR),
"GETMESSAGE - wParam: %s, msg: %s, %d times ",
szRem, szMsg, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szMSGBuf, 256/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 35, szMSGBuf, cch);
break;
default:
break;
}
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_GETMESSAGE].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_DEBUG hook procedure
****************************************************************/
LRESULT CALLBACK DebugProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_DEBUG].hhook, nCode,
wParam, lParam);
hdc = GetDC(gh_hwndMain);
switch (nCode)
{
case HC_ACTION:
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"DEBUG - nCode: %d, tsk: %ld, %d times ",
nCode,wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 55, szBuf, cch);
break;
default:
break;
}
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_DEBUG].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_CBT hook procedure
****************************************************************/
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szCode[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_CBT].hhook, nCode, wParam,
lParam);
hdc = GetDC(gh_hwndMain);
switch (nCode)
{
case HCBT_ACTIVATE:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_ACTIVATE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_CLICKSKIPPED:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_CLICKSKIPPED");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_CREATEWND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_CREATEWND");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_DESTROYWND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_DESTROYWND");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_KEYSKIPPED:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_KEYSKIPPED");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_MINMAX:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_MINMAX");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_MOVESIZE:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_MOVESIZE");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_QS:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_QS");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_SETFOCUS:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_SETFOCUS");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case HCBT_SYSCOMMAND:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "HCBT_SYSCOMMAND");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
default:
hResult = StringCchCopy(szCode, 128/sizeof(TCHAR), "Unknown");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR), "CBT - nCode: %s, tsk: %ld, %d times ",
szCode, wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 75, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_CBT].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_MOUSE hook procedure
****************************************************************/
LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szMsg[16];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process the message
return CallNextHookEx(myhookdata[IDM_MOUSE].hhook, nCode,
wParam, lParam);
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"MOUSE - nCode: %d, msg: %s, x: %d, y: %d, %d times ",
nCode, szMsg, LOWORD(lParam), HIWORD(lParam), c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 95, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_MOUSE].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_KEYBOARD hook procedure
****************************************************************/
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_KEYBOARD].hhook, nCode,
wParam, lParam);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR), "KEYBOARD - nCode: %d, vk: %d, %d times ", nCode, wParam, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 115, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_KEYBOARD].hhook, nCode, wParam, lParam);
}
/****************************************************************
WH_MSGFILTER hook procedure
****************************************************************/
LRESULT CALLBACK MessageProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CHAR szBuf[128];
CHAR szMsg[16];
CHAR szCode[32];
HDC hdc;
static int c = 0;
size_t cch;
HRESULT hResult;
if (nCode < 0) // do not process message
return CallNextHookEx(myhookdata[IDM_MSGFILTER].hhook, nCode,
wParam, lParam);
switch (nCode)
{
case MSGF_DIALOGBOX:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_DIALOGBOX");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case MSGF_MENU:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_MENU");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
case MSGF_SCROLLBAR:
hResult = StringCchCopy(szCode, 32/sizeof(TCHAR), "MSGF_SCROLLBAR");
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
default:
hResult = StringCchPrintf(szCode, 128/sizeof(TCHAR), "Unknown: %d", nCode);
if (FAILED(hResult))
{
// TODO: write error handler
}
break;
}
// Call an application-defined function that converts a message
// constant to a string and copies it to a buffer.
LookUpTheMessage((PMSG) lParam, szMsg);
hdc = GetDC(gh_hwndMain);
hResult = StringCchPrintf(szBuf, 128/sizeof(TCHAR),
"MSGFILTER nCode: %s, msg: %s, %d times ",
szCode, szMsg, c++);
if (FAILED(hResult))
{
// TODO: write error handler
}
hResult = StringCchLength(szBuf, 128/sizeof(TCHAR), &cch);
if (FAILED(hResult))
{
// TODO: write error handler
}
TextOut(hdc, 2, 135, szBuf, cch);
ReleaseDC(gh_hwndMain, hdc);
return CallNextHookEx(myhookdata[IDM_MSGFILTER].hhook, nCode, wParam, lParam);
}
网友评论