消息钩子函数入门篇.docx

合集下载

5分钟掌握Python中的Hook钩子函数

5分钟掌握Python中的Hook钩子函数

5分钟掌握Python中的Hook钩子函数1. 什么是Hook经常会听到钩子函数(hook function)这个概念,最近在看目标检测开源框架mmdetection,里面也出现大量Hook的编程方式,那到底什么是hook?hook的作用是什么?•what is hook ?钩子hook,顾名思义,可以理解是一个挂钩,作用是有需要的时候挂一个东西上去。

具体的解释是:钩子函数是把我们自己实现的hook函数在某一时刻挂接到目标挂载点上。

•hook函数的作用举个例子,hook的概念在windows桌面软件开发很常见,特别是各种事件触发的机制; 比如C++的MFC程序中,要监听鼠标左键按下的时间,MFC提供了一个onLeftKeyDown的钩子函数。

很显然,MFC框架并没有为我们实现onLeftKeyDown具体的操作,只是为我们提供一个钩子,当我们需要处理的时候,只要去重写这个函数,把我们需要操作挂载在这个钩子里,如果我们不挂载,MFC事件触发机制中执行的就是空的操作。

从上面可知•hook函数是程序中预定义好的函数,这个函数处于原有程序流程当中(暴露一个钩子出来)•我们需要再在有流程中钩子定义的函数块中实现某个具体的细节,需要把我们的实现,挂接或者注册(register)到钩子里,使得hook 函数对目标可用•hook 是一种编程机制,和具体的语言没有直接的关系•如果从设计模式上看,hook模式是模板方法的扩展•钩子只有注册的时候,才会使用,所以原有程序的流程中,没有注册或挂载时,执行的是空(即没有执行任何操作)本文用python来解释hook的实现方式,并展示在开源项目中hook的应用案例。

hook函数和我们常听到另外一个名称:回调函数(callback function)功能是类似的,可以按照同种模式来理解。

2. hook实现例子据我所知,hook函数最常使用在某种流程处理当中。

这个流程往往有很多步骤。

typescript 钩子函数

typescript 钩子函数

TypeScript钩子函数1. 定义钩子函数(Hook)是指在某个特定时间点被自动调用的函数,可以在这个时间点执行一些特定的操作。

在TypeScript中,钩子函数常常用于对类方法的前后进行拦截或扩展。

2. 用途钩子函数可以帮助我们实现以下功能:•在方法调用前进行权限验证或参数校验;•在方法调用后进行日志记录或错误处理;•在方法执行过程中进行状态监控或性能统计等。

通过使用钩子函数,我们可以将这些通用的功能代码从业务逻辑中抽离出来,使得代码更加清晰、可维护和可复用。

3. 工作方式在TypeScript中,我们可以使用装饰器(Decorator)来定义和使用钩子函数。

装饰器是一种特殊类型的声明,它能够被附加到类声明、方法、属性或参数上,并且能够修改类的行为。

下面是一个简单的示例,演示了如何使用装饰器来定义一个前置钩子函数:function before(target: any, propertyKey: string, descriptor: PropertyDescript or) {const originalMethod = descriptor.value;descriptor.value = function (...args: any[]) {console.log('Before method execution');return originalMethod.apply(this, args);};}class Example {@beforegreet(name: string) {console.log(`Hello, ${name}!`);}}example.greet('Alice');在上面的示例中,我们定义了一个名为before的装饰器函数。

这个装饰器函数接收三个参数:target表示被装饰的类的原型对象,propertyKey表示被装饰的方法名,descriptor表示被装饰方法的属性描述符。

钩子技术介绍及函数使用

钩子技术介绍及函数使用

钩子技术介绍及函数使用当你创建一个钩子时,WINDOWS系统会创建一个数据结构,该结构包含了您创建的钩子的信息,安装钩子则是把该结构体插入到系统钩子列表中去,注意:新插入的放置到旧的前面。

当指定的钩子事件被触发后,局部钩子只需要调用进程中的钩子函数来预处理事件,全局钩子则需要把处理插入到其他地址空间,要做到这一点,就需要有一个动态连接库,把钩子函数放到库中。

但有两个是例外,就是日志钩子和日志回放钩子,它是一种比较特殊的钩子,它可以挂载到系统范围内的任何进程中,而且不需要另外编写一个dll来映射到其他进程的内存空间之中(关于日志钩子,以后有机会再详细介绍)。

一、钩子的分类:安装不同的钩子,可以截获监视不同的消息类型,有针对的对所需要的消息进行过滤和处理,钩子主要分以下几类:WH_CALLWNDPROC 发送到窗口的消息。

