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日

相关文章

  • Unity的IPostBuildPlayerScriptDLLs实用案例深入解析

    Unity的IPostBuildPlayerScriptDLLs实用案例深入解析 什么是IPostBuildPlayerScriptDLLs IPostBuildPlayerScriptDLLs是Unity中的一个接口类,可以在BuildPlayer过程中自定义处理DLL文件。通过在Unity编辑器中实现该接口,可以在生成构建设置时自定义处理DLL文件,从而…

    C# 2023年6月7日
    00
  • C#实现动态执行字符串脚本(优化版)的示例代码

    让我来详细讲解“C#实现动态执行字符串脚本(优化版)的示例代码”的完整攻略。 首先,需要明确的是,我们要实现的目标是动态执行字符串脚本,所以需要满足以下要求: 能够将字符串解析为C#代码 能够动态地将解析出来的代码编译成程序集 能够调用编译后的程序集中的方法 针对上述要求,我们需要利用C#的编译器,通过代码生成器将字符串转为C#代码,并通过编译器将生成后的代…

    C# 2023年5月15日
    00
  • C#实现窗体淡入淡出效果的方法总结

    C#实现窗体淡入淡出效果的方法总结 1. 引言 在C#编写窗体应用程序时,我们可能会需要为窗体增加各种特效来增强用户的体验感。其中,淡入淡出效果是一种比较常见的特效方式,可以使窗体的显示效果更加平滑自然。那么,本篇文章将对C#实现窗体淡入淡出效果的方法进行总结。 2. 方法总结 2.1 使窗体透明度渐变 首先,我们可以通过改变窗体的透明度,来实现窗体淡入淡出…

    C# 2023年6月7日
    00
  • Entity Framework使用DBContext实现增删改查

    以下是使用EntityFramework使用DBContext实现增删改查的完整攻略: 1. 什么是EntityFramework EntityFramework是微软的一个ORM(对象关系映射)框架,它可以将数据库中的表映射为.NET中的对象,从而方便地进行数据库操作。 2. 什么是DBContext DBContext是EntityFramework中的…

    C# 2023年5月12日
    00
  • C#垃圾回收机制的详细介绍

    C#是一种托管式语言,这意味着它带有自己的垃圾回收机制,可以帮助程序员管理内存。以下是C#中垃圾回收机制的详细介绍: 什么是垃圾回收? 在程序执行期间,每次分配内存时,都需要在堆上分配内存,当不再使用该内存时,需要将其释放并还回给操作系统。垃圾回收是一种内存管理机制,在没有明确指定释放内存的情况下,自动释放不再使用的内存。 C#中的垃圾回收机制 C#的垃圾回…

    C# 2023年6月8日
    00
  • ES6 Iterator遍历器原理,应用场景及相关常用知识拓展详解

    ES6 Iterator遍历器原理,应用场景及相关常用知识拓展 1. Iterator遍历器基本概念 Iterator遍历器是一个可以迭代访问集合中元素的接口,它是一种统一的遍历机制,为各种不同类型的数据结构提供了一种统一的遍历方式。 在ES6中,Iterator遍历器是一种统一的协议,也就是说只要一个对象实现了Iterator遍历器协议,就可以通过这种协议…

    C# 2023年6月8日
    00
  • .NETCore基于RabbitMQ实现延时队列的两方法

    以下是“.NETCore基于RabbitMQ实现延时队列的两方法”的完整攻略: 什么是延时队列 延时队列是一种特的消息队列,它可以在一时间后才将消息发送到消费者。延时队列通常用于实现定时任务、消息重试等功能。 基于RabbitMQ实现延时队列的两种方法 RabbitMQ是一种流行的消息队列系统,它支持延时队列。以下两种基于RabbitMQ实现延时队列的方法:…

    C# 2023年5月12日
    00
  • 基于 .NET 6 的ASP.NET Core启动地址配置方法及优先级顺序

    基于 .NET 6 的ASP.NET Core启动地址配置方法及优先级顺序 在ASP.NET Core中,我们可以通过配置启动地址来指定应用程序的监听地址。本攻略将详细介绍基于.NET 6的ASP.NET Core启动地址配置方法及优先级顺序,并提供两个示例说明。 启动地址配置方法 以下是基于.NET 6的ASP.NET Core启动地址配置方法: 在Pro…

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