以下代码摘录自《VC++深入详解》:

首先我们新建一个DLL,并编写钩子函数和钩子过程函数:

# include <windows.h>

HHOOK g_hMouse = NULL;
HHOOK g_hKeyboard = NULL;

#pragma data_seg( "MySec" )
HWND g_hWnd = NULL;
#pragma data_seg()

#pragma comment( linker,"/section:MySec,RWS" )



LRESULT CALLBACK MouseProc( int nCode,
WPARAM wParam,
LPARAM lParam
)
{
    return 1;
}

LRESULT CALLBACK KeyboardProc( int code,
WPARAM wParam,
LPARAM lParam
)
{
    if ( VK_F2 == wParam )
    {
        SendMessage( g_hWnd,WM_CLOSE,0,0 );
        UnhookWindowsHookEx( g_hMouse );
        UnhookWindowsHookEx( g_hKeyboard );
    }

    return 1;
}

void SetHook( HWND hwnd )
{
    g_hWnd = hwnd;
    g_hMouse = SetWindowsHookEx( WH_MOUSE,MouseProc,GetModuleHandle( "Hook" ),0 );
    g_hKeyboard = SetWindowsHookEx( WH_KEYBOARD,KeyboardProc,GetModuleHandle( "Hook" ),0 );
}

并编写一个模块定义文件:

LIBRARY Hook
EXPORTS
SetHook @2

编译连接即可。为了防止系统给全局变量g_hWnd开辟新的空间,我们在DLL中添加一个新的区段,并设置成共享属性,将其加入其中。这样一来g_hWnd就不会产生副本,也就是可以一直保存着客户程序的句柄了。

 

这里,我们用LordPE程序查看生成的dll文件:

看见生成了一个MySec区段,根据其标志位可知其属性为:

IMAGE_SCN_CNT_INITIALIZED_DATA
0x00000040
 

The section contains initialized data.

该区块包含以初始化的数据。

 -----------------------------------
IMAGE_SCN_MEM_SHARED
0x10000000
The section can be shared in memory.
该区块为共享区块。
 -----------------------------------
IMAGE_SCN_MEM_READ
0x40000000

The section can be read.
该区块可读,可执行文件中的区块总是设置该
标志。
 -----------------------------------
IMAGE_SCN_MEM_WRITE
0x80000000
The section can be written to.
该区块可写。

接下来,我们新建一个MFC程序,选择对话框风格。拷贝dll文件至MFC程序路径下,并在菜单“工程”->“设置”中引入lib文件:

接下来在程序中声明SetHook函数:

_declspec( dllimport ) void SetHook( HWND hwnd );

并修改OnInitDialog函数如下:

BOOL CHookTestDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }

    // Set the icon for this dialog.  The framework does this automatically
    //  when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);            // Set big icon
    SetIcon(m_hIcon, FALSE);        // Set small icon
    
    // TODO: Add extra initialization here
    int cxScreen,cyScreen;
    cxScreen = GetSystemMetrics( SM_CXSCREEN );
    cyScreen = GetSystemMetrics( SM_CYSCREEN );
    SetWindowPos( &wndTopMost,0,0,cxScreen,cyScreen,SWP_SHOWWINDOW );

    SetHook( m_hWnd );
    
    return TRUE;  // return TRUE  unless you set the focus to a control
}

这里,整个钩子程序就设置好了,运行将屏蔽所有鼠标与键盘消息,只有按下“F2”键才可以退出。