zoukankan      html  css  js  c++  java
  • 创建钩子(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函数是没有用的。因为原本的消息根本就没有修改,你改的只是传给其他钩子函数的消息。而且还非常容易出错。
     

  • 相关阅读:
    Java 单链表的倒置
    Android查询:模拟键盘鼠标事件(adb shell 实现)
    安卓 发送短信两种方式
    java tcp socket实例
    Java中读取某个目录下的所有文件和文件夹
    Android剖析和运行机制
    linux下搭建android NDK开发环境
    把log存起来
    判断Android系统net和wap接入点的开发实例
    android 4.0.4系统下实现apk的静默安装和启动
  • 原文地址:https://www.cnblogs.com/qilezaitu/p/3806982.html
Copyright © 2011-2022 走看看