
分两个步骤创建全局鼠标挂钩:一、创建DLL,并在DLL中实现挂钩设置,释放和挂钩功能;二、建立另一个要调用和测试的项目。 -------------------------------------------------- -----------------------------第一步:首先创建一个DLL项目,并且自动初始代码如下(未注释): ------------------------------------------------- -----------------------------图书馆Project1;使用SysUtils,类; {$ R *。 res}开始结束。 -------------------------------------------------- ----------------------------- ///将项目另存为MyHook。 dpr,并实现如下:库MyHook;使用SysUtils,Windows,{挂钩函数全部来自Windows单元}消息,{消息WM_LBUTTONDOWN在消息单元中定义}类; {$ R *。
res} var钩子:HHOOK; {hook变量} {hook函数,太多的鼠标消息(例如鼠标移动),必须选择,这里是按下鼠标左键的选择} function MouseHook(nCode:Integer; wParam:WPARAM; lParam:LPARAM ):LRESULT; stdcall;如果wParam = WM_LBUTTONDOWN开始,然后开始MessageBeep(0); end;结果:= CallNextHookEx(hook,nCode,wParam,lParam); end; {建立钩子}函数SetHook:布尔值; stdcall; beginhook:= SetWindowsHookEx(WH_MOUSE,@ MouseHook,HInstance,0);结果:=挂钩0;结束; {释放挂钩}函数DelHook:布尔值; stdcall;开始结果:= UnhookWindowsHookEx(hook);结束; {DLL所需的输出函数}导出SetHook名称' SetHook',DelHook名称'DelHook',MouseHook名称'MouseHook'; // SetHook,DelHook,MouseHook; {如果不需要更改名称,则可以像这样直接导出}开始结尾。

--------------------------------------------------- --------------------------------注意:SetWindowsHookEx的第一个参数WH_MOUSE表示这是鼠标钩;第四个参数0表示它是全局的。鼠标挂钩回调函数的格式在此处,然后按Ctrl + F9进行编译。与项目名称相同的文件将在项目目录(这里为MyHook)中生成。 dll。 -------------------------------------------------- -----------------------------步骤2:调用新项目后,将其保存并放入刚刚创建的MyHook。将dll复制到该项目目录;然后添加两个按钮,实现如下:--------------------------------- ------ ---------------------------------------- unit Unit1;界面使用Windows,消息,SysUtils,变体,类,图形,控件,表单,对话框,StdCtrls;类型TForm1 = class(TForm)Button1:TButton; Button2:TButton;程序Button1Click(Sender:TObject);程序Button2Click(Sender:TObject);结束; {DLL中的函数声明} function SetHook:Boolean; stdcall;函数DelHook:布尔值; stdcall; var Form1:TForm1;实施{$ R *。
dfm} {该函数在DLL中的实现,这意味着它来自其最初的调用位置}函数SetHook;外部'MyHook。 dll'名称'SetHook';功能DelHook;外部'MyHook。 dll'名称'DelHook'; {建立挂钩}过程TForm1。 Button1Click(Sender:TObject);开始SetHook;结束; {destroy hook}过程TForm1。 Button2Click(Sender:TObject);开始DelHook;结束;结束。 -------------------------------------------------- ----------------------------- Test:单击第一个按钮后,挂钩被激活;无论鼠标在哪里,都单击鼠标左键以“单击”;单击第二个按钮以缩回挂钩。 -------------------------------------------------- -----------------------------以下是动态调用的方法,功能与上面完全相同:- ------ -------------------------------------------- ------ --------------------- Unit Unit1;界面使用Windows,消息,SysUtils,变体,类,图形,控件,表单,对话框,StdCtrls;类型TForm1 =类(TForm)Button1:TButton; Button2:TButton;程序Button1Click(Sender:TObject);程序Button2Click(Sender:TObject);结束; var Form1:TForm1;实施{$ R *。

dfm} {您必须首先使用与DLL中相同的参数并返回值来定义函数类型} type TDLLFun = function:Boolean; stdcall; {现在所需的DLL中函数的格式都是这样,只需定义一个} Var h:HWND; {声明DLL句柄} SetHook,DelHook:TDLLFun; {声明两个TDLLFun变量} {加载DLL并调用其函数}过程TForm1。 Button1Click(Sender:TObject);开始h:= LoadLibrary('MyHook.dll'); {加载DLL并获取句柄}如果h0则开始SetHook:= GetProcAddress(h,'SetHook'); {让SetHook指向DLL对应函数} DelHook:= GetProcAddress(h,'DelHook'); {让DelHook指向DLL中的相应函数}结束,否则ShowMessage('Err'); SetHook; {执行钩子建立函数,这里SetHook及其指向的函数名称相同,也可以具有不同的名称}结束; {销毁钩子并释放DLL}过程TForm1。
Button2Click(Sender:TObject);开始DelHook; {执行钩子释放功能} FreeLibrary(h); {释放DLL资源}结束;结束。 -------------------------------------------------- -----------------------------为什么全局挂钩必须在DLL中?因为每个EXE是一个独立且封闭的进程; DLL是系统的通用资源。如果一个钩子不是面向系统的,恐怕它没有多大意义。因此,在实践中,钩子与DLL是分不开的。问大家:全局挂钩可以用“包装”制成吗?我还没有尝试过。 -------------------------------------------------- ----------------------------- SetWindowsHookEx函数的第一个参数指示挂钩的类型。有14个选项,我们在两种类型之前使用过:WH_KEYBOARD,WH_MOUSE。系统将为每种类型的挂钩创建一个表(即14个表)。例如,如果应用程序启动了键盘挂钩,我们自己的程序也会启动键盘挂钩,并且相同的键盘挂钩将输入相同的表。