由SendMessage触发WH_CALLWNDPROCRET 发送到窗口的消息。

由SendMessage处理完成返回时触发WH_GETMESSAGE 发送到窗口的消息。

GetMessage或PeekMessage 触发WH_KEYBROAD 键盘钩子,键盘触发消息。

WM_KEYUP或WM_KEYDOWN消息WH_KEYBROAD_LL 地层键盘钩子WH_MOUSE 鼠标钩子,查询鼠标事件消息WH_MOUSE_LL 低层键盘钩子WH_HARDWARE 非鼠标、键盘消息时WH_MSGFILTER 对话框、菜单或滚动条要处理一个消息时。

该钩子是局部的。

WH_SYSMSGFILTER 同WH_MSGFILTER一样,系统范围的。

WH_DEBUG 调试钩子,用来给钩子函数除错WH_JOURNALRECORD 监视和记录输入事件WH_JOURNALPLAYBACK 回放用WH_JOURNALRECORD记录事件WH_SHELL 外壳钩子,当关于WINDOWS外壳事件发生时触发.WH_CBT 当基于计算机的训练(CBT)事件发生时WH_FOREGROUNDIDLE 前台应用程序线程变成空闲时候,钩子激活。

钩子函数讲解

钩子函数讲解

钩⼦函数讲解钩⼦,⼏乎所有的键盘监控程序都使⽤钩⼦机制来捕获系统的击键信息。

⼤家知道,在DOS操作系统下,如果要截获某种系统功能,可以在编程中采取截获中断的办法,⽐如要获取击键信息,可以使⽤9号中断调⽤,要获取应⽤程序对⽂件操作功能的调⽤可以截获21号中断。

DOS下截获中断的⽅法是这样的随意和⽅便,不论是驱动程序还是应⽤程序都可以操作,这样就给⼀些恶意程序留下了可乘之机,对系统的安全造成了极⼤的隐患。

⽽在Windows 2000下就不同了,Windows 2000采⽤了保护模式,在保护模式下的中断描述符表是受系统保护的,应⽤程序是不可能再通过修改中断向量来截获系统中断了。

这在提供了更⾼安全性的同时,实际上对应⽤程序在调⽤底层功能⽅⾯造成了很⼤的不便。

不过,Windows采取了⼀些变通的⽅法,将⼀些系统的底层调⽤封装在了⾃⼰的API函数中,通过向⽤户提供接⼝使⽤户可以受限的使⽤⼀些系统调⽤。

钩⼦,⼏乎所有的键盘监控程序都使⽤钩⼦机制来捕获系统的击键信息。

⼤家知道,在DOS操作系统下,如果要截获某种系统功能,可以在编程中采取截获中断的办法,⽐如要获取击键信息,可以使⽤9号中断调⽤,要获取应⽤程序对⽂件操作功能的调⽤可以截获21号中断。

DOS下截获中断的⽅法是这样的随意和⽅便,不论是驱动程序还是应⽤程序都可以操作,这样就给⼀些恶意程序留下了可乘之机,对系统的安全造成了极⼤的隐患。

⽽在Windows 2000下就不同了,Windows 2000采⽤了保护模式,在保护模式下的中断描述符表是受系统保护的,应⽤程序是不可能再通过修改中断向量来截获系统中断了。

这在提供了更⾼安全性的同时,实际上对应⽤程序在调⽤底层功能⽅⾯造成了很⼤的不便。

不过,Windows采取了⼀些变通的⽅法,将⼀些系统的底层调⽤封装在了⾃⼰的API函数中,通过向⽤户提供接⼝使⽤户可以受限的使⽤⼀些系统调⽤。

TIPS:钩⼦是Windows的消息处理机制中提供的⼀个监视点,应⽤程序可以在这⾥安装⼀个过滤程序,这样就可以在系统中的消息流到达⽬的程序前监控它们。

使用钩子函数

使用钩子函数

