winform C#键盘钩子(Hook)拦截器,屏蔽键盘深入解析

钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。 
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。


运行机制
1、钩子链表和钩子子程:
每一个Hook都有一个与之相关联的指针列表,称之为钩子链表,由系统来维护。这个列表的指针指向指定的,应用程 序定义的,被Hook子程调用的回调函数,也就是该钩子的各个处理子程。当与指定的Hook类型关联的消息发生时,系统就把这个消息传递到Hook子程。 一些Hook子程可以只监视消息,或者修改消息,或者停止消息的前进,避免这些消息传递到下一个Hook子程或者目的窗口。最近安装的钩子放在链的开始, 而最早安装的钩子放在最后,也就是后加入的先获得控制权。

Windows 并不要求钩子子程的卸载顺序一定得和安装顺序相反。每当有一个钩子被卸载,Windows 便释放其占用的内存,并更新整个Hook链表。如果程序安装了钩子,但是在尚未卸载钩子之前就结束了,那么系统会自动为它做卸载钩子的操作。

钩子子程是一个应用程序定义的回调函数(CALLBACK Function),不能定义成某个类的成员函数,只能定义为普通的C函数。用以监视系统或某一特定类型的事件,这些事件可以是与某一特定线程关联的,也可以是系统中所有线程的事件。

KeyboardHook.cs 类

public class KeyboardHook
{
        private const int WH_KEYBOARD_LL = 13; //键盘 

        //键盘处理事件委托 ,当捕获键盘输入时调用定义该委托的方法. 
        private delegate int HookHandle(int nCode, int wParam, IntPtr lParam);

        //客户端键盘处理事件 
        public delegate void ProcessKeyHandle(HookStruct param, out bool handle);

        //接收SetWindowsHookEx返回值 
        private static int _hHookValue = 0;

        //勾子程序处理事件 
        private HookHandle _KeyBoardHookProcedure;

        //Hook结构 
        [StructLayout(LayoutKind.Sequential)]
        public class HookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }

        //设置钩子 
        [DllImport("user32.dll")]
        private static extern int SetWindowsHookEx(int idHook, HookHandle lpfn, IntPtr hInstance, int threadId);

        //取消钩子 
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        private static extern bool UnhookWindowsHookEx(int idHook);

        //调用下一个钩子 
        [DllImport("user32.dll")]
        private static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);

        //获取当前线程ID 
        [DllImport("kernel32.dll")]
        private static extern int GetCurrentThreadId();

        //Gets the main module for the associated process. 
        [DllImport("kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string name);

        private IntPtr _hookWindowPtr = IntPtr.Zero;

        //构造器 
        public KeyboardHook() { }

        //外部调用的键盘处理事件 
        private static ProcessKeyHandle _clientMethod = null;

        /// <summary> 
        /// 安装勾子 
        /// </summary> 
        /// <param name="hookProcess">外部调用的键盘处理事件</param> 
        public void InstallHook(ProcessKeyHandle clientMethod)
        {
            _clientMethod = clientMethod;

            // 安装键盘钩子 
            if (_hHookValue == 0)
            {
                _KeyBoardHookProcedure = new HookHandle(OnHookProc);

                _hookWindowPtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

                _hHookValue = SetWindowsHookEx(
                WH_KEYBOARD_LL,
                _KeyBoardHookProcedure,
                _hookWindowPtr,
                0);

                //如果设置钩子失败. 
                if (_hHookValue == 0) UninstallHook();
            }
        }

        //取消钩子事件 
        public void UninstallHook()
        {
            if (_hHookValue != 0)
            {
                bool ret = UnhookWindowsHookEx(_hHookValue);
                if (ret) _hHookValue = 0;
            }
        }

        //钩子事件内部调用,调用_clientMethod方法转发到客户端应用。 
        private static int OnHookProc(int nCode, int wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                //转换结构 
                HookStruct hookStruct = (HookStruct)Marshal.PtrToStructure(lParam, typeof(HookStruct));

                if (_clientMethod != null)
                {
                    bool handle = false;
                    //调用客户提供的事件处理程序。 
                    _clientMethod(hookStruct, out handle);
                    if (handle) return 1; //1:表示拦截键盘,return 退出 
                }
            }
            return CallNextHookEx(_hHookValue, nCode, wParam, lParam);
        }

}

