Hooks MSDN 翻译

Hooks

本文翻译自 MSDN

Hook 是系统消息处理机制中的一个点,在这个点上,程序可以装载一个子程序。利用这个子程序,程序可以监控消息在系统中的传输,对于某些种类的消息,还可以在这些消息被投递到窗口过程函数前先对消息做一些处理。

本文讲述了一下几个话题:

  1. Hooks Overview 介绍 Hook 的用途
  2. Using Hook 演示如何执行关联到 hook 上的任务
  3. 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 集合。
wParamlParam 参数,这两个参数依赖于 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 hookGlobal 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 可以。

要了解更多信息,请参考 CallWndProcCallWndRetProc 回调函数

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 就能通过这个常量判断出调用方来自哪里。

要了解更多信息,请参考 MessageProcSysMsgProc 回调函数。

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); 
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容

  • SetWindowsHookEx 将应用程序定义的钩子过程安装到钩子链中.您将安装一个挂钩程序来监视系统的某些类型...
    f675b1a02698阅读 5,760评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,494评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,493评论 18 399
  • 6月20日 1、财富播种恩田、敬田、悲田√ 2、上午陪婆婆去看病,帮她找医生,带领她去检查,种下保护生命的种子。 ...
    鹊曾阅读 102评论 0 0
  • 应用场景:团队拓展游戏 项目性质:团队协作类场地项目 活动时间:40分钟 使用道具:3米细直棍(pvc管也可) 活...
    私念染流年阅读 677评论 0 0