procedure FormCreate(Sender: TObject);procedure FormDestroy(Sender: TObject);end;{声明键盘钩子回调函数; 其参数传递方式要用 API 的 stdcall}function KeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; st dcall;varForm1: TForm1;implementation{$R *.DFM}varhook: HHOOK; {定义一个钩子句柄}{实现键盘钩子回调函数}function KeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; beginif (wParam = 65) then Beep; {每拦截到字母 A 会发声}Result := CallNextHookEx(hook, nCode, wParam, lParam);end;{设置键盘钩子}procedure TForm1.FormCreate(Sender: TObject);beginhook := SetWindowsHookEx(WH_KEYBOARD, @KeyHook, 0, GetCurrentThreadID); end;{释放键盘钩子}procedure TForm1.FormDestroy(Sender: TObject);beginUnhookWindowsHookEx(hook);end;end.尽管这个例子已经很简单了, 但还不足以让人明白彻底; 下面还得从更简单的开始.使用钩子函数[2]钩子函数虽然不多, 但其参数复杂, 应该从参数入手才能深入进去.UnhookWindowsHookEx 只需要SetWindowsHookEx 返回的钩子句柄作参数, 这个简单;先看看SetWindowsHookEx 的声明:SetWindowsHookEx(idHook: Integer; {钩子类型}lpfn: TFNHookProc; {函数指针}hmod: HINST; {包含钩子函数的模块(EXE、DLL)的句柄}dwThreadId: DWORD {关联的线程}): HHOOK;第一个参数非常麻烦, 从后面说:参数四dwThreadId : 在设置全局钩子时这个参数一般是0, 表示关联所有线程; 本例是线程级的钩子, 所以是GetCurrentThreadId.参数三hmod: 是模块实例的句柄, 在EXE 和DLL 中都可以用HInstance 得到当前实例的句柄; 直接用API 也可以:GetModuleHandle(nil).参数二lpfn: 是钩子函数的指针, 用@ 和Addr 函数都可以得到函数指针; 这里的关键是那个钩子函数:首先不同的钩子类型对应着不同的钩子函数结构, Win32 共有14 种钩子类型, 这是详细注释;本例用的是键盘钩子, 键盘钩子的回调函数的参数结构在这里, 我们定义的函数名无所谓, 参数必须按照Windows的规定来.还有, 这个回调函数的调用惯例必须是: stdcall; 我们在上例中是先在接口区声明, 如果不要声明直接实现, 也不能忘了这个stdcall.根据以上说明, 做如下修改:SetWindowsHookEx 的参数有变通;并且取消了钩子函数在接口区的声明, 是直接实现的;取消了拦截条件, 现在只要是键盘消息全都拦截.unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;typeTForm1 = class(TForm)procedure FormCreate(Sender: TObject);procedure FormDestroy(Sender: TObject);end;varForm1: TForm1;implementation{$R *.DFM}varhook: HHOOK; {定义一个钩子句柄}{现在这个钩子函数没有在接口区声明, 这里必须指定参数调用方式: stdcall}function KeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; st dcall;beginBeep;Result := CallNextHookEx(hook, nCode, wParam, lParam);end;{设置键盘钩子}procedure TForm1.FormCreate(Sender: TObject);beginhook := SetWindowsHookEx(WH_KEYBOARD, Addr(KeyHook), HInstance, GetCurrentT hreadId);end;{释放键盘钩子}procedure TForm1.FormDestroy(Sender: TObject);beginUnhookWindowsHookEx(hook);end;end.钩子函数为什么非得使用stdcall 调用机制? 因为钩子函数不是被应用程序调用, 而是被系统调用的.end;varForm1: TForm1;implementation{$R *.dfm}{要先要定义和 DLL 中同样参数和返回值的的函数类型}typeTDLLFun = function: Boolean; stdcall;{现在需要的 DLL 中的函数的格式都是这样, 定义一个就够了}varh: HWND; {声明一个 DLL 句柄}SetHook, DelHook: TDLLFun; {声明两个 TDLLFun 变量}{载入 DLL 并调用其函数}procedure TForm1.Button1Click(Sender: TObject);beginh := LoadLibrary('MyHook.dll'); {载入 DLL 并获取句柄}if h<>0thenbeginSetHook := GetProcAddress(h, 'SetHook'); {让 SetHook 指向 DLL 中相应的函数} DelHook := GetProcAddress(h, 'DelHook'); {让 DelHook 指向 DLL 中相应的函数} endelseShowMessage('Err');SetHook; {执行钩子建立函数, 这里的 SetHook 和它指向的函数是同名的, 也可以不同名} end;{销毁钩子, 并释放 DLL}procedure TForm1.Button2Click(Sender: TObject);beginDelHook; {执行钩子释放函数}FreeLibrary(h); {释放 DLL 资源}end;end.varForm1: TForm1;implementation{$R *.dfm}varhook: HHOOK;function MyKeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; beginForm1.Memo1.Lines.Add(IntToStr(wParam)); {参数二是键值}Result := 0; {分别测试返回 0 或非 0 这两种情况}end;{派出钩子}procedure TForm1.Button1Click(Sender: TObject);beginhook := SetWindowsHookEx(WH_KEYBOARD, MyKeyHook, HInstance, GetCurrentThrea dId);Memo1.Clear;Text := '钩子启动';end;{收回钩子}procedure TForm1.Button2Click(Sender: TObject);beginUnhookWindowsHookEx(hook);Text := '钩子关闭';end;{如果忘了收回钩子...}procedure TForm1.FormDestroy(Sender: TObject);beginif hook<>0then UnhookWindowsHookEx(hook);end;end.小秘密: 发现没有, 这次在SetWindowsHookEx 时, 第二参数(函数地址), 没有使用@、也没有用Addr, 怎么也行呢? 因为函数名本身就是个地址.为钩子的下一步学习补课: 如何提取32 位中的某一位Integer 类型是32 位的, 有4 个字节, 现在我们需要能够提取出其32 位中的某一位.但Delphi 最小的整数类型也是一个字节(8位)的: Byte(无符号)、Shortint(有符号).要不先从提取一个字节开始:vari: Integer;b: Byte;begini := MaxInt; {Integer 的最大值}ShowMessage(IntToStr(i)); {2147483647}{现在 i 的二进制表示是: 01111111 11111111 11111111 11111111} {Interger 的最高位 0 表示这是个正数(1表示负数)}{假如:}i := 2146439167;{现在 i 的二进制表示是: 01111111 11110000 00001111 11111111} {现在其十六进制表示是: $7 F F 0 0 F F F }{落实一下, 从右到左四个字节分别是: $FF、$0F、$F0、$7F }{如果需要单独提取四个字节中的某个字节, Delphi 位我们提供了两个函数:}b := Lo(i); {提取低位字节}ShowMessage(Format('%.2x',[b])); {FF; 这是从右数第一个字节}b := Hi(i); {提取高位字节}ShowMessage(Format('%.2x',[b])); {0F; 这是从右数第二个字节}{那么我们怎么提取第三个和第四个字节呢? 方法一:}{右移 16 位, 然后再用 Lo 和 Hi 提取}{01111111 11110000 00001111 11111111 右移 16 位后会变成:}{ 01111111 11110000; 试一下:}b := Lo(i shr16);ShowMessage(Format('%.2x',[b])); {F0; 这是从右数第三个字节}b := Hi(i shr16);ShowMessage(Format('%.2x',[b])); {7F; 这是从右数第四个字节}{当然 i 的第四个字节也可以这样提取:}b := Lo(i shr24);ShowMessage(Format('%.2x',[b])); {7F; 这是从右数第四个字节}{现在换个思路, 假如没有 Lo 和 Hi 函数, 我们能做到吗? 当然能:}b := (i and$FF);ShowMessage(Format('%.2x',[b])); {FF; 这是从右数第一个字节}b := (i shr8and$FF);ShowMessage(Format('%.2x',[b])); {0F; 这是从右数第二个字节}b := (i shr16and$FF);ShowMessage(Format('%.2x',[b])); {F0; 这是从右数第三个字节}b := (i shr24and$FF);ShowMessage(Format('%.2x',[b])); {7F; 这是从右数第四个字节}{这是为什么? 换个语句块仔细分析}end;//关于上面例子的补充:varb: Byte;begin{我们知道 Byte 的最大值是 255, 也就是十六进制的 $FF, 二进制的 11111111}b := i shr0and1; ShowMessage(IntToStr(b)); {1}{提取第 1 位:}b := i shr1and1; ShowMessage(IntToStr(b)); {1}{提取第 13 位:}b := i shr13and1; ShowMessage(IntToStr(b)); {0}{提取最高位(第 31 位):}b := i shr31and1; ShowMessage(IntToStr(b)); {0} end;//假如只判断最高位, 是 0 还是 1(也就是判断正负), 还可以这样: vari: Integer;begini := MaxInt; {这肯定是个正数}if i shr31 = 0then ShowMessage('正'); {正}i := -1;if i shr31 = 1then ShowMessage('负'); {负}end;Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;typeTForm1 = class(TForm)Button1: TButton;Button2: TButton;Timer1: TTimer;procedure FormCreate(Sender: TObject);procedure Button1Click(Sender: TObject);procedure Button2Click(Sender: TObject);procedure Timer1Timer(Sender: TObject);procedure FormDestroy(Sender: TObject);end;function SetHook: Boolean; stdcall;function DelHook: Boolean; stdcall;function GetInfo: PChar; stdcall;varForm1: TForm1;implementation{$R *.dfm}function SetHook; external'MyHook.dll';function DelHook; external'MyHook.dll';function GetInfo; external'MyHook.dll';procedure TForm1.Button1Click(Sender: TObject);beginSetHook;Timer1.Enabled := True;end;procedure TForm1.Button2Click(Sender: TObject);beginFont.Height = -11 = 'Tahoma'Font.Style = []OldCreateOrder = False OnCreate = FormCreateOnDestroy = FormDestroy PixelsPerInch = 96TextHeight = 13object Button1: TButton Left = 48Top = 32Width = 75Height = 25Caption = 'Button1'TabOrder = 0OnClick = Button1Click endobject Button2: TButton Left = 144Top = 32Width = 75Height = 25Caption = 'Button2'TabOrder = 1OnClick = Button2Click endobject Timer1: TTimerOnTimer = Timer1Timer Left = 128Top = 8endend{获取外部窗口的句柄}function SetHWnd(hwnd: HWND): Boolean; stdcall;beginh := hwnd;Result := True;end;function MouseHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;begincase wParam ofWM_MOUSEMOVE : info := '鼠标位置';WM_LBUTTONDOWN : info := '按下';WM_LBUTTONUp : info := '放开';end;info := Format('%s: %d,%d', [info, PMouseHookStruct(lParam)^.pt.X, PMouseHo okStruct(lParam)^.pt.Y]);{通过消息把数据传递给指定窗口}PostMessage(h, WM_MyMessage, 0, Integer(PChar(info)));Result := CallNextHookEx(hook, nCode, wParam, lParam);end;function SetHook: Boolean; stdcall;constWH_MOUSE_LL =14;beginhook := SetWindowsHookEx(WH_MOUSE_LL, @MouseHook, HInstance, 0);Result := hook <> 0;end;function DelHook: Boolean; stdcall;beginResult := UnhookWindowsHookEx(hook);implementation{$R *.dfm}function SetHook; external'MyHook.dll';function DelHook; external'MyHook.dll';function SetHWnd; external'MyHook.dll';procedure TForm1.Button1Click(Sender: TObject); beginSetHook;SetHWnd(Handle);end;procedure TForm1.Button2Click(Sender: TObject); beginDelHook;end;procedure TForm1.FormCreate(Sender: TObject);beginButton1.Caption := '安装钩子';Button2.Caption := '载卸钩子';FormStyle := fsStayOnTop; {为了测试, 让窗口一直在前面} end;procedure TForm1.FormDestroy(Sender: TObject); beginDelHook;end;{把接受到的内容显示在窗体}procedure TForm1.MyMessage(var msg: TMessage); beginText := PChar(msg.LParam);end;OnClick = Button2Click endend。

