说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

用DELPHI编制Windows95下的钩子函数

HTML文档下载 WORD文档下载 PDF文档下载
用DELPHI编制Windows95下的钩子函数

Windows消息管理机构提供了能使应用程序访问控制消息流μ

'c4所谓的钩子(HOOK)机制。钩子有多种,分别用于捕获某一特定类型或某一范围的消息。如:键盘消息,鼠标消息等。我们这里仅以键盘钩子的使用为例,讨论在DELPHI下怎样编写DLL程序和怎样在自己的程序中安装使用键盘钩子函数,并讨论了不同程序使用同一DLL文件时怎样共享数据。

一、 钩子过滤函数的编写说明

由于钩子过滤函数必须在独立的模块中,也就是说我们必须首先生成一个DLL框架,然后再在其中加入钩子函数代码以及其他相关函数代码。我们这里以键盘钩子过滤函数的编写为例来说明。具体步骤如下:

1、先生成一个DLL筐2架

2、编写自己的键盘钩子过滤函数

钩子过滤函数必须是回调函数,其函数的 4稳缦拢o

function KeyHookProc(

iCode:Integer;

wParam:WPARAM;

lParam:LPARAM ) : LRESULT; stdcall ;export ;

在生成的DLL框架中加入自己的键盘钩子处理函数处理键盘消息。

代码如下:…

if(iCode>=0) then begin

Result:=0; //初始化返回值

// 在这里加入自己的代码

end else

begin

Result:=CallNextHook(hOldKeyHook

iCode

wParam

lParam);

// hOldKeyHook是保存的原键盘过滤函数 5刂·

end;

3、 安装键盘钩子过滤函数

为安装一个钩子筥fd滤函数应调用SetWindowsHookEx函数(适用于Windows3.0的SetWindowsHook钩子安装函数现在已经废弃不用)。该函数的原形如下:

HHOOK SetWindowsHookEx(

int idHook

// 安装的筥b3子类型

HOOKPROC lpfn

// 钩子过滤籂f数地址

HINSTANCE hMod

// 任务句柄

DWORD dwThreadId // 钩子用于的目的

);

需要说明的是:蚠a8常应该调用MakeProcInstance函数以获取一个输出函数的前导码的入口地址,再将此地址作为SetWindowsHookEx的第二个参数lpfn。但由于Delphi提供了"灵巧调用(smart callback)",使得MakeProcInstance可以省去,而直接将钩子过滤函数名用作入口地址。

这样当应用程序觃c3GetMessage或PeekMessage函数从消息队列中读消息或有按键消息(WM_KEYDOWN或WM_KEYUP)要处理时,系统就要调用钩子过滤函数KeyHookProc处理键盘消息。

4、 卸载钩子过滤函数。

当钩子函数不再需要时,应调用UnHookWindowsHookProc卸载安装的钩子以释放系统资源。

完整的程序清单如下ba

Library KEYHOOK;

uses Windows;

const BUFFER_SIZE=16*1024;

const HOOK_MEM_FILENAME='SAMPLE KEY_HOOK_MEM_FILE';

const HOOK_MUTEX_NAME ='SAMPLE KEY_HOOK_MUTEX_NAME';

type

TShared=record

Keys : array[0..BUFFER_SIZE] of Char;

KeyCount : Integer;

end;

PShared=^TShared;

var

MemFile

HookMutex : THandle;

hOldKeyHook : HHook;

ProcSaveExit : Pointer;

Shared : PShared;

//键盘钩子过滤函数

function KeyHookProc(iCode: Integer; wParam: WPARAM ; lParam: LPARAM):LRESULT

; stdcall; export;

const KeyPressMask = $80000000;

begin

if iCode < 0 then

Result := CallNextHookEx(hOldKeyHook

iCode

wParam

lParam)

else begin

if ((lParam and KeyPressMask)= 0) then // 键按下

begin

Shared^.Keys[Shared^.KeyCount]:=Char(wParam and $00ff);

Inc(Shared^.KeyCount);

if Shared^.KeyCount>=BUFFER_SIZE-1 then Shared^.KeyCount:=0;

end;

iCode:=-1;

Result := CallNextHookEx(hOldKeyHook

iCode

wParam

lParam);

end;

end;

// 设置钩子过滤函数

function EnableKeyHook : BOOL ; export;

begin

