创建钩子(Hook)

创建钩子(Hook)
什么是Hook(钩子)

    钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。

 

    钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。

安装Hook的过程

step1:调用SetWindowsHookEx函数安装Hook。

step2:创建钩子函数,处理截获的消息。

常用函数

  1. SetWindowsHookEx
  2. GetCurrentThreadId
  3. CallNextHookEx
  4. UnhookWindowsHookEx

  注:函数具体用法请查阅MSDN

实例1:

安装只截获当前线程的鼠标和键盘消息的钩子

 

step1:创建一个MFC基于对话框的工程命名为Hook。

step2:在OnInitDialog()函数中安装两个Hook,一个用于截获鼠标一个用于截获键盘。

 g_hMouse = SetWindowsHookEx(WH_MOUSE, MouseProc, NULL, GetCurrentThreadId());  //安装一个鼠标的Hook将Hook的句柄保存在全局的g_hMouse中
 g_hKeyboard = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, GetCurrentThreadId());
step3:在全局区创建钩子函数,处理截获的消息。

LRESULT CALLBACK MouseProc(
         int nCode,      // hook code
         WPARAM wParam,  // message identifier
         LPARAM lParam   // mouse coordinates
         )
{
 if(nCode < 0)
  return CallNextHookEx(g_hMouse, nCode, wParam, lParam);
 else
  return 1;
}

LRESULT CALLBACK KeyboardProc(
							  int nCode,       // hook code
							  WPARAM wParam,  // virtual-key code
							  LPARAM lParam   // keystroke-message information
							  )
{
	if(nCode < 0)
		return CallNextHookEx(g_hKeyboard, nCode, wParam, lParam);
	//else if(VK_SPACE == wParam)
	else if(VK_F4 == wParam && ((lParam>>29) & 0x1))//截获Alt+F4
		return 1;
	else
		return CallNextHookEx(g_hKeyboard, nCode, wParam, lParam);
	
}

注:在Hook函数中返回大于0的数表示此消息已由Hook函数处理了就不会交给Windows窗口过程处理了。如果对此消息不感兴趣可以调用CallNextHookEx将此消息交给Hook链中的下一个Hook函数。


实例2:

安装一个全局的钩子(Hook)

step1:首先建立一个动态链接库用来安装全局钩子。

 

#include <windows.h>

HHOOK g_hMouse = NULL;
HHOOK g_hKeyboard = NULL;
HWND  g_hWnd = NULL;
//鼠标钩子函数
LRESULT CALLBACK MouseProc(
						   int nCode,      // hook code
						   WPARAM wParam,  // message identifier
						   LPARAM lParam   // mouse coordinates
						   )
{
	return 1;
}
//键盘钩子函数
LRESULT CALLBACK KeyboardProc(
							  int code,       // hook code
							  WPARAM wParam,  // virtual-key code
							  LPARAM lParam   // keystroke-message information
							  )
{
	if(VK_F2 == wParam)
	{
		SendMessage(g_hWnd, WM_CLOSE, 0, 0);
		UnhookWindowsHookEx(g_hMouse);
		UnhookWindowsHookEx(g_hKeyboard);
	}	
	return CallNextHookEx(g_hKeyboard, code, wParam, lParam);
}



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

 

 

step2:将SetHook函数导出。

建立一个扩展名为def的模版定义文件。

 

LIBARY "HookDll"
EXPORTS
SetHook 

 

 

step3:建立一个客户端来安装全局钩子。

建立一个基于对话框的程序,设置链接库文件设置方法见动态链接的创建相关文章。接着声明一个导入函数如下:

_declspec(dllimport)void SetHook(HWND hWnd);

再在OnInitDialog()函数中调用SetHook函数安装全局钩子。

SetHook(m_hWnd);

CallNextHookEx函数的说明

Hook队列的正确的消息处理流程应该如下:

  物理击键
   ↓
  钩子管理函数←→钩子A←→钩子B←→钩子C←→钩子D
   ↓
  Window消息处理函数
 
  在钩子A函数中,如果调用CallNextHookEx函数,则会将按键消息传给钩子B;如果不调用CallNextHookEx函数,则钩子B不会得到按键消息,换句话说,钩子B失效了,当然此时的钩子C和钩子D也失效了。为了钩子间和平相处,还是应该在钩子函数里添加CallNextHookEx函数的调用。
 
  再说说钩子函数的返回值的问题。在上面的事例中,钩子A的返回值决定按键消息是否丢弃。返回值0,告诉系统,消息继续传递给Window消息处理函数;返回值1(非0),告诉系统,消息将丢弃,Window消息处理函数得不到按键的消息。
 
  所以说,如果只是统计按键的信息
  在钩子函数中的最后直接调用
  Return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)
  由后面的钩子函数来决定是否丢弃该消息。(大家和平相处)
 
  如果是屏蔽按键
  在钩子函数中进行判断,满足要求后直接
  CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)  
  Return 1
  告诉系统,丢弃该消息。当然出于礼貌,在之前还是调用CallNextHookEx函数,以便其他的钩子函数处理该消息
 
  至于修改按键(映射按键),修改参数,调用CallNextHookEx函数是没有用的。因为原本的消息根本就没有修改,你改的只是传给其他钩子函数的消息。而且还非常容易出错。
 

 

posted @ 2012-09-26 23:35  骑乐在途  阅读(593)  评论(0编辑  收藏  举报