windows程序设计读书笔记——键盘钩子

为了安装全局钩子,创建一个DLL工程。包含安装钩子,卸载钩子,钩子函数。

1.安装钩子

HHOOK SetWindowsHookEx( <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">int idHook,</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">//键盘钩子钩子类型为WH_KEYBOARD</span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> HOOKPROC </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">lpfn,</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">//钩子函数地址 </span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">HINSTANCE hMod,</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">//钩子函数所在DLL的实例句柄 </span>
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">DWORD dwThreadId</span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">//指定线程,0表示系统范围内的安装钩子);</span>
 

如何获取钩子函数所在DLL的实例句柄?

VirtualQuery函数可以取得调用进程虚拟地址空间中指定内存页的状态

DWORD VirtualQuery(  
LPCVOID lpAddress,                       //指向要查找的地址
PMEMORY_BASIC_INFORMATION lpBuffer,//返回该地址所在页面以及与它相邻具有相同属性的页面信息,返回信息到MEMORY_BASIC_INFORMATION结构
DWORD dwLength 				//结构的长度
); 
typedef struct _MEMORY_BASIC_INFORMATION { 
  PVOID BaseAddress; 
  PVOID AllocationBase; 
  DWORD AllocationProtect; 
  DWORD RegionSize; 
  DWORD State; 
  DWORD Protect; 
  DWORD Type; 
  } MEMORY_BASIC_INFORMATION; 
typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION;

这里只需要用到AllocationBase,表示VirtualAlloc函数分配的基地址。由此我们得到了DLL的实例句柄。

综合上述方法,安装卸载钩子函数如下

BOOL WINAPI SetKeyHook(BOOL bInstall,DWORD dwThreadId,HWND hWndCaller)
{
	BOOL m_ok;
	g_hwnd=hWndCaller;
	if (bInstall)
	{
		g_hhook=::SetWindowsHookEx(WH_KEYBOARD,HookProc,Modulefromaddress(HookProc),dwThreadId);
		m_ok=(g_hhook!=NULL);
	}
	else
	{
		m_ok=::UnhookWindowsHookEx(g_hhook);
		g_hhook=NULL;
	}
	return m_ok;
}

2.键盘钩子函数

LRESULT CALLBACK HookProc(int nCode,WPARAM wParam,LPARAM lParam)

下面重点介绍这个函数参数:

(1)nCode:查MSDN,这个参数用来决定如何处理得到的消息,<0时返回CallNextHookEx,把消息传递到下去。还有下面两个值

HC_ACTION:表示后面两个参数包含按下键值的消息

HC_NOREMOVE:表示后面两个参数包含键值消息,且消息没有移出消息队列。

(2)wParam:虚拟简直产生的消息

(3)lParam:值范围0~31。29=1:按下了ALT;30=1,信息发送前某键被按下,=0表示某键弹起

钩子函数具体代码入下:

LRESULT CALLBACK HookProc(int ncode,WPARAM wParam,LPARAM lParam)
{
	if (ncode<0||ncode==HC_NOREMOVE)
	{
		return ::CallNextHookEx(g_hhook,ncode,wParam,lParam);
	}
	if (lParam&0x40000000)         //0x40000000,第30位=1,键被按下时
	{
		return ::CallNextHookEx(g_hhook,ncode,wParam,lParam);
	}
	::PostMessage(g_hwnd,HM_KEY,wParam,lParam);
	return ::CallNextHookEx(g_hhook,ncode,wParam,lParam);
}
其中HM_KEY为自定义消息,利用WM_USER,此处可定义在WM_USER~0X7FFF。
0 through WM_USER –1用于系统消息
WM_USER through 0x7FFF用户自定义窗口类消息
WM_APP through 0xBFFF用户可用于应用程序的消息
0xC000 through 0xFFFF串消息
Greater than 0xFFFF为系统以后所用

发送消息用PostMessage函数,它将消息放入与创建窗口的线程相关联的消息队列后立即返回。当线程产生HM_KEY消息的时候,调用消息响应函数,将在应用程序部分说明。

3.这里需要用到共享数据段,因为DLL将被映射到不同进程的地址空间,每个进程空间中,钩子函数都要使用钩子句柄和主窗口句柄,为了调用CallNextHookEx以及向主窗口       发送消息。当钩子成功安装后,将DLL加载进其他进程的地址空间,但是在这些地址空间中钩子句柄和主窗口句柄没有正确设置,因为没有线程为他们赋值。

    共享数据段中的数据在所有进程中共享一块内存。一个进程中设置了共享数据段的数据,其他进程中的同一数据段的数据也会改变。

#pragma data_seg("YCIShared")
HWND g_hwnd=NULL;
HHOOK g_hhook=NULL;
#pragma data_seg()
4.关于DLL导出函数

#define KEYHOOK_API extern "C" _declspec(dllexport)
在C++中,加入extern "C",否则会找不到重载函数。

不要写成下面的形式,会有KEYHOOK_API重定义的警告

.cpp

#define KEYHOOK_API
.h
#ifdef KEYHOOK_API
#define KEYHOOK_API extern "C" _declspec(dllexport)
#else
#define KEYHOOK_API extern "C" _declspec(dllimport)
#endif 
5.在.def文件,定义导出函数和共享代码段。 因为在应用程序需要调用SetKeyHook,通过它安装卸载钩子,实现一系列功能!

EXPORTS 
SetKeyHook
SECTIONS
YCIShared Read Write Shared


至此DLL工作就完成了
接下来编写应用程序,创建MFC应用程序,我们只需要编写上面提及的消息响应函数

1.定义函数

afx_msg long OnHookKey(WPARAM wParam, LPARAM lParam);

函数体为你想要实现的响应动作

2.绑定自定义消息和消息相应函数,代码写于 BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间

ON_MESSAGE(HM_KEY,OnHookKey)
3. 调用DLL导出的SetKeyHook函数,代码写到DLG类初始化函数中!

SetKeyHook(TRUE,0,m_hWnd);
参数 :    TRUE:确认安装钩子

0:在系统范围内安装钩子

m_hWnd:是windows自定义的窗口句柄,最后将把消息Post到这个句柄所标志的窗口

这是很久之前学习的内容,可是没有深入理解不久就忘记了。看似简单的一个程序,实际动手编写也花费很多时间,我终于体会到各位大神们所说的,无论程序看起来多简单,都要自己动手实际,因为看上去简单,等到实现时会发现各种问题。

重新学习,不足之处,烦请指正。

具体代码查看《windows程序设计》第九章


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值