Shared^.KeyCount:=0; //初始化键盘指针

if hOldKeyHook=0 then begin

hOldKeyHook := SetWindowsHookEx(WH_KEYBOARD

KeyHookProc

HInstance

0);

end;

Result := (hOldKeyHook <> 0);

end;

//撤消钩子过滤函数

function DisableKeyHook: BOOL ; export;

begin

if hOldKeyHook<> 0 then

begin

UnHookWindowsHookEx(hOldKeyHook); // 解除 Keyboard Hook

hOldKeyHook:= 0;

Shared^.KeyCount:=0;

end;

Result := (hOldKeyHook = 0);

end;

//取得键盘缓冲区中击键的个数

function GetKeyCount :Integer ; export;

begin

Result:=Shared^.KeyCount;

end;

//取得键盘缓冲区的键

function GetKey(index:Integer) : Char ; export;

begin

Result:=Shared^.Keys[index];

end;

//清空键盘缓冲区

procedure ClearKeyString ; export;

begin

Shared^.KeyCount:=0;

end;

//DLL的退出处理过程

procedure KeyHookExit; far;

begin

if hOldKeyHook <> 0 then DisableKeyHook;

UnMapViewOfFile(Shared); // 释放内存映象文件

CloseHandle(MemFile); // 关闭映象文件

ExitProc := ProcSaveExit;

end;

exports // 定义输出函数

EnableKeyHook

DisableKeyHook

GetKeyCount

ClearKeyString

GetKey;

begin

// DLL 初始化部分

HookMutex:=CreateMutex(nil

True

HOOK_MUTEX_NAME);

// 通过建立内存映象文件以共享内存

MemFile:=OpenFileMapping(FILE_MAP_WRITE

False

HOOK_MEM_FILENAME);

if MemFile=0 then

MemFile:=CreateFileMapping($FFFFFFFF

nil

PAGE_READWRITE

0

SizeOf(TShared)

HOOK_MEM_FILENAME);

Shared:=MapViewOfFile(MemFile

File_MAP_WRITE

0

0

0);

ReleaseMutex(HookMutex);

CloseHandle(HookMutex);

ProcSaveExit := ExitProc; // 保存DLL的ExitProc

ExitProc := @KeyHookExit; // 设置DLL新的ExitProc

end.

// 源代码结束

二、 在自己的程序中使用编制好的键盘钩子过滤函数。

钩子函数编制好后,使用起来其实很简单:首先调用SetWindowsHookEx安装自己的钩子过滤函数,同时保存原先的钩子过滤函数地址。这时钩子函数就开始起作用了,它将按照你的要求处理键盘消息。程序运行完毕或不再需要监视键盘消息时,调用UnHookWindowsHookProc函数卸载所安装的钩子函数,同时恢复原来的钩子过滤函数地址。

下面就是使用在以上编制的钩子函数的例子:

unit Unit1;

interface

uses

Windows

Messages

SysUtils

Classes

Graphics

Controls

Forms

Dialogs

StdCtrls

ExtCtrls;

type

TForm1 = class(TForm)

Memo1: TMemo;

Panel1: TPanel;

bSetHook: TButton;

bCancelHook: TButton;

bReadKeys: TButton;

bClearKeys: TButton;

Panel2: TPanel;

procedure bSetHookClick(Sender: TObject);

procedure bCancelHookClick(Sender: TObject);

procedure bReadKeysClick(Sender: TObject);

procedure bClearKeysClick(Sender: TObject);

end;

var Form1: TForm1;

implementation

{$R *.DFM}

function EnableKeyHook : BOOL ; external 'KEYHOOK.DLL';

function DisableKeyHook : BOOL ; external 'KEYHOOK.DLL';

function GetKeyCount : Integer ; external 'KEYHOOK.DLL';

function GetKey(idx:Integer) : Char ; external 'KEYHOOK.DLL';

procedure ClearKeyString ; external 'KEYHOOK.DLL';

procedure TForm1.bSetHookClick(Sender: TObject); // 设置键盘钩 7ó

begin

EnableKeyHook;

bSetHook.Enabled :=False;

bCancelHook.Enabled:=True;

bReadKeys.Enabled :=True;

bClearKeys.Enabled :=True;

Panel2.Caption:=' 键盘钩子已经设置';

end;

procedure TForm1.bCancelHookClick(Sender: TObject); // 卸载键盘钩子

