文档章节

使用钩子函数[4] - 钩子链和 CallNextHookEx 的返回值

涂孟超
 涂孟超
发布于 2014/09/26 15:30
字数 1208
阅读 8
收藏 1
SetWindowsHookEx 函数的第一个参数表示钩子类型, 共有 14 种选择, 前面我们已经用过两种:
WH_KEYBOARD、WH_MOUSE.

系统会为每一种类型的钩子建立一个表(那就是 14 个表), 譬如某个应用程序启动了键盘钩子, 我们自己的程序也启动了键盘钩子, 同样是键盘钩子就会进入同一个表. 这个表(可能不止一个, 可能还会有鼠标钩子等等)就是传说中的"钩子链".

假如某个钩子链中共进来了三个钩子(譬如是: 钩子A、钩子B、钩子C 依次进来), 最后进来的 "钩子C" 会先执行.
是不是先进后出? 我觉得应该说成: 后进先出! 这有区别吗? 有! 因为先进来的不一定出得来.
最后进了的钩子会最先得到执行, 先前进来的钩子(钩子A、钩子B)能不能得到执行那还得两说, 这得有正在执行的 "钩子C" 说了算.
如果 "钩子C" 的函数中包含了 CallNextHookEx 语句, 那么 "钩子A、钩子B" 就有可能得以天日; 不然就只有等着相应的
UnhookWindowsHookEx 来把它们带走(我想起赵本山的小品...).

这时你也许会想到: 这样太好了, 我以后就不加 CallNextHookEx , 只让自己的钩子"横行"; 但如果是你的钩子先进去的呢?
所以 Windows 建议: 钩子函数要调用 CallNextHookEx, 并把它的返回值当作钩子函数自己的返回值.

CallNextHookEx 同时要给钩子链中的下一个(或许应该叫上一个)钩子传递参数(譬如在键盘消息中按了哪个键). 一个键盘钩子和鼠标钩子的参数一样吗? 当然不一样, 所以它们也不在一个 "链" 中啊; 同一个链中的钩子的类型肯定是一样的.

再聊聊钩子函数的返回值:
在这之前, 钩子函数的返回值, 我们都是遵循 Windows 的惯例, 返回了 CallNextHookEx 的返回值.
如果 CallNextHookEx 成功, 它会返回下一个钩子的返回值, 是个连环套;
如果 CallNextHookEx 失败, 会返回 0, 这样钩子链也就断了, 只有当前钩子还在执行任务.

不同类型的钩子函数的返回值是不同的, 对键盘钩子来讲如果返回一个非 0 的值, 表示它处理完以后就把消息给消灭了.
换句话说:
如果给键盘的钩子函数 Result := 0; 说明消息被钩子拦截并处理后就给 "放" 了;
如果给键盘的钩子函数 Result := 1; 说明消息被钩子拦截并处理后又给 "杀" 了.

在下面的例子中, 我们干脆不使用 CallNextHookEx (反正暂时就我一个钩子), 直接给返回值!

这是接下来例子的演示动画:


动画中, 我在三种状态下分别给 Memo 输入了字母 a
当没启动钩子时, Memo 是可以正常输入的;
当钩子函数返回 0, 钩上以后, 先执行了钩子函数的功能(返回键值), 字母 a 也能输入成功;
当钩子函数返回非 0 值(譬如1), 钩上以后, 就只执行了钩子函数的功能(返回键值), 可怜的 Memo 不知道发生了什么.

但这里又有了新问题: 钩子函数返回键值时怎么...不是一个?
先提醒: 在前面用 Beep 测试时, 你有没有发现那个声音也不只一次, 这是一个道理.
因为按一次键就会发出两个消息: WM_KEYDOWN、WM_KEYUP, 我们没有指定拦截哪个, 就都拦截了.
那怎么区分这两个消息呢? 秘密在键盘钩子函数的第三个参数 lParam 里面, 等下一个话题再研究吧.
//示例代码:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  end;

  {钩子函数声明}
  function MyKeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

var
  Form1: TForm1;

implementation

{$R *.dfm}

var
  hook: HHOOK;