python 钩子函数 通俗

python 钩子函数 通俗

python 钩子函数通俗
Python钩子函数,也称为钩子,是一种在特定时间或事件发生时,自动执行的函数。

钩子通常用于扩展或修改现有程序的行为。

在Python中,钩子可以用于拦截程序执行的某些事件,例如函数调用、变量赋值、异常处理等。

在Python中,钩子函数通常使用装饰器实现。

装饰器是一种包装函数的技术,它允许在不修改原始函数代码的情况下,为函数添加额外的功能。

钩子函数通常定义为装饰器函数,并与原始函数一起使用。

例如,以下是一个简单的钩子函数,它在函数调用时打印一条消息:
```
def my_hook(func):
def wrapper(*args, **kwargs):
print('Calling function', func.__name__)
return func(*args, **kwargs)
return wrapper
@my_hook
def my_function():
print('Hello world!')
my_function()
```
在这个例子中,`my_hook`是一个装饰器函数,它接受一个函数作为参数并返回一个包装器函数。

`wrapper`函数打印一条消息,然后调用原始函数`func`。

通过将`@my_hook`装饰器应用于
`my_function`函数,我们可以在函数调用时自动执行`my_hook`函数。

除了函数调用之外,钩子函数还可以用于捕获程序中的异常,拦截变量赋值等事件。

