C#全局钩子和局部钩子记录
源自: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#全局钩子和局部钩子记录相关推荐
- 局部钩子能防全局钩子吗_Django局部钩子和全局钩子
Ⅰ 局部钩子的使用 在自定义的Form类中写 clean_字段名 取出字段的真正值 做复杂判断 如果判断失败,抛出ValidationError 如果通过,return 判断的字段 判断用户名是否以字 ...
- Django13-ModelForm中的is_valid及局部钩子、全局钩子源码解析
1.查看is_valid方法,返回self.is_bound和非self.errors def is_valid(self):"""Returns True if the ...
- baseresponse响应类_内部类、响应类Response、序列化基类、反序列化、全局局部钩子...
一.内部类 1.概念:将类定义在一个类的内部,被定义的类就是内部类 2.特点:内部类及内部类的所以名称空间,可以直接被外部类访问的 3. 应用:通过内部类的名称空间,给外部类额外拓展一些特殊的属性(配 ...
- 局部遮荫光伏matlab,一种基于随机蛙跳全局搜索算法的局部阴影光伏阵列MPPT控制的制作方法...
本发明涉及一种局部阴影光伏阵列多峰MPPT控制方法,特别涉及一种基于随机蛙跳全局搜索算法的局部阴影光伏列阵多峰MPPT控制. 背景技术: 伴随太阳能发电的普及,光伏阵列的运行环境变的越来越复杂,局部遮 ...
- 全局敏感度,局部敏感度和平滑敏感度到底有什么区别?【差分隐私】
全局敏感度,局部敏感度和平滑敏感度到底有什么区别?[差分隐私] 写在前面的话 噪声校准 全局敏感度: 局部敏感度 平滑敏感度 噪声分布范围 自己的理解 写在前面的话 关于敏感度相关的知识,我认为这是差 ...
- mysql 钩子函数_SetWindowsHookEx原理(如何使用钩子,使用钩子hook其他进程的函数)...
基本概念 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的.当消息到达后,在目标窗口处理函数之前处理 ...
- npm包全局安装和局部安装,执行包命令有什么不同?
之前开发了一个npm的包.在实际应用中发现了一个问题.如果你想要直接执行这个包的命令,那么你就需要全局安装这个包.如果你只是局部安装,且没有在package.json文件中配置的话,就会提示该命令无法 ...
- leetcode 775. Global and Local Inversions | 775. 全局倒置与局部倒置(Java)
题目 https://leetcode.com/problems/global-and-local-inversions/ 题解 看了评论区答案. 局部倒置一定是全局倒置:局部倒置是连续递减: 所以只 ...
- Vue组件之全局组件与局部组件
组件 (Component) 是 Vue.js 最强大的功能之一.组件可以扩展 HTML 元素,封装可重用的代码.在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能.在有些情况下, ...
- 16-作用域(全局作用域及局部作用域)
16-作用域(全局作用域及局部作用域) //作用域 全局作用域 函数作用域 //函数的内部环境可以访问到所有外部环境的值,但是外部环境不能访问内部环境的值 //注意事项 //在全局变量和局部变量不同名 ...
最新文章
- 逐飞科技对于STC8H1K系列的单片机正交解码的资料以及实验
- 最直接的解决服务器宕机的方法
- HighNewTech:2019.08.09程序猿界大事件之【你好,我是鸿蒙OS】~【来了,老弟】—技术才是硬道理,开源方能建立新生态!
- ABAP 如何实现屏幕字段不可输入
- 【视频内含福利】原来手机套壳视频是这么做出来的
- 带你认识Flink容错机制的两大方面:作业执行和守护进程
- 微软将于6月24日发布下一代Windows
- matlab误码率分析,误码率分析 请大神帮忙解释下程序
- git remote 命令的用法
- Flask数据库学习
- 只用两行代码,我让Transformer推理加速了10倍
- php数组是否存在数组,php判断数组中是否存在某值
- Java学习之Xpath报错 Exception in thread “main“ java.lang.NoClassDefFoundError: org/jaxen/Namespa
- 计算机硬件安装装置,一种计算机硬件教学装置制造方法及图纸
- ac3168无线网卡驱动下载_REALTEK芯片无线网卡最新驱动!支持到10.15
- Android NDK SO库隐藏内部符号表
- Android设置输入法
- 在面试中脱颖而出的流程全解
- 实朴检测深交所上市:市值44亿 应收账款逾期6587万
- 未来十年计算机体系结构的历史和趋势