begin

DisableKeyHook;

bSetHook.Enabled :=True;

bCancelHook.Enabled:=False;

bReadKeys.Enabled :=False;

bClearKeys.Enabled :=False;

Panel2.Caption:=' 键盘钩子没有设置';

end;

procedure TForm1.bReadKeysClick(Sender: TObject); // 取得击键的历史记录

var i:Integer;

begin

Memo1.Lines.Clear; // 在Memo1中显示击键历史记录

for i:=0 to GetKeyCount-1 do

Memo1.Text:=Memo1.Text+GetKey(i);

end;

procedure TForm1.bClearKeysClick(Sender: TObject); // 清除击键历史记录

begin

Memo1.Clear;

ClearKeyString;

end;

end.

// 源代码结束

三、 Windows95下DLL中实现共享内存

在上面的钩子函数所在的DLL文件中,需要使用共享内存,即,所有击键的记录存储在同一个数据段中。为什么要这样做呢?这是因为Windows95的DLL调用方法与Windows3.X的方法不同。每个进(线)程在登录某动态连接库时都会为该动态连接库传入一个新的实例句柄(即DLL数据段的句柄)。这使得DLL各个实例之间互不干扰,但是这对那些所有DLL实例共享一组变量带来一些困难。为了解决这个问题,我们在这儿通过建立内存映射文件的方法来解决。即使用Windows的OpenFileMapping、CreateFileMapping和

MapViewOfFile三个函数来实现。使用方法如下:

MemFile是THandle类型,Shared是指针类型,HOOK_MEM_FILENAME是一常量串

MemFile:=OpenFileMapping(FILE_MAP_WRITE

False

HOOK_MEM_FILENAME); //打开内存映射文件

if MemFile=0 then //打开失败则衉c2建内存映射文件

MemFile:=CreateFileMapping($FFFFFFFF

nil

PAGE_READWRITE

0

SizeOf(TShared)

HOOK_MEM_FILENAME);

//映射文件到变量

Shared:=MapViewOfFile(MemFile

File_MAP_WRITE

0

0

0);

到此为止,你已经知道用Delphi编制钩子函数有多么容易。最后不得不提醒大家:钩子函数虽然功能比较强,但如果使用不当将会严重影响系统的效率,所以要尽量避免使用系统钩子。非要使用不可时也应该格外小心,应使之尽可能小地影响系统的运行。