Form窗体

  1. public partial class Form1 : Form

  2.    {

  3.       //勾子管理类 

  4.       private KeyboardHookLib _keyboardHook = null;

  5.       public frmKeyboardHook()

  6.       {

  7.          InitializeComponent();

  8.       }

  9.       private void button1_Click(object sender, EventArgs e)

  10.       {

  11.          //安装勾子 

  12.          _keyboardHook = new KeyboardHookLib();

  13.          _keyboardHook.InstallHook(this.OnKeyPress);

  14.       }

  15.       private void button2_Click(object sender, EventArgs e)

  16.       {

  17.          //取消勾子 

  18.          if (_keyboardHook != null) _keyboardHook.UninstallHook();

  19.       }

  20.       /// <summary> 

  21.       /// 客户端键盘捕捉事件. 

  22.       /// </summary> 

  23.       /// <param name="hookStruct">由Hook程序发送的按键信息</param> 

  24.       /// <param name="handle">是否拦截</param> 

  25.       public void OnKeyPress(KeyboardHookLib.HookStruct hookStruct, out bool handle)

  26.       {

  27.          handle = false; //预设不拦截任何键 

  28.          if (hookStruct.vkCode == 91) // 截获左win(开始菜单键)

  29.          {

  30.             handle = true;

  31.          }

  32.          if (hookStruct.vkCode == 92)// 截获右win

  33.          {

  34.             handle = true;

  35.          }

  36.          //截获Ctrl+Esc 

  37.          if (hookStruct.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control)

  38.          {

  39.             handle = true;

  40.          }

  41.          //截获alt+f4 

  42.          if (hookStruct.vkCode == (int)Keys.F4 && (int)Control.ModifierKeys == (int)Keys.Alt)

  43.          {

  44.             handle = true;

  45.          }

  46.          //截获alt+tab 

  47.          if (hookStruct.vkCode == (int)Keys.Tab && (int)Control.ModifierKeys == (int)Keys.Alt)

  48.          {

  49.             handle = true;

  50.          }

  51.          //截获F1 

  52.          if (hookStruct.vkCode == (int)Keys.F1)

  53.          {

  54.             handle = true;

  55.          }

  56.          //截获Ctrl+Alt+Delete 

  57.          if ((int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Alt + (int)Keys.Delete)

  58.          {

  59.             handle = true;

  60.          }

  61.          //如果键A~Z 

  62.          if (hookStruct.vkCode >= (int)Keys.A && hookStruct.vkCode <= (int)Keys.Z)

  63.          {

  64.             //挡掉B键 

  65.             if (hookStruct.vkCode == (int)Keys.B)

  66.             hookStruct.vkCode = (int)Keys.None; //设键为0 

  67.             handle = true;

  68.          }

  69.          Keys key = (Keys)hookStruct.vkCode;

  70.          label1.Text = "你按下:" + (key == Keys.None ? "" : key.ToString());

  71.       }

  72.    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/71549.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫数据存哪里|数据存储到文件的几种方式

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 爬虫请求解析后的数据&#xff0c;需要保存下来&#xff0c;才能进行下一步的处理&#xff0c;一般保存数据的方式有如下几种&#xff1a; 文件&#xff1a;txt、csv、excel、json等&#xff0c;保存数据量小。 关系型数据库…

Python小知识 - Python装饰器

Python装饰器 在Python中&#xff0c;装饰器是一个特殊的函数&#xff0c;可以将其他函数包装在装饰器函数中&#xff0c;并且将被包装的函数作为参数传递给装饰器函数。 使用装饰器的好处是可以自动在被包装的函数前后执行一些额外的代码&#xff0c;比如在函数执行前后打印日…

嵌入式开发-11 Linux下GDB调试工具

目录 1 GDB简介 2 GDB基本命令 3 GDB调试程序 1 GDB简介 GDB是GNU开源组织发布的一个强大的Linux下的程序调试工具。 一般来说&#xff0c;GDB主要帮助你完成下面四个方面的功能&#xff1a; 1、启动你的程序&#xff0c;可以按照你的自定义的要求随心所欲的运行程序&#…

RabbitMQ 常用运维命令

AMQP协议简介 AMQP&#xff0c;即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息&#xff0c;并不受客户端/中间件不同产品&#xff0c…

PaddleX:一站式、全流程、高效率的飞桨AI套件

随着ChatGPT引领的AI破圈&#xff0c;各行各业掀起了AI落地的潮流&#xff0c;从智能客服、智能写作、智能监控&#xff0c;到智能医疗、智能家居、智能金融、智能农业&#xff0c;谁能快速将AI与传统业务相结合&#xff0c;谁就将成为企业数字化和智能化变革的优胜者。然而&am…

Git 命令行查看仓库信息

目录 查看系统config ​编辑查看当前用户&#xff08;global&#xff09;配置 查看当前仓库配置信息 查看系统config git config --system --list 1 查看当前用户&#xff08;global&#xff09;配置 git config --global --list 1 查到的是email , name 等ssl签名信息&a…

机器学习实战-系列教程2:线性回归1(项目实战、原理解读、源码解读)

&#x1f308;&#x1f308;&#x1f308;机器学习 实战系列 总目录 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 机器学习实战-系列教程1&#xff1a;线性回归入门教程 机器学习实战-系列教程2&#xff1a;线性回归1 机器学习实战-系列教程3&am…

知识大杂烩(uniapp)

首先声明&#xff1a;不敢保证都管用&#xff0c;这是我自己实践得来的。 box-shadow: 这段 CSS 样式代码用于创建一个阴影效果&#xff0c;它是通过 box-shadow 属性来实现的。让我解释一下这段代码的含义&#xff1a; - box-shadow: 这是 CSS 的属性&#xff0c;用于添加阴影…

算法笔记:平衡二叉树

1 介绍 平衡二叉树&#xff08;AVL树&#xff09;是一种特殊的二叉搜索树&#xff08;BST&#xff09;&#xff0c;它自动确保树保持低高度&#xff0c;以便实现各种基本操作&#xff08;如添加、删除和查找&#xff09;的高效性能。 ——>时间都维持在了O(logN)它是一棵空…

百度百科词条怎么更新?怎么能顺利更新百科词条?

企业和个人百度百科词条的更新对于他们来说都具有重要的意义&#xff0c;具体如下&#xff1a; 对企业来说&#xff1a; 塑造品牌形象&#xff1a;百度百科是一个常被用户信任并参考的知识平台&#xff0c;通过更新企业词条可以提供准确、全面的企业信息&#xff0c;帮助企业塑…

算法专题:前缀和

文章目录 Acwing&#xff1a;前缀和示例2845.统计趣味子数组的数目思路容易理解的写法&#xff1a;前缀和两层循环存在问题&#xff1a;超时 优化写法&#xff1a;两数之和思路&#xff0c;转换为哈希表 前缀和&#xff0c;就是求数组中某一段的所有元素的和。 求子数组中某一…

Unity3D 连接 SQLite 作为数据库基础功能【详细图文教程】

一、简单介绍一下SQLite的优势&#xff08;来自ChatGPT&#xff09; 轻量级: SQLite是一个嵌入式数据库引擎&#xff0c;它的库文件非常小巧&#xff0c;没有独立的服务器进程&#xff0c;适用于嵌入到其他应用程序中&#xff0c;对于轻量级的项目或移动应用程序非常适用。零配…

Golang RabbitMQ实现的延时队列

文章目录 前言一、延时队列与应用场景二、RabbitMQ如何实现延时队列实现延时队列的基本要素整体的实现原理如下 三、Go语言实战生产者消费者 前言 之前做秒杀商城项目的时候使用到了延时队列来解决订单超时问题&#xff0c;本博客就总结一下Golang是如何利用RabbitMQ实现的延时…

结构体对齐原理及在STM32中的设计原则和实现

在嵌入式系统开发中&#xff0c;结构体作为一种常见的数据组织方式&#xff0c;在内存中的布局方式对于程序性能和内存占用具有重要影响。本文将深入探讨单片机C语言中的结构体对齐原理、重要性以及不同的对齐方式&#xff0c;并通过示例演示结构体对齐如何影响内存占用、访问性…

SMT贴片制造:专业、现代、智能的未来之选

在现代科技的快速发展下&#xff0c;SMT贴片制造作为电子元器件的核心工艺之一&#xff0c;正以其专业、现代和智能的特点成为未来的首选。 随着电子产品越来越小型化&#xff0c;传统的手工焊接已经无法满足高速、高精度、高稳定性的要求。而SMT贴片制造作为一种先进的表面贴…

说说复合索引之最左前缀原理?

分析&回答 MySQL中的索引可以以一定顺序引用多个列&#xff0c;这种索引叫做复合&#xff08;联合&#xff09;索引。 如果表 Ta 中存在索引 A、B、&#xff08;C、D&#xff09; 规则1&#xff1a;全列匹配 SELECT * FROM Ta WHERE E F1 AND A 10001; 复制代码 若没…

【代码随想录】Day 50 动态规划11 (买卖股票Ⅲ、Ⅳ)

买卖股票Ⅲ https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/ 无语了。。。 写的很好就是怎么都过不了。。。 还是就用代码随想录的写法吧。。。 class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();vector&…

权限提升-Windows本地提权-AT+SC+PS命令-进程迁移-令牌窃取-getsystem+UAC

权限提升基础信息 1、具体有哪些权限需要我们了解掌握的&#xff1f; 后台权限&#xff0c;网站权限&#xff0c;数据库权限&#xff0c;接口权限&#xff0c;系统权限&#xff0c;域控权限等 2、以上常见权限获取方法简要归类说明&#xff1f; 后台权限&#xff1a;SQL注入,数…

DCMM数据能力成熟度评估模型--学习笔记(1)

DCMM数据能力成熟度评估模型--学习笔记 1、DCMM简介、结构组成和成熟度评估等级划分1.1 DCMM简介1.2 DCMM结构组成1.3 DCMM关键过程域1.3.1、数据战略&#xff08;指导方针&#xff09;1.3.2、数据治理 &#xff08;机制保障&#xff09;1.3.3、数据架构 (施工图纸)1.3.4、数据…

【Java】线程都有哪几种状态

文章目录 前言传统线程模型&#xff08;操作系统&#xff09;中线程状态Java线程中的状态线程的运行流程 前言 首先我们要知道&#xff0c;在传统&#xff08;操作系统&#xff09;的线程模型中线程被分为五种状态&#xff0c;在java线程中&#xff0c;线程被分为六种状态。 …