1.首先创建一个DLL项目,用以生成自定义的DLL文件,在DLL文件中对外有两个接口,安装钩子的函数SetHook和卸载钩子函数UnSetHook函数,对于
这些函数由于需要导出,所以在工程项目的.h文件中需要声明这些函数需要导出。
//MouseKeyboardHook.h
#ifdef MOUSEKEYBOARDHOOK_EXPORTS
#define MOUSEKEYBOARDHOOK_API __declspec(dllexport)
#else
#define MOUSEKEYBOARDHOOK_API __declspec(dllimport)
#endif
extern "C" MOUSEKEYBOARDHOOK_API int SetHook( DWORD dwThreadId );
extern "C" MOUSEKEYBOARDHOOK_API int UnSetHook(void);
这里只有安装钩子函数有参数,该参数是线程ID号,这里需要注意,如果在调用DLL时发现找不到函数地址,那就需要加extern “C” 说明了,当时我就是没有加郁闷了很久才找到这个问题。我思考了一下,应该是DLL中我采用的是C编程语言,而我的调用该DLL的应用程序默认是C++,但是由于C和C++的OBJ的函数名格式不同,所以才会出现找不到函数地址的问题。是对于DLL的头文件按照这个格式就可以导出函数了。
//MouseKeyboardHook.cpp文件
#include "stdafx.h"
#include "MouseKeyboardHook.h"
#include "stdio.h"
//共享内存变量
#pragma data_seg("MouseKeyboardHook")
HHOOK g_hMouseHook = NULL;
HHOOK g_hKeyboardHook = NULL;
#pragma data_seg()
// 这是导出变量的一个示例
MOUSEKEYBOARDHOOK_API int nMouseKeyboardHook=0;
// 这是导出函数的一个示例。
int UnSetHook(void);
int fnMouseKeyboardHook(void);
int SetHook( DWORD dwThreadId );
//注意:钩子函数的格式必须是 LRESULT CALLBACK 函数名( int 钩子类型, WPARAM wParam, LPARAM lParam );
LRESULT CALLBACK MouseHookProc( int nCode, WPARAM wParam, LPARAM lParam );//处理鼠标的钩子函数
LRESULT CALLBACK KeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam );//处理键盘的钩子函数
HMODULE WINAPI ModuleFromAddress(PVOID pv) ;//这个是获取DLL的内存地址,可以重复使用,当做模版
MOUSEKEYBOARDHOOK_API int fnMouseKeyboardHook(void)//这个是项目自己生成的没多大用
{
return 42;
}
LRESULT CALLBACK KeyboardHookProc( int nCode, WPARAM wParam, LPARAM lParam )
{
if( wParam=='Q' && lParam>0 )//当只有按下Q键的时候才会退出钩子函数。其他其他的话都屏蔽
{
MessageBox( NULL, "卸载钩子中...", "卸载钩子", MB_OK );
UnSetHook();
}
else return TRUE;
return ::CallNextHookEx(g_hKeyboardHook, nCode, wParam, lParam);
}
LRESULT CALLBACK MouseHookProc( int nCode, WPARAM wParam, LPARAM lParam )//我这里屏蔽所有鼠标消息
{
return ::CallNextHookEx(g_hMouseHook, nCode, wParam, lParam);
}
// 这是已导出类的构造函数。
// 有关类定义的信息,请参阅 MouseKeyboardHook.h
CMouseKeyboardHook::CMouseKeyboardHook()
{
return;
}
MOUSEKEYBOARDHOOK_API int SetHook( DWORD dwThreadId )//安装钩子函数
{
g_hMouseHook = ::SetWindowsHookEx( WH_MOUSE, MouseHookProc, ModuleFromAddress(MouseHookProc), 0 );
g_hKeyboardHook = ::SetWindowsHookEx( WH_KEYBOARD, KeyboardHookProc, ModuleFromAddress(KeyboardHookProc), 0 );
return 0;
}
MOUSEKEYBOARDHOOK_API int UnSetHook(void)//卸载钩子函数,不过这个例子有问题,卸载不了,不知道为什么
{
BOOL b1 = ::UnhookWindowsHookEx( g_hMouseHook );
BOOL b2 = ::UnhookWindowsHookEx( g_hKeyboardHook );
if( b1==FALSE || b2==FALSE )
MessageBox( NULL, "卸载钩子失败!", "", MB_OK );
return 0;
}
HMODULE WINAPI ModuleFromAddress(PVOID pv)
{
MEMORY_BASIC_INFORMATION mbi;
if(::VirtualQuery(pv, &mbi, sizeof(mbi)) != 0)
{
return (HMODULE)mbi.AllocationBase;
}
else
{
return NULL;
}
}
这里要注意的地方是钩子函数的格式,其他的话应该问题不大。同时,因为在头文件中已经声明了导出函数,所以这里不需要再次声明了,按照正常函数写即可。
不过不知道为什么我的钩子卸载时失败了,真心不懂!
2.创建加载该DLL的应用程序
因为需要监视整个计算机,所以SetHook函数传参是0,代表监视整个计算机。
在本实例中,对于DLL的加载方式是动态加载的。
具体流程是:加载DLL文件-->获取导出函数地址-->调用钩子安装函数-->卸载钩子
程序主要源码如下:
BOOL bInstall = FALSE;//用来指示是否已经安装了钩子
// 用于应用程序“关于”菜单项的 CAboutDlg 对话框
//需要声明导出函数指针
typedef int ( *pSetHook)(DWORD * );//声明函数类型
typedef int ( *pUnsetHook)(void);
void CKeyMouseHookAppDlg::OnBnClickedButton1()//程序是按下按钮动态加载DLL的
{
HMODULE hModule = ::LoadLibrary( "MouseKeyboardHook.dll" );//加载DLL库
if( hModule!=NULL )
{
if( bInstall==FALSE )
{
pSetHook mpSetHook;
mpSetHook = (pSetHook)::GetProcAddress( hModule, "SetHook" );//获取导出函数地址
if( mpSetHook!=NULL )
{
mpSetHook( 0 );//安装全局钩子
bInstall = TRUE;
GetDlgItem( IDC_BUTTON1 )->SetWindowText( "卸载DLL" );
}
else MessageBox( "获取函数地址失败!" );
}
else
{
pUnsetHook mpUnsetHook;
mpUnsetHook = (pUnsetHook)::GetProcAddress( hModule, "UnSetHook" );
if( mpUnsetHook!=NULL )
{
mpUnsetHook();//卸载钩子
bInstall = FALSE;
GetDlgItem( IDC_BUTTON1 )->SetWindowText( "加载DLL" );
}
else MessageBox( "获取函数地址失败!" );
::FreeLibrary( hModule );//释放加载的DLL库
}
}
else MessageBox( "加载DLL失败!" );
}