用VB尝试新的界面风格 用VB建立字符界面的控制台程序 用VB快速读取TextBox第N行的数据 用VB 设计VCD播放器 用VB设计更好的用户界面 用VB设计聚焦框程序 用VB实现“ICQ”式的启动欢迎画面 用VB实现全屏幕图形界面及动态功能提示 用VB实现任务栏右下角的小图标 用VB制作常居上层的浮动工具箱 用VB制作即时动态按钮 用VB作浮动式图标提示按钮 用Visual Basic编写托盘程序 用Visual Basic窗体背景花纹的实现 用Visual Basic设计窗体背景花纹 用Visual Basic设计更好的用户界面 用Visual Basic设计三维图形按钮 用VisualBasic制作半透明窗体 运行时改变控件大小的两种方法-VB资料 运行中隐藏/显示窗口标题栏-VB资料 在ListBox适当设定水平滚动条的宽度-VB资料 在VB中利用API实现窗体的平滑显示 在vb中让控件大小和位置随着表单的大小成比例变化的方法 在VB中实现闪动标题栏 在VB中实现位图的透明放置 在VB中使用数据窗体设计器插件 在VB中制作单独程序封面的两种方法 在VB中制作透明按钮 在Visual Basic中如何拖动窗体或控件 在Visual Basic中显示动态运行进度 在菜单中加入图标 -VB资料 喜欢CS的朋友请进来 各位高手:IIS 不解析asp页面是什么原因? 我想用delphi在前端输入7位小数点,怎幺做? sql7数据库使用中的奇怪错误!!! 谁能告诉我这是怎么回事啊?急!在线等,分不够在加,马上解决马上结恬! 怎样把日期转化为星期 一个关于建立文件管理窗口的问题 我想在3dmax中的立方体顶面贴图,其他面不动,如何实现? 如何在DataGrid中加入CheckBox,并确定是否被选中?急!!! 关于用户自定义page类的问题 存储过程中IF EXISTS(select @result=aaa from tbl)提示等号附近有语法错误!!! 请问除了设置Anchor属性外如何保证窗体放大后组件的位置和大小? 如何在BCB中动态创建对象? SOS 救火 帮忙看个错,数据库连接问题 看看这个xml怎么用xsl解析 在DELPHI中,怎么遍历相同的控件? 一个简单的问题---在线等 在线等待:如何捕捉listctrl垂直滚动条的点击事件? 控件分类管理 急求一个递归统计函数,能解决者马上给分!!! 如何在ie中只打印iframe里面的页面内容 求select语句 请jennifergiant来领分,谢谢 如何将在内存中创建的BMP文件加载到页面上??? 帮忙看个错,ORA-00600 那里可以下载测试工具(Loadrunner,testdirector) 如何写一个往数据库里插入记录的公共模块啊? 文本两边对齐 请问sqlserver2000中bit类型值怎样表示 谁有jspsmart 上传组件。我上不了jspsmart.com ,好心人给我发一个!!! 时间格式有误,不知是何原因? 怎样开、关进程!(不是线程)? 今年高考的一篇旷世奇文 cnn连接怎么单独写出来,让Sub或Function调用?不用每次都写一次连接, 请附上Code ,谢谢 请教multibytetowidechar的用法 请救各位. 关于用nmudp实现传输!up也有分,:)) jcreator的debug模式不是很好用,怎么(黄色小三角)指的位置不对啊? 关于用mscomm编程的问题,请大虾指教 导出数据库和操作时经常出现无法分配共享内存错误. 关于ListBox 重分请教:关于制作自定义报表的问题!!! 请问怎样编程查询一个字符串的五笔字型编码? 我们单位要上ERP,作为公司分管微机这一块的我该准备些什么? 右键菜单问题 d7+ADO+SQL2000,如何判断SQL2000数据库中存在某个表? 想要去清华读研究生,大家帮忙出出意见!!!!!!!!!!!!!!!!!!!!!!!! 大价钱求解小问题 好硕的5460!!!! iwantsay 关于MSComm的output和Chr()函数的问题 36~ 他说 他会在桌子上留一个 条子的(英语翻译) 给短文加标题.杰米·格兰特是一位伟大艺人.他曾被邀请参加一场慰问第二次世界大战退伍军人的表演,但他告诉邀请单位自己行程很紧,只能作一段独白.可后来,他居然表演了30分钟,安排表演 由0.1.2.3.4.5.6可以组成多少个无重复数字且能被6整除的五位数 已知a=根号9,b=2011°,c=-(-2),求a-b+c的值. 明清时谁反对重农抑商 日本遭受了如此强震,有人说这次地震对于日本来说不一定是一件坏事,日本可能会在这次地震后迅速觉醒,难道日本会在这次地震中觉醒吗? 日本地震醒悟不恨日本祈祷平安还有我喜欢看日本动漫 求(a+1)(b+1)+(a+2)(b+2)+……+(a+2014)(b+2014) 的值.其求(a+1)(b+1)+(a+2)(b+2)+……+(a+2014)(b+2014) 的值.其中a=1.b=1 请问smexy什么意思? 已知a-b=1/2,a+b=2014,则a^2-b^2的值为(求过程) 新疆日报:始终筑牢反分裂思想防线新加坡:见习飞行员遇车祸 获赔留学费美建议叙问题会议11月举行 不确信反印度民众燃放爆竹庆祝排灯节 引发环境孙杨可自选拘留时间 新女友浮出水面亦德国拒绝为斯诺登提供庇护 避免影响德刚果(金)政府宣布该国打击反政府武装俄注重文化保护 文化事业拨款70%用穆尔西审判延后 分析指与穆沙拉夫审判科索沃举行地方政府选举 投票点遭蒙面印尼巴厘岛男子咖啡地中发现2000多惊心动魄 美“风暴追逐者”捕捉的电闪点赞!安化县3000余幅“军功年画”陈敏尔:省委常委班子要带好头、作表率2017 01 11 05:54 来30年代何偶然事件导致中共中央决定从政法机关重拳出击守护人民安全台媒:美国防部要求拨款5000亿美元美媒:奥巴马将发表告别演说 特朗普次“立法禁止过马路玩手机”需慎重考量民警学习“微笑服务”,彰显理念的进步贷分实验:学生自律与他律相结合的教育
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