源自:https://blog.csdn.net/programvae/article/details/80292076

最近碰巧要使用键盘钩子,于是在网上搜索了一番,发现大多数博客的文章都是雷同的,根本就没有讲清楚全局钩子和局部钩子的区别,于是特开一贴,讲全局钩子和局部钩子捋一捋。也供后面的人学习。
   因为大部分应用都应该采用局部钩子,所以我这儿使用的是局部钩子,而全局钩子的例子网上到处都是。
   大部分网上参考文章都只是展示了全局钩子的写法,而线程钩子的写法和介绍相对少一些,特别是关键语句上如果定义的不正确是没有任何效果的,在自己反复尝试后决定留下一个正确的版本分享出来
    代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows.Forms;namespace AssistToolSet.Util
{/// <summary>/// 键盘钩子类/// </summary>public class Hook{public delegate int HookProc(WH_CODE nCode, Int32 wParam, IntPtr lParam);public enum WH_CODE : int{WH_JOURNALRECORD = 0,WH_JOURNALPLAYBACK = 1,/// <summary>/// 进程钩子/// </summary>WH_KEYBOARD = 2,/// <summary>/// 底层键盘钩子 全局钩子就是用这个/// </summary>WH_KEYBOARD_LL = 13,}public enum HC_CODE : int{HC_ACTION = 0,HC_GETNEXT = 1,HC_SKIP = 2,HC_NOREMOVE = 3,HC_NOREM = 3,HC_SYSMODALON = 4,HC_SYSMODALOFF = 5}/// <summary>/// 安装钩子/// </summary>[DllImport("user32.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]public static extern IntPtr SetWindowsHookEx(WH_CODE idHook, HookProc lpfn, IntPtr pInstance, uint threadId);/// <summary>/// 卸载钩子/// </summary>[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);/// <summary>/// 传递钩子/// </summary>[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]public static extern int CallNextHookEx(IntPtr pHookHandle, WH_CODE nCodem, Int32 wParam, IntPtr lParam);/// <summary>/// 获取全部按键状态/// </summary>/// <param name="pbKeyState"></param>/// <returns>非0表示成功</returns>[DllImport("user32.dll")]public static extern int GetKeyboardState(byte[] pbKeyState);/// <summary>/// 获取程序集模块的句柄/// </summary>/// <param name="lpModuleName"></param>/// <returns></returns>[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]public static extern IntPtr GetModuleHandle(string lpModuleName);/// <summary>/// 获取当前进程中的当前线程ID/// </summary>/// <returns></returns>[DllImport("kernel32.dll", CharSet = CharSet.Auto)]public static extern uint GetCurrentThreadId();#region 私有变量private byte[] mKeyState = new byte[256];private Keys mKeyData = Keys.None; //专门用于判断按键的状态/// <summary>/// 键盘钩子句柄/// </summary>private IntPtr mKetboardHook = IntPtr.Zero;/// <summary>/// 键盘钩子委托实例/// </summary>private HookProc mKeyboardHookProcedure;#endregion#region 键盘事件public event KeyEventHandler OnKeyDown;public event KeyEventHandler OnKeyUp;#endregion/// <summary>/// 构造函数/// </summary>public Hook(){GetKeyboardState(this.mKeyState);}~Hook(){UnInstallHook();}/// <summary>/// 键盘钩子处理函数/// </summary>private int KeyboardHookProc(WH_CODE nCode, Int32 wParam, IntPtr lParam){/*全局钩子应该这样设定KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));*/// 定义为线程钩子时,wParam的值是击打的按键,与Keys里的对应按键相同if ((nCode == (int)HC_CODE.HC_ACTION) && (this.OnKeyDown != null || this.OnKeyUp != null)){mKeyData = (Keys)wParam;KeyEventArgs keyEvent = new KeyEventArgs(mKeyData);//这里简单的通过lParam的值的正负情况与按键的状态相关联if (lParam.ToInt32() > 0 && this.OnKeyDown != null){this.OnKeyDown(this, keyEvent);}else if (lParam.ToInt32() < 0 && this.OnKeyUp != null){this.OnKeyUp(this, keyEvent);}}if (ShortcutManagement.s_bHotkeyUsed){ShortcutManagement.s_bHotkeyUsed = false;return 1;}return CallNextHookEx(this.mKetboardHook, nCode, wParam, lParam);}/// <summary>/// 安装钩子/// </summary>/// <returns></returns>public bool InstallHook(){//线程钩子时一定要通过这个取得的值才是操作系统下真实的线程uint result = GetCurrentThreadId();if (this.mKetboardHook == IntPtr.Zero){this.mKeyboardHookProcedure = new HookProc(this.KeyboardHookProc);//注册线程钩子时第三个参数是空this.mKetboardHook = SetWindowsHookEx(WH_CODE.WH_KEYBOARD, this.mKeyboardHookProcedure, IntPtr.Zero, result);/*如果是全局钩子应该这样使用this.mKetboardHook = SetWindowsHookEx(WH_CODE.WH_KEYBOARD_LL, mKeyboardHookProcedure,GetModuleHandle(System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName), 0);*/if (this.mKetboardHook == IntPtr.Zero){return false;}}return true;}/// <summary>/// 卸载钩子/// </summary>/// <returns>true表示成功 </returns>public bool UnInstallHook(){bool result = true;if (this.mKetboardHook != IntPtr.Zero){result = UnhookWindowsHookEx(this.mKetboardHook) && result;this.mKetboardHook = IntPtr.Zero;}return result;}}}
---------------------
作者:PGEva
来源:CSDN
原文:https://blog.csdn.net/programvae/article/details/80292076
版权声明:本文为博主原创文章,转载请附上博文链接!

View Code

通过这次认知,意识到,以后如果要做这些接触相关的api的时候,我们应该尽量去查官方文档,而不是一开始就是查看别人的博客。应该以官方文档为主。一定要记住键盘钩子事件。

32位和64位的系统不一样。

转载于:https://www.cnblogs.com/kuangwong/p/10292680.html

C#全局钩子和局部钩子记录相关推荐

  1. 局部钩子能防全局钩子吗_Django局部钩子和全局钩子

    Ⅰ 局部钩子的使用 在自定义的Form类中写 clean_字段名 取出字段的真正值 做复杂判断 如果判断失败,抛出ValidationError 如果通过,return 判断的字段 判断用户名是否以字 ...

  2. Django13-ModelForm中的is_valid及局部钩子、全局钩子源码解析

    1.查看is_valid方法,返回self.is_bound和非self.errors def is_valid(self):"""Returns True if the ...

  3. baseresponse响应类_内部类、响应类Response、序列化基类、反序列化、全局局部钩子...

    一.内部类 1.概念:将类定义在一个类的内部,被定义的类就是内部类 2.特点:内部类及内部类的所以名称空间,可以直接被外部类访问的 3. 应用:通过内部类的名称空间,给外部类额外拓展一些特殊的属性(配 ...

  4. 局部遮荫光伏matlab,一种基于随机蛙跳全局搜索算法的局部阴影光伏阵列MPPT控制的制作方法...

    本发明涉及一种局部阴影光伏阵列多峰MPPT控制方法,特别涉及一种基于随机蛙跳全局搜索算法的局部阴影光伏列阵多峰MPPT控制. 背景技术: 伴随太阳能发电的普及,光伏阵列的运行环境变的越来越复杂,局部遮 ...

  5. 全局敏感度,局部敏感度和平滑敏感度到底有什么区别?【差分隐私】

    全局敏感度,局部敏感度和平滑敏感度到底有什么区别?[差分隐私] 写在前面的话 噪声校准 全局敏感度: 局部敏感度 平滑敏感度 噪声分布范围 自己的理解 写在前面的话 关于敏感度相关的知识,我认为这是差 ...

  6. mysql 钩子函数_SetWindowsHookEx原理(如何使用钩子,使用钩子hook其他进程的函数)...

    基本概念 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的.当消息到达后,在目标窗口处理函数之前处理 ...

  7. npm包全局安装和局部安装,执行包命令有什么不同?

    之前开发了一个npm的包.在实际应用中发现了一个问题.如果你想要直接执行这个包的命令,那么你就需要全局安装这个包.如果你只是局部安装,且没有在package.json文件中配置的话,就会提示该命令无法 ...

  8. leetcode 775. Global and Local Inversions | 775. 全局倒置与局部倒置(Java)

    题目 https://leetcode.com/problems/global-and-local-inversions/ 题解 看了评论区答案. 局部倒置一定是全局倒置:局部倒置是连续递减: 所以只 ...

  9. Vue组件之全局组件与局部组件

    组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有些情况下, ...

  10. 16-作用域(全局作用域及局部作用域)

    16-作用域(全局作用域及局部作用域) //作用域 全局作用域 函数作用域 //函数的内部环境可以访问到所有外部环境的值,但是外部环境不能访问内部环境的值 //注意事项 //在全局变量和局部变量不同名 ...

最新文章

  1. 逐飞科技对于STC8H1K系列的单片机正交解码的资料以及实验
  2. 最直接的解决服务器宕机的方法
  3. HighNewTech:2019.08.09程序猿界大事件之【你好,我是鸿蒙OS】~【来了,老弟】—技术才是硬道理,开源方能建立新生态!
  4. ABAP 如何实现屏幕字段不可输入
  5. 【视频内含福利】原来手机套壳视频是这么做出来的
  6. 带你认识Flink容错机制的两大方面:作业执行和守护进程
  7. 微软将于6月24日发布下一代Windows
  8. matlab误码率分析,误码率分析 请大神帮忙解释下程序
  9. git remote 命令的用法
  10. Flask数据库学习
  11. 只用两行代码,我让Transformer推理加速了10倍
  12. php数组是否存在数组,php判断数组中是否存在某值
  13. Java学习之Xpath报错 Exception in thread “main“ java.lang.NoClassDefFoundError: org/jaxen/Namespa
  14. 计算机硬件安装装置,一种计算机硬件教学装置制造方法及图纸
  15. ac3168无线网卡驱动下载_REALTEK芯片无线网卡最新驱动!支持到10.15
  16. Android NDK SO库隐藏内部符号表
  17. Android设置输入法
  18. 在面试中脱颖而出的流程全解
  19. 实朴检测深交所上市:市值44亿 应收账款逾期6587万
  20. 未来十年计算机体系结构的历史和趋势

热门文章

  1. 因为一条SQL,我差点被祭天......
  2. 什么是技术驱动型公司?阿里算吗?
  3. 【机房运维】网格机房机柜、机架内的空间规划及理线方法
  4. 遇见Flask-Script
  5. CF1062D Fun with Integers
  6. MongoDB 数据库管理(不定时更新)
  7. .NET下添加Redis
  8. Android事件模型之interceptTouchEvnet ,onTouchEvent关系正解
  9. jquery ajax jsonp跨域调用实例代码
  10. Linux中weblogic的设置