以下代码摘录自《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”键才可以退出。
我们一路奋战,不是为了改变世界,而是不让世界改变我们
——《熔炉》