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 = ,
WH_JOURNALPLAYBACK = ,
/// <summary>
/// 进程钩子
/// </summary>
WH_KEYBOARD = , /// <summary>
/// 底层键盘钩子 全局钩子就是用这个 /// </summary>
WH_KEYBOARD_LL = ,
} public enum HC_CODE : int
{
HC_ACTION = ,
HC_GETNEXT = ,
HC_SKIP = ,
HC_NOREMOVE = ,
HC_NOREM = ,
HC_SYSMODALON = ,
HC_SYSMODALOFF =
} /// <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[];
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() > && this.OnKeyDown != null)
{
this.OnKeyDown(this, keyEvent);
}
else if (lParam.ToInt32() < && this.OnKeyUp != null)
{
this.OnKeyUp(this, keyEvent);
}
}
if (ShortcutManagement.s_bHotkeyUsed)
{
ShortcutManagement.s_bHotkeyUsed = false;
return ;
} 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
版权声明:本文为博主原创文章,转载请附上博文链接!
通过这次认知,意识到,以后如果要做这些接触相关的api的时候,我们应该尽量去查官方文档,而不是一开始就是查看别人的博客。应该以官方文档为主。一定要记住键盘钩子事件。
32位和64位的系统不一样。
C#全局钩子和局部钩子记录的更多相关文章
- Django学习——分页器基本使用、分页器终极用法、forms组件之校验字段、forms组件之渲染标签、forms组件全局钩子,局部钩子
内容 1 分页器基本使用 2 分页器终极用法 3 forms组件之校验字段 1 前端 <!DOCTYPE html> <html lang="en"> &l ...
- form表单钩子,局部钩子和全局钩子
form表单源码解析: 局部钩子: 全局钩子:
- Django学习笔记之form组件的局部钩子和全局钩子
本文通过注册页面的form组件,查看其中使用的全局钩子和局部钩子. # Create your views here. class RegForm(forms.Form): username = fo ...
- Django学习笔记(14)——AJAX与Form组件知识补充(局部钩子和全局钩子详解)
我在之前做了一个关于AJAX和form组件的笔记,可以参考:Django学习笔记(8)——前后台数据交互实战(AJAX):Django学习笔记(6)——Form表单 我觉得自己在写Django笔记(8 ...
- Django12-ModelForm中创建局部钩子和全局钩子
一.局部钩子 命名规则为clean_对象名称,例如上面定义了username.pwd对象,那么可以定义clean_username.clean_pwd的局部钩子进行规则校验 1.例子:定义一个手机号校 ...
- django----利用Form 实现两次密码输入是否一样 ( 局部钩子和全局钩子 )
from django import forms # 导入表单模块 from django.core.exceptions import ValidationError class RegisterF ...
- (32)forms组件(渲染自建规则:局部钩子函数和全局钩子函数)
要达成渲染自建规则 1.局部钩子函数(某个字段,自定意义规则,不如不能以sb开头,数据库已存在等) 2.全局钩子函数(校验两次密码是否一致) 3.使用css样式 register.html <! ...
- django基础之day09,创建一个forms表单组件进行表单校验,知识点:error_messages,label,required,invalid,局部钩子函数,全局钩子函数, forms_obj.cleaned_data,forms_obj.errors,locals(), {{ forms.label }}:{{ forms }},{{ forms.errors.0 }}
利用forms表单组件进行表单校验,完成用户名,密码,确认密码,邮箱功能的校验 该作业包含了下面的知识点: error_messages,label,required,invalid,局部钩子函数,全 ...
- Django框架(十四)-- forms组件、局部钩子、全局钩子
一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语 ...
随机推荐
- TMS320VC5509总线驱动LED灯
1. 重新建立的工程,需要添加宏定义才行 CHIP_5509 2. 驱动LED用的是74LVC573锁存器,LE高电平时,Q1=D0,LE低电平时,Q1=之前的状态,下面是数据总线 看下地址总线 看下 ...
- 洛咕P4542 [ZJOI2011]营救皮卡丘
套路题? 感觉讲不清,先写建图 把每个点拆成两个,A和B, S->Ai流量=1费用=0,Bi->T流量=1费用=0, Ai->Bj流量=1费用=ij最短路 还有一个特殊的s点,S-& ...
- 洛谷 P4593 [TJOI2018]教科书般的亵渎
洛谷 P4593 [TJOI2018]教科书般的亵渎 神仙伯努利数...网上一堆关于伯努利数的东西但是没有证明,所以只好记结论了? 题目本质要求\(\sum_{i=1}^{n}i^k\) 伯努利数,\ ...
- c3p0 ComboPooledDataSource无法识别的问题
maven项目下,基本就是导错包了的问题. 下面那个才是连接池的.
- Linux 挂载 xshell 命令 配置环境变量
- 用 Python 给程序加个进度条,让你的看起来更炫酷?
对于开发或者运维来说,使用 Python 去完成一些跑批任务,或者做一些监控事件是非常正常的情况.那么如何有效地监控任务的进度?除了在任务中加上 Log 外,还能不能有另一种方式来了解任务进展到哪一步 ...
- 从零搭建HBase集群
本文从零开始搭建大数据集群,涉及Linux集群安装搭建,Hadoop集群搭建,HBase集群搭建,Java接口封装,对接Java的C#类库封装 Linux集群搭建与配置 Hadoop集群搭建与配置 H ...
- CentOS搭建Docker Hub私有仓库
docker pull registry拉取registry镜像 docker images查看镜像 docker run -d -p 5000:5000 -v /opt/data/registry: ...
- python魔法方法大全
1.python魔法方法详解: python魔法方法是可以修改重载的,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而 ...
- Unity 几何着色器
Unity 几何着色器 shaderGeometry Shader几何着色器 Unity 几何着色器 如果学习不能带来价值,那将毫无意义 简介 在顶点和片段着色器之间有一个可选的着色器,叫做几 ...