• 在程序中使用钩子


    使用钩子

    在程序中使用钩子



    库引用
    using System.Runtime.InteropServices;



    DLL模块
    使用钩子首先必须知道一个比较重要的知识。也就是系统全局钩子必须将钩子代码放置在一个单独的DLL中。该DLL加载后会将代码嵌入其他应用程序的进程中,从而实现获取全局的鼠标键盘信息。

    因此,想要在C#中使用钩子函数的话,首先花一点功夫自己写一个DLL是一个不错的想法。即使你用的钩子不需要DLL,对于你以后增加功能只会更方便:-)



    DLL模块的基本实现(C++)
    // ==========include文件==========
    // 定义回调函数的函数类型
    typedef VOID (CALLBACK *CallBackFunc)(WPARAM, LPARAM);

    // 安装钩子(当include被其他程序引用的时候,dllexport → dllimport)
    extern "C" __declspec(dllexport) VOID InstallHook(HINSTANCE, CallBackFunc, CallBackFunc);

    // 卸载钩子(当include被其他程序引用的时候,dllexport → dllimport)
    extern "C" __declspec(dllexport) VOID UninstallHook();

    // ==========cpp文件==========
    // KB=Keyboard
    // MS=Mouse
    // 钩子的全局变量
    HHOOK _hHookKB = NULL;
    HHOOK _hHookMS = NULL;

    // Ctrl是否被按下
    BOOL  _bCtrlDown = FALSE;

    // DLL外部传入的回调函数(C#侧传入)
    CallBackFunc _funcMS = NULL;
    CallBackFunc _funcKB = NULL;

    // 函数声明
    LRESULT CALLBACK LowLevelKeyboardProc(int, WPARAM, LPARAM);
    LRESULT CALLBACK LowLevelMouseProc(int, WPARAM, LPARAM);

    // 安装钩子
    VOID InstallHook(HINSTANCE hInstance, CallBackFunc funcMS, CallBackFunc funcKB)
    {
      // 将外部传入的回调函数保存起来
      _funcMS = funcMS;
      _funcKB = funcKB;

      // 安装键盘钩子
      if(_hHookKB == NULL)
      {
        _hHookKB = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInstance, 0);
      }

      // 安装鼠标钩子
      if(_hHookMS == NULL)
      {
        _hHookMS = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, hInstance, 0);
      }
    }

    // 卸载钩子
    VOID UninstallHook()
    {
      // 卸载鼠标钩子
      if(_hHookMS != NULL)
      {
        UnhookWindowsHookEx(_hHookMS);
      }

      // 卸载键盘钩子
      if(_hHookKB != NULL)
      {
        UnhookWindowsHookEx(_hHookKB);
      }

      // 全局函数清空
      _hHookKB = NULL;
      _hHookMS = NULL;
      _funcMS = NULL;
      _funcKB = NULL;
    }

    // 简单的键盘钩子处理函数
    LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        // 返回值,如果想屏蔽一些数据的话,比如不想让监视的应用程序获得Enter键的事件
        // 那么在这个函数中处理完Enter键后,直接设定返回值为S_OK,不调用CallNextHookEx()直接返回
      LRESULT nRet = S_FALSE;

      // 一些键盘钩子获得的信息
      //PKBDLLHOOKSTRUCT pKb = (PKBDLLHOOKSTRUCT)lParam;

      switch(nCode)
      {
        case HC_ACTION:
          // 获得此时Ctrl键的状态
          _bCtrlDown = ((GetAsyncKeyState(VK_CONTROL) & 0x8000) != 0);

          // 如果外部传入过回调函数,则调用之
          if (_funcKB != NULL)
          {
            _funcKB(wParam, lParam);
          }
          break;
      }

      // 为了使被监视的程序正常处理事件,必须调用CallNextHookEx()
      nRet = CallNextHookEx(_hHookKB, nCode, wParam, lParam);

      return nRet;
    }

    // 简单的鼠标钩子处理函数
    LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam)
    {
        // 返回值,如果想屏蔽一些数据的话,比如不想让监视的应用程序获得鼠标滚轮的事件
        // 那么在这个函数中处理完鼠标滚轮事件后,直接设定返回值为S_OK,不调用CallNextHookEx()直接返回
      LRESULT nRet = S_FALSE;

      // 一些鼠标钩子获得的信息
      //PMOUSEHOOKSTRUCT pMS = (PMOUSEHOOKSTRUCT)lParam;

      switch(nCode)
      {
        case HC_ACTION:
          // 键盘Ctrl按下的情况下,才调用鼠标的回调函数
          if (_bCtrlDown && _funcMS != NULL)
          {
            _funcMS(wParam, lParam);
          }
          break;
      }

      // 为了使被监视的程序正常处理事件,必须调用CallNextHookEx()
      nRet = CallNextHookEx(_hHookMS, nCode, wParam, lParam);

      return nRet;
    }



    C#侧的基本运用
    // 一个简单的使用钩子的运用
    public class UseHook
    {
        // 声明DLL中的输出函数
        // 安装钩子函数
        [DllImport("xxx.dll")]
        public static extern void InstallHook(IntPtr hInstance, CallBackFunc funcMS, CallBackFunc funcKB);

        // 卸载钩子函数
        [DllImport("xxx.dll")]
        public static extern void UninstallHook();

        // 回调函数声明
        public delegate void CallBackFunc(IntPtr wParam, IntPtr lParam);

        // 启动钩子
        public void Start()
        {
            // 使用当前模块句柄启动钩子
            InstallHook(
                Marshal.GetHINSTANCE(
                        Assembly.GetEntryAssembly().GetModules()[0]
                        ),
                MouseCapture,
                KeyboardCapture
                );
        }

        // 停止钩子
        public void Stop()
        {
            UninstallHook();
        }
        
        // 鼠标回调事件
        protected void MouseCapture(IntPtr wParam, IntPtr lParam)
        {
            // 当有鼠标事件发生时,这个函数会被调用
        }

        // 键盘回调事件
        protected void KeyboardCapture(IntPtr wParam, IntPtr lParam)
        {
            // 当有键盘事件发生时,这个函数会被调用
        }
    }


  • 相关阅读:
    FCKeditor的问题
    每天学习一点点(2010年二月)
    Excel使用小技巧
    JavaScript 取页面属性
    附加 数据库错误 5120
    CSS中元素水平居中显示的方法
    css中height:100%不起作用的解决方法
    SQL SERVER数据库开发之存储过程应用(转载)
    双路由器双小型交换机组建公司网络,2个公网IP上网案例(转载)
    如何解决VS2005没有代码智能提示(联想)的问题(转载)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2217579.html
Copyright © 2020-2023  润新知