此表(可能不止一个,可能有鼠标钩等)是传说中的“钩链”。如果一个钩子链中有三个钩子(例如:钩子A,钩子B和钩子C依次),则最后一个“钩子C”将首先执行。是先进先出吗?我认为应该说:后进先出!有区别吗?是!因为第一位的不一定会出来。最后出现的钩子将首先执行。必须说是否可以执行之前进入的钩子(钩子A,钩子B),这必须由“钩子C”执行。如果CallNextHookEx语句包含在“ hook C”函数中,则“ hook A,hook B”可能可以生存;否则,您必须等待相应的UnhookWindowsHookEx将其拿走(我想到了赵本山的素描...)。这时,您可能会认为:太好了,以后我将不再添加CallNextHookEx,只需让我的钩子“运行”即可;但是,如果您的钩子先行怎么办?因此Windows建议:挂钩函数应调用CallNextHookEx,并将其返回值视为挂钩函数本身的返回值。 CallNextHookEx还将参数(例如,在键盘消息中按下了哪个键)传递到挂钩链中的下一个(或上一个)挂钩。
键盘挂钩和鼠标挂钩的参数是否相同?当然,它们是不相同的,因此它们不在同一“链”中。同一链中钩子的类型肯定是相同的。让我们谈谈钩子函数的返回值:在此之前,钩子函数的返回值遵循Windows约定,并返回CallNextHookEx的返回值。如果CallNextHookEx成功,它将返回下一个钩子的返回值,该钩子是一个链。如果CallNextHookEx失败,它将返回0,因此该钩子链将断开,只有当前的钩子仍在执行任务。不同类型的钩子函数的返回值是不同的。对于键盘挂钩,如果它返回非0的值,则表示消息在处理后将被销毁。换句话说:如果您赋予键盘挂钩功能Result:= 0;这意味着该消息被该钩子拦截并处理,然后“放入”;如果提供了键盘挂钩功能,则结果:= 1;这意味着该消息再次被该钩子拦截并处理。它被“杀死”。在下面的示例中,我们根本不使用CallNextHookEx(无论如何,这对我来说只是一个钩子),而直接提供返回值!这是下一个示例的演示:在中,我在三种状态下为Memo输入了字母a。如果未激活挂钩,则可以正常输入备忘录。当钩子函数返回0时,钩子被钩住后,钩子函数的功能(返回键值)首先被执行,字母a也可以成功输入;当钩子函数返回非零值时(例如1)),在钩子函数执行后,仅执行钩子函数(返回键值)的函数,可怜的备忘录不知道发生了什么。

但是这里有一个新问题:当钩子函数返回键值时会发生什么。 。 。不是一个?第一提醒:在使用Beep进行测试时,您是否发现声音多次?这是事实。因为按一次该键会发出两个消息:WM_KEYDOWN,WM_KEYUP,我们没有指定要拦截的消息,所以我们都截获了这两个消息。那么您如何区分这两个消息?秘密在键盘挂钩函数的第三个参数lParam中。让我们在下一个主题之后进行研究。 //示例代码:Unit Unit1;界面使用Windows,消息,SysUtils,变体,类,图形,控件,表单,对话框,StdCtrls;类型TForm1 = class(TForm)Button1:TButton; Button2:TButton;备注1:TMemo;过程FormDestroy(Sender:TObject);程序Button1Click(Sender:TObject);程序Button2Click(Sender:TObject);结束; {hook函数声明}函数MyKeyHook(nCode:整数; wParam:WPARAM; lParam:LPARAM):LRESULT; stdcall; var Form1:TForm1;实施{$ R *。
dfm} var hook:HHOOK;函数MyKeyHook(nCode:Integer; wParam:WPARAM; lParam:LPARAM):LRESULT;开始Form1。备忘1。线。添加(IntToStr(wParam)); {第二个参数是键值}结果:= 0; {分别在测试中返回0或非零}结束; {发送挂钩}过程TForm1。 Button1Click(Sender:TObject);开始挂钩:= SetWindowsHookEx(WH_KEYBOARD,MyKeyHook,HInstance,GetCurrentThreadId);备忘1。明确;文字:=“开始挂钩”;结束; {Retract hook}过程TForm1。 Button2Click(Sender:TObject);开始UnhookWindowsHookEx(hook);文字:=“挂钩已关闭”;结束; {如果您忘记收回挂钩,就可以了。
。 。 }过程TForm1。 FormDestroy(Sender:TObject);如果hook0开始,则开始UnhookWindowsHookEx(hook);结束;结束。小秘密:我没找到。这次在SetWindowsHookEx中,第二个参数(函数地址)没有使用@和Addr,那么它如何工作?因为函数名称本身是一个地址。原始地址:
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/bofangqi/article-324460-1.html
让我们知道你一直记得海浪的好
哇靠如果是我绝对淘到马云哭想买的东西太多了