c# 钩子学习笔记

C#钩子学习笔记

什么是钩子

Windows操作系统为我们提供了许多钩子(Hooks),如键盘钩子、鼠标钩子、Windows消息钩子、时间戳钩子等。钩子可以让我们在系统层面对各种事件消息进行拦截、监控、修改或者定制化输出等操作。

钩子的分类

Windows中的钩子有很多种,我们可以将它们大体分为两类:

  1. 系统钩子 (system-wide hook):作用于整个系统,能够接收到所有相关事件消息。
  2. 应用程序钩子 (application-specific hook):只作用于当前应用程序,只能接收到当前应用程序相关的事件消息。

钩子的实现

我们可以使用C#代码来实现钩子,具体步骤如下:

  1. 定义一个回调函数来处理钩子事件,回调函数必须为标准的回调委托类型。
  2. 通过调用Win32 API的SetWindowsHookEx函数来注册钩子,获取钩子句柄。
  3. 使用Win32 API的UnhookWindowsHookEx函数来卸载钩子,及时释放系统资源。

示例1:键盘钩子

以下是一个基于C#和Win32 API的系统键盘钩子实现。

using System;
using System.Runtime.InteropServices;

namespace KeyboardHookDemo {
    class Program {
        //定义回调委托
        private delegate IntPtr HookDelegate(int nCode, IntPtr wParam, IntPtr lParam);

        //定义键盘输入事件枚举
        private enum KeyboardMsg {
            WmKeyDown = 0x0100,
            WmKeyUp = 0x0101
        }

        //定义键盘状态检查枚举
        private enum KeyboardState {
            KeyDown = 0x8000,
            AltKeyPressed = 0x2000,
            CtrlKeyPressed = 0x0008,
            ShiftKeyPressed = 0x0100
        }

        //定义钩子事件回调函数
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
            //判断是否为键盘输入事件
            if (nCode < 0 || (int)wParam != (int)KeyboardMsg.WmKeyDown) {
                //传递给下一个钩子
                return CallNextHookEx(hookId, nCode, wParam, lParam);
            }

            //获取键盘事件的基本信息
            int vkCode = Marshal.ReadInt32(lParam);
            bool isAltKeyPress = ((GetKeyState((int)KeyboardState.AltKeyPressed) & KeyboardState.AltKeyPressed) != 0);
            bool isCtrlKeyPress = ((GetKeyState((int)KeyboardState.CtrlKeyPressed) & KeyboardState.CtrlKeyPressed) != 0);
            bool isShiftKeyPress = ((GetKeyState((int)KeyboardState.ShiftKeyPressed) & KeyboardState.ShiftKeyPressed) != 0);

            //输出按键信息
            Console.WriteLine(string.Format("{0} {1} {2} {3}", isAltKeyPress, isCtrlKeyPress, isShiftKeyPress, (Keys)vkCode));

            //传递给下一个钩子
            return CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        //导入Windows API函数
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, HookDelegate lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern short GetKeyState(int nVirtKey);

        [DllImport("kernel32.dll")]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        //定义钩子ID
        private static IntPtr hookId = IntPtr.Zero;

        static void Main(string[] args) {
            //注册钩子
            hookId = SetWindowsHookEx((int)13, new HookDelegate(HookCallback), GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);

            //等待程序退出
            Application.Run();

            //卸载钩子
            UnhookWindowsHookEx(hookId);
        }
    }
}

示例2:鼠标钩子