通过使用钩子函数,我们可以轻松扩展和修改现有程序的行为,从而实现更高效和灵活的编程。

消息钩子函数入门篇

消息钩子函数入门篇

消息钩子函数入门篇【摘要】消息钩子函数是一种常见的编程技术,用于在特定事件发生时触发自定义功能。

本文将介绍消息钩子函数的基本概念,包括其定义、作用和使用方法。

我们将通过实例演示消息钩子函数的具体应用,并解释与之相关的一些重要概念。

在结尾部分,我们将对本文内容进行总结,展望未来消息钩子函数的发展,以及提出一些建议。

希望通过本文的介绍,读者能够对消息钩子函数有一个更深入的理解,并在实际项目中灵活应用。

【关键词】消息钩子函数、入门、介绍、目的、背景、作用、使用、实例、相关概念、总结、展望、结束语1. 引言1.1 消息钩子函数入门篇- 介绍消息钩子函数是一种在软件开发中非常常见的概念,它可以让我们在特定的事件发生时执行自定义的逻辑。

在程序执行的过程中,系统会触发一些特定的事件,比如用户点击按钮、发送请求等,这时就可以通过消息钩子函数来捕获这些事件并进行相应的处理。

消息钩子函数的概念在不同的编程语言和框架中有着不同的实现方式,但其核心思想是相通的。