function MyKeyHook(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
  Form1.Memo1.Lines.Add(IntToStr(wParam)); {参数二是键值}
  Result := 0; {分别测试返回 0 或非 0 这两种情况}
end;

{派出钩子}
procedure TForm1.Button1Click(Sender: TObject);
begin
  hook := SetWindowsHookEx(WH_KEYBOARD, MyKeyHook, HInstance, GetCurrentThreadId);
  Memo1.Clear;
  Text := '钩子启动';
end;

{收回钩子}
procedure TForm1.Button2Click(Sender: TObject);
begin
  UnhookWindowsHookEx(hook);
  Text := '钩子关闭';
end;

{如果忘了收回钩子...}
procedure TForm1.FormDestroy(Sender: TObject);
begin
  if hook<>0 then UnhookWindowsHookEx(hook);
end;

end.

 
 
 
 
 

 

 

  
小秘密: 发现没有, 这次在 SetWindowsHookEx 时, 第二参数(函数地址), 没有使用 @、也没有用 Addr, 怎么也行呢?
因为函数名本身就是个地址.

本文转载自:http://www.cnblogs.com/del/archive/2008/02/27/1083011.html

涂孟超
粉丝 12
博文 2011
码字总数 14107
作品 0
深圳
程序员
私信 提问
Windows Hook

啥是windows的钩子?钩子故名思议就是在嵌入到正常执行程序的功能。对于windows来说,每个系统和应用程序之间的交互是使用消息机制来进行。比如点击应用程序上面的某个按钮,就是发送了事件给...

王二狗子11
2018/01/07
0
0
Windows Hook机制(转贴一)

最近想写个监视系统的小软件,需要Windows Hook的知识,所以会陆续贴几个关于Hook的文章做参考。 本文将试图以下面的顺序讲解HOOK的大部分内容: 1、 WINDOWS的消息机制 2、 HOOK介绍 3、 HO...

像教授
2017/11/26
0
0
《windows核心编程系列》谈谈windows钩子

windows应用程序是基于消息驱动的。各种应用程序对各种消息作出响应从而实现各种功能。 windows钩子是windows消息处理机制的一个监视点,通过安装钩子可以达到监视指定窗口某种类型的消息的功...

长平狐
2012/10/08
166
0
SetWindowsHookEx的用法

HOOK钩子详细介绍 基本概念 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监 视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,...

付品军
2010/01/19
1K
0
Delphi - 关于钩子函数HOOK

Delphi - 关于钩子函数HOOK (1) 基本概念 钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息, 而且所监视的窗口可以是其他进程所创建的。当...

jimbuster
2005/12/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

前端面试题汇总

一. HTML常见的兼容性 1.HTML5 标签在低版本浏览器不兼容 解决办法:使用html5shiv库,引入下列语句 <!--[if lte IE 8]> <script src="https://cdn.bootcss.com/html5shiv/r29/html5.js"></sc......

蓝小驴
28分钟前
7
0
OSChina 周四乱弹 —— 我气的脸都黑了!

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 小小编辑推荐《Red Battle》- 高橋李依 / 豊崎愛生 《Red Battle》- 高橋李依 / 豊崎愛生 手机党少年们想听歌,请使劲儿戳(这里) @丶Lion ...

小小编辑
41分钟前
554
22
找OSG教程, B站就有

https://www.bilibili.com/video/av64849038?from=search&seid=11632913960900279653

洛克人杰洛
今天
5
0
学习记录(day07-Vue组件、自定义属性、自定义事件)

[TOC] 1.1.1什么是组件 一个vue文件就是一个组件 组件将html标签/css样式/对应JS打包成一个整体,也可以理解钻进一个具有样式和特效的自定义标签。 一、编写组件(提供方)<template> <di...

庭前云落
今天
5
0
使用Prometheus监控SpringBoot应用

通过之前的文章我们使用Prometheus监控了应用服务器node_exporter,数据库mysqld_exporter,今天我们来监控一下你的应用。(本文以SpringBoot 2.1.9.RELEASE 作为监控目标) 编码 添加依赖 使...

JAVA日知录
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部