以下是一个基于C#和Win32 API的应用程序鼠标钩子实现。

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace MouseHookDemo {
    class Program {

        //定义回调委托
        private delegate IntPtr HookDelegate(int nCode, IntPtr wParam, IntPtr lParam);

        //定义鼠标输入事件枚举
        private enum MouseMsg {
            WmMouseMove = 0x200,
            WmLButtonDown = 0x201,
            WmLButtonUp = 0x202,
            WmRButtonDown = 0x204,
            WmRButtonUp = 0x205,
            WmMButtonDown = 0x207,
            WmMButtonUp = 0x208,
            WmMouseWheel = 0x20A
        }

        //定义鼠标状态检查枚举
        private enum MouseState {
            LeftButtonPressed = 0x0001,
            RightButtonPressed = 0x0002,
            MiddleButtonPressed = 0x0010,
            AltKeyPressed = 0x0002,
            CtrlKeyPressed = 0x0008,
            ShiftKeyPressed = 0x0100
        }

        //定义钩子事件回调函数
        private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam) {
            //判断是否为鼠标输入事件
            if (nCode < 0 || wParam == IntPtr.Zero) {
                //传递给下一个钩子
                return CallNextHookEx(hookId, nCode, wParam, lParam);
            }

            //获取鼠标事件的基本信息
            MouseMsg msg = (MouseMsg)wParam;
            Point pt = new Point();
            GetCursorPos(out pt);
            short wheelDelta = (short)0;
            if (msg == MouseMsg.WmMouseWheel) {
                wheelDelta = (short)HIWORD((uint)lParam);
            }
            bool isCtrlKeyPress = ((GetKeyState((int)MouseState.CtrlKeyPressed) & MouseState.CtrlKeyPressed) != 0);
            bool isShiftKeyPress = ((GetKeyState((int)MouseState.ShiftKeyPressed) & MouseState.ShiftKeyPressed) != 0);
            bool isAltKeyPress = ((GetKeyState((int)MouseState.AltKeyPressed) & MouseState.AltKeyPressed) != 0);
            bool isLeftButtonPressed = ((GetKeyState((int)MouseState.LeftButtonPressed) & MouseState.LeftButtonPressed) != 0);
            bool isRightButtonPressed = ((GetKeyState((int)MouseState.RightButtonPressed) & MouseState.RightButtonPressed) != 0);
            bool isMiddleButtonPressed = ((GetKeyState((int)MouseState.MiddleButtonPressed) & MouseState.MiddleButtonPressed) != 0);

            //输出鼠标事件信息
            Console.WriteLine(string.Format("{0} {1} {2} {3} {4} {5} {6} ({7},{8}) {9}", isAltKeyPress, isCtrlKeyPress, isShiftKeyPress, isLeftButtonPressed, isRightButtonPressed, isMiddleButtonPressed, wheelDelta, pt.X, pt.Y, msg));

            //传递给下一个钩子
            return CallNextHookEx(hookId, nCode, wParam, lParam);
        }

        //导入Windows API函数
        [DllImport("user32.dll")]
        private static extern IntPtr SetWindowsHookEx(int idHook, HookDelegate lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll")]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll")]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll")]
        private static extern short GetKeyState(int nVirtKey);

        [DllImport("user32.dll")]
        private static extern bool GetCursorPos(out Point lpPoint);

        [DllImport("user32.dll")]
        private static extern uint GetMessagePos();

        private static int HIWORD(uint dword) {
            return (int)(short)(dword >> 16);
        }

        //定义钩子ID
        private static IntPtr hookId = IntPtr.Zero;

        static void Main(string[] args) {
            //注册钩子
            hookId = SetWindowsHookEx((int)14, new HookDelegate(HookCallback), GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);

            //等待程序退出
            Application.Run();

            //卸载钩子
            UnhookWindowsHookEx(hookId);
        }
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:c# 钩子学习笔记 - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • asp.net 添加水印的代码(已测试)

    根据您提供的主题,我将为您详细讲解如何在ASP.NET中添加水印的代码(已测试)。 简介 添加水印是网站开发中的常见需求之一。本篇攻略将帮助您实现一个简单的ASP.NET添加水印功能,并且已经过测试,代码经过了验证和校验,可以在常规的web应用程序中运行。 前置条件 在使用本文中的代码示例之前,请确保您已经满足以下前置条件: 拥有一个ASP.NET Web …

    C# 2023年5月31日
    00
  • C# 游戏外挂实现核心代码

    C# 游戏外挂实现核心代码,通常包含以下几个步骤: 1. 找到游戏内存地址 首先需要找到游戏内存地址,这通常需要使用一些常见的内存查找技术,例如静态地址查找、动态地址查找等等。找到游戏内存地址之后,我们就可以通过读写内存操作实现对游戏数据的修改和访问。 2. 代码注入 代码注入是指将自己编写的代码注入到游戏进程中,从而实现对游戏的控制。这可以通过使用一些第三…

    C# 2023年6月3日
    00
  • JS、CSS和HTML实现注册页面

    下面是关于“JS、CSS和HTML实现注册页面”的完整攻略: 1.确定页面设计 在开始实现注册页面之前,我们需要先确定页面设计。包括布局、元素的排列和样式等方面。可以利用工具软件或者手绘草稿来完成页面设计。 2.HTML结构与元素 经过页面设计之后,我们就可以开始构建HTML结构和元素了。在这个过程中,我们需要考虑页面元素和布局,比如表单、按钮等。 以下示例…

    C# 2023年5月31日
    00
  • C#实现飞行棋(Winform)

    C#实现飞行棋(Winform)攻略 基本流程 飞行棋是一个简单的棋类游戏,玩家通过掷骰子前进,最先将所有棋子走完的玩家获胜。实现游戏的基本流程如下: 新建WinForm窗体,添加控件 点击“开始”按钮,初始化游戏数据 玩家掷骰子,随机移动棋子 判断是否有棋子达到终点,如有则获胜 切换到下一个玩家,返回步骤3 代码实现 窗体设计 使用Visual Studi…

    C# 2023年6月6日
    00
  • C#图表算法之无向图

    C#图表算法之无向图 什么是无向图 无向图是图的一种,其中边没有方向。也就是说,图中的节点之间的关系是没有顺序的,就像两个人之间的友谊关系不分先后。 在 C# 中,我们可以使用 Dictionary<T1, List<T2>> 来表示一个无向图。其中 T1 表示节点,T2 表示节点和它相邻的节点组成的列表。 构建无向图 下面是一个构建…

    C# 2023年6月1日
    00
  • C# 生转换网页为pdf

    下面我将详细讲解C#如何实现将网页转换为PDF的完整攻略,包括步骤和代码示例。 步骤1:下载使用合适的PDF组件 要生成PDF文件,我们需要使用PDF生成组件。C#中常用的PDF组件包括iTextSharp、PDFSharp以及Winnovative等。这里,我们以iTextSharp为例,进行讲解。 步骤2:创建一个PDF文档对象 在使用iTextShar…

    C# 2023年6月6日
    00
  • 详细分析c# 运算符重载

    详细分析C#运算符重载 C#运算符重载是一种在类定义中定义特定运算符的方式。通过对运算符进行重载,我们可以为自定义类型定义自定义算术和逻辑行为。本文将介绍如何实现C#运算符重载,并提供两个实际的示例。 1、什么是C#运算符重载 在C#中,一些运算符如 +、-、*、/、< 等都是具有预定义行为的。当我们对 int、float、double、string等…

    C# 2023年6月7日
    00
  • 基于C#解决库存扣减及订单创建时防止并发死锁的问题

    首先需要明确的是,在高并发情况下,库存扣减和订单创建操作可能会引发数据不一致的问题,例如出现超卖的情况。为了避免发生这种情况,需要对库存扣减及订单创建进行并发控制。 在C#平台下,可以利用锁机制来进行并发控制。具体实现方式如下: 对库存扣减与订单创建的关键代码块(例如数据库操作)加锁,确保同时只有一个线程能够访问该关键代码块。这可以使用C#语言中的lock关…

    C# 2023年5月14日
    00
合作推广
合作推广
分享本页
返回顶部