通过消息钩子函数,开发者可以在程序的不同阶段插入自定义的逻辑,这样可以更灵活地控制程序的行为。

在本篇文章中,我们将深入介绍消息钩子函数的概念和应用,帮助读者更好地理解和应用这一重要的技术。

从消息钩子函数的基本概念、作用和使用方法,到实际的应用案例和相关概念的解释,我们将全方位地探讨消息钩子函数的入门知识,希望能够帮助读者更好地利用这一功能提升自己的编程技能。

的内容将在接下来的文章中一一展开,让我们一起来深入学习吧!1.2 消息钩子函数入门篇- 目的消息钩子函数入门篇是一种非常有用的编程技术,它可以让开发人员在特定的事件发生时执行特定的功能。

在编程中,我们经常需要在某些事件发生时执行一些额外的操作,比如在用户点击按钮时验证表单数据,在用户登录时发送通知等。

而消息钩子函数就是为了实现这种需求而设计的。

这篇文章的目的是帮助读者了解什么是消息钩子函数,以及它们的作用和使用方法。

pytorch register钩子函数

pytorch register钩子函数

pytorch register钩子函数全文共四篇示例,供读者参考第一篇示例:PyTorch是一个主流深度学习框架,提供了许多便捷的功能和工具来简化深度学习模型的开发和训练过程。

钩子函数(hook)是一个非常强大的功能,可以帮助用户在模型的各个阶段插入自定义的逻辑,比如在每次前向传播或反向传播过程中获取中间数据或梯度信息。

本文将介绍PyTorch中register钩子函数的用法和实例。

## 什么是钩子函数钩子函数是一种在PyTorch中非常重要的概念,它允许用户在模型的某些关键节点插入自定义的逻辑,以便实现一些特定的功能或目的。

用户可以通过钩子函数获取模型中间层的输出,监控梯度的变化,实现梯度剪裁等。

PyTorch提供了两种类型的钩子函数,分别是register_forward_hook和register_backward_hook。

## register_forward_hookregister_forward_hook允许用户在每次前向传播过程中注册一个钩子函数,该钩子函数可以获取模型中间层的输出或其他信息。

register_forward_hook接受一个函数作为参数,这个函数的输入参数有三个:模块,输入和输出。

在这个函数中,用户可以通过输出参数获取模块的输出数据。

```import torchimport torch.nn as nndef hook_fn(module, input, output):print(module)print('input:', input)print('output:', output)model = nn.Linear(2, 1)hook = model.register_forward_hook(hook_fn)hook.remove()```在这个示例中,我们首先定义了一个模型nn.Linear(2, 1),然后注册了一个钩子函数hook_fn。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

消息钩子函数入门篇Windows系统是建立在事件驱动的机制上的,说穿了就是整个系统都是通过消息的传递来实现的。

而钩子是Windows系统中非常重要的系统接口,用它可以截获并处理送给其他应用程序的消息,来完成普通应用程序难以实现的功能。

钩子可以监视系统或进程中的各种事件消息,截获发往目标窗口的消息并进行处理。

这样,我们就可以在系统中安装自定义的钩子,监视系统中特定事件的发生,完成特定的功能,比如截获键盘、鼠标的输入,屏幕取词, 日志监视等等。

可见,利用钩子可以实现许多特殊而有用的功能。

因此,对于高级编程人员来说,掌握钩子的编程方法是很有必要的。

钩子的类型一.按事件分类,有如下的几种常用类型(1)键盘钩子和低级键盘钩子可以监视各种键盘消 /息、O(2)鼠标钩子和低级鼠标钩子可以监视各种鼠标消息。

(3)外壳钩子可以监视各种Shell事件消息。

比如启动和关闭应用程序。

(4)日志钩子可以记录从系统消息队列中取出的各种事件消息。

(5)窗口过程钩子监视所有从系统消息队列发往目标窗口的消息。

此外,还有一些特定事件的钩子提供给我们使用,不列举。

下面描述常用的Hook类型:1、WH_CA LLWNDPROC 和WH_CALLWND PROCRETHoo ksWH_CAL LWNDPROC 和W H_CALLWNDP ROCRETHook s 使你可以监视发送到窗口过程的消息。

系统在消息发送到接收窗口过程之前调用WH_C ALLWNDPROC Hook子程,并且在窗口过程处理完消息之后调用WH_CALL WNDPR0CR ETHook 子程。

W H_CALLWNDP ROCRETHook 传递指针到CWPRE TSTRUCT 结构,再传递到Hook 子程。

CWPRETSTR UCT 结构包含了来自处理消息的窗口过程的返回值,同样也包括了与这个消息关联的消息参数。

2、WH_CB THook在以下事件之前,系统都会调用WH_CBTHoo k子程,这些事件包括:1.激活,建立,销毁,最小化,最大化,移动,改变尺寸等窗口事件;2.完成系统指令;3.来自系统消息队列中的移动鼠标,键盘事件;4.设置输入焦点事件;5 •同步系统消息队列事件。

Hook子程的返回值确定系统是否允许或者防止这些操作中的一个。

3、WH_DEBUGHook在系统调用系统中与其他Hook关联的H ook子程之前, 系统会调用WH_DEBU GHook子程。

你可以使用这个Hook来决定是否允许系统调用与其他Hook关联的Hook子程。

4、WH_F0REGR OUNDIDLEHo ok当应用程序的前台线程处于空闲状态时,可以使用WH_F OREGROUNDI DLEHook执行低优先级的任务。

当应用程序的前台线程大概要变成空闲状态时,系统就会调用WH_F0R EGROUNDIDL EHook 子程。

5、WH_GETMESS AGEHook应用程序使用WH_GE TMESSAGEHo ok来监视从GetM essageorPe ekMessage函数返回的消息。

你可以使用WH_GETME SSAGEHook去监视鼠标和键盘输入,以及其他发送到消息队列中的消息。

6、WH_JOURNAL PLAYBACKHo okWH_J0U RNALPLAYBA CKHook使应用程序可以插入消息到系统消息队列。

可以使用这个Hook回放通过使用WH_J0URNA LRECORDHoo k记录下来的连续的鼠标和键盘事件。

只要WH_JOURNALP LAYBACKHoo k已经安装,正常的鼠标和键盘事件就是无效的。

WH_JOURN ALPLAYBACK Hook是全局Hoo k,它不能象线程特定Hook —样使用。

W H_JOURNALP LAYBACKHoo k返回超时值,这个值告诉系统在处理来自回放Hook当前消息之前需要等待多长时间(毫秒)。

这就使Hoo k可以控制实时事件的回放。

WH_J0UR NALPLAYBAC K是system-w idelocalho oks,它們不會被注射到任何行程位址空間。

(估计按键精灵是用这个hook做的)7、WH_J0UR NALRECORDH ookWH_J0 URNALRECOR DHook用来监视和记录输入事件。

典型的,可以使用这个Hook记录连续的鼠标和键盘事件,然后通过使用WH_JOURNAL PLAYBACKHo ok 来回放。

WH_J OURNALRECO RDHook是全局H ook,它不能象线程特定Hook 一样使用。

WH_J0URNA LREC0RD 是sy stem-widel ocalhooks,它們不會被注射到任何行程位址空間。

8、W H_KEYBOARD Hook在应用程序中,WH_KEYB OARDHook用来监视WM_KEYD0 WNandWM_KE YUP 消息,这些消息通过GetMessa georPeekMe ssagefunct ion返回。

可以使用这个Hook来监视输入到消息队列中的键盘消息。

9、WH_KE YB0ARD丄LH ookWH_KE YBOARD_LLH ook监视输入到线程消息队列中的键盘消息。

10、WH_MOU SEHookWH JlOUSEHook 监视从GetMess age 或者PeekM essage 函数返回的鼠标消息。

使用这个Hook监视输入到消息队列中的鼠标消息。

11、WH_M0US E_LLHookWH_M0USE_L LHook监视输入到线程消息队列中的鼠标消息。

12、WH _MSGFILTER 和WH_SYSMSG FILTERHook sWHJ1SGF ILTER 和WH_S YSMSGFILTE RHooks 使我们可以监视菜单,滚动条,消息框,对话框消息并且发现用户使用ALT TABorALTES C 组合键切换窗口。

W HJ1SGFILTE RHook 只能监视传递到菜单,滚动条,消息框的消息,以及传递到通过安装了Hook子程的应用程序建立的对话框的消息。

WH_ SYSMSGFILT ERHook监视所有应用程序消息。

WH_ MSGFILTER和WH_SYSMSGF ILTERHooks使我们可以在模式循环期间过滤消息,这等价于在主消息循环中过滤消息。

通过调用Cal IMsgFilter function可以直接的调用WH_MS GFILTERHoo k0通过使用这个函数,应用程序能够在模式循环期间使用相同的代码去过滤消息,如同在主消息循环里一样。

13、WH_SHELL Hook外壳应用程序可以使用WH_S HELLHook去接收重要的通知。

当外壳应用程序是激活的并且当顶层窗口建立或者销毁时,系统调用WH_SHELLHook子程。

WH_SHELL共有5钟情況:1 .只要有个top-1 evel> unown ed窗口被产生、起作用、或是被摧毁;2.当Taskbar需要重画某个按钮;3 .当系统需要显示关于Taskbar的一个程序的最小化形式;4 •当目前的键盘布局状态改变;5.当使用者按CtrlEsc去执行TaskMan ager (或相同级别的程序)。

按照惯例,外壳应用程序都不接收WH_SHELL消息。

所以,在应用程序能够接收WH_SH ELL消息之前,应用程序必须调用Syst emParamete rslnfofunc tion 注册它自己。

以上是13种常用的hook类型!二.按使用范围分类,主要有线程钩子和系统钩子(1)线程钩子监视指定线程的事件消息。

(2)系统钩子监视系统中的所有线程的事件消息。

因为系统钩子会影响系统中所有的应用程序,所以钩子函数必须放在独立的动态链接库(DLL)本篇论文是由为您在网络上收集整理的,论文版权属原作者,请不要用于商业用途或者抄袭,仅供参考学习之用,否则后果自负,如果此文侵犯您的合法权益,烦请联系我们。

中。

这是系统钩子和线程钩子很大的不同之处。

几点需要说明的地方:(1)如果对于同一事件(如鼠标消息)既安装了线程钩子又安装了系统钩子,那么系统会自动先调用线程钩子, 然后调用系统钩子。

(2)对同一事件消息可安装多个钩子处理过程,这些钩子处理过程形成了钩子链。

当前钩子处理结束后应把钩子信息传递给下一个钩子函数。

而且最近安装的钩子放在链的开始,而最早安装的钩子放在最后,也就是后加入的先获得控制权。

(3 )钩子特别是系统钩子会消耗消息处理时间,降低系统性能。

只有在必要的时候才安装钩子,在使用完毕后要及时卸载。

编写钩子程序编写钩子程序的步骤分为三步:定义钩子函数、安装钩子和卸载钩子。

1.定义钩子函数钩子函数是一种特殊的回调函数。

钩子监视的特定事件发生后,系统会调用钩子函数进行处理。

不同事件的钩子函数的形式是各不相同的。

下面以鼠标钩子函数举例说明钩子函数的原型:LRES ULTCALLBAC KHookProc(intnCode, W PARAMwPara m,LP ARAM IP aram)参数w Param和IPar am包含所钩消息的信息,比如鼠标位置、状态,键盘按键等。

nC ode包含有关消息本身的信息,比如是否从消息队列中移出。

我们先在钩子函数中实现自定义的功能,然后调用函数CallNextHookEx.把钩子信息传递给钩子链的下一个钩子函数。

C allNextHoo kEx.的原型如下:LRESULTC allNextHoo kEx(HHOOKh hk, intnCode, WPARAMwP aram, LPARA MIParam)参数hhk是钩子句柄。

nCode、wPa ram和1 Param是钩子函数。

当然也可以通过直接返回T RUE来丢弃该消息,就阻止了该消息的传递。

2.安装钩子在程序初始化的时候,调用函数SetWind owsHookEx安装钩子。

其函数原型为:HHOOKSe tWindowsHo okEx (intid Hook, HOOKP ROClpfn, IN STANCEhMod , DWORDdwTh readld)参数idHook表示钩子类型,它是和钩子函数类型一一对应的。

比如,WH KEYBO ARD表示安装的是键盘钩子,WH_MOU SE表不是鼠标钩子等等。

Lpfn是钩子函数的地址。

HMo d是钩子函数所在的实例的句柄。

对于线程钩子,该参数为NULL ;对于系统钩子,该参数为钩子函数所在的DLL句柄。

dwT hreadld指定钩子所监视的线程的线程号。

对于全局钩子,该参数为NULLoSetWindows HookEx返回所安装的钩子句柄。

3.卸载钩子当不再使用钩子时,必须及时卸载。

简单地调用函数BO OLUnhookWi ndowsHookE x (HHOOKhhk )艮卩可。

相关文档
最新文档