一种使类成员函数成为 Windows 回调函数的方法

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

问题:一种使类成员函数成为Windows 回调函数的方法( 积分:100, 回复:62, 阅读:3393 )

分类:Object Pascal ( 版主:menxin, cAkk )

来自:savetime, 时间:2004-6-20 2:41:00, ID:2672562 [显示:小字体| 大字体] 一种使类成员函数成为Windows 回调函数的方法

savetime2k@ 2004.6.20

本文排版格式为:

正文由窗口自动换行;所有代码以80 字符为边界;中英文字符以空格符分隔。

未经作者同意请勿在在任何公共媒体转载

大富翁satanmonkey 提出一个问题:HOOK 的时候,那个回调函数怎么弄才能做成类的成员?现在回调函数不能是类成员函数,访问不了类的成员变量。

/delphibbs/dispq.asp?lid=2624773

后来又在另一篇贴子上也看到类似的问题,看来解决这个问题还有点用(我现在还不知道这有什么用处),所以趁着今天周末思考一下。

(太想睡了,下面只好草率地说明,如有不清楚请提问,或者日后有空再详作解释)

一开始我的想法是在类成员的回调函数内部复制参数的值,差不多理顺了,后来发现如果回调函数有返回值时,这种方法不行...

只好重新开工,用手工编制机器码的方法完成,其中查询JMP $00001111 这样的立即数跳转机器指令花了一个小时,结果是没有找到,只好以JMP [$00001111] 这个代码代替。如果有谁知道前一种跳转指令的机

器码,请告诉我。

思路是这样的:Windows 回调时跳转到一段自己生成的代码中,这段代码模拟Delphi的成员函数调用。大概的情况是:在类成员变量中声明一块内存空间TCallbackObject,这块内存中放入一些跳转指令:1.修改ESP;2.放入对象指针;3.跳转到类的成员函数。

type

TCallbackFunc = function(A, B: Integer): Integer; stdcall; // 某回调函数原型

// 对象相关的,临时生成的机器码结构

TCallbackObject = packed record

Code1: array[1..5] of Byte;

SelfPtr: Pointer; // 对象指针

Code2: array[1..6] of Byte;

FuncPtr: Pointer; // 类成员函数地址

end;

// 上面TCallbackObject 的结构就是这些汇编代码

MOV EAX, [ESP];

PUSH EAX;

MOV EAX, SelfPtr;

MOV [ESP+4], EAX;

JMP AbsoluteCallbackAddr;

// 一个示范类,其ClassCallback 为相应的Windows 回调函数格式

TMyClass = class(TObject)

FCallbackObject: TCallbackObject;

BaseInt: Integer;

constructor Create;

procedure MakeCallbackObject;

end;

// 在自己类的构造函数中生成回调函数–引导机器码constructor TMyClass.Create;

begin

MakeCallbackObject; // 生成回调函数代码

BaseInt := 100; // 示范数据

end;

// 生成一段回调函数- 引导机器码

procedure TMyClass.MakeCallbackObject;

const

CallbackCode: array[1..SizeOf(TCallbackObject)] of Byte =

($8B,$04,$24,$50,$B8,$00,$00,$00,$00,$89,$44,$24,$04,

$FF,$25,$00,$00,$00,$00);

AbsoluteCallbackAddr: Pointer = @TMyClass.ClassCallback; begin

Move(CallbackCode, FCallbackObject, SizeOf(TCallbackObject)); with FCallbackObject do

begin

SelfPtr := Self;

FuncPtr := @AbsoluteCallbackAddr;

end;

end;

// 示范:在类成员回调函数中使用类成员变量

// 注:没测试调用成员函数,应该没什么问题吧

begin

Result := A + B + BaseInt;

end;

// 示范:如何使类的回调函数被赋值给Windows 回调函数

procedure TForm1.Button1Click(Sender: TObject);

var

MyClass: TMyClass;

CallbackFunc: TCallbackFunc;

begin

MyClass := TMyClass.Create;

CallbackFunc := @MyClass.FCallbackObject;

ShowMessage(IntToStr(CallbackFunc(1, 2))); // 模拟Windows 回调

ShowMessage(IntToStr(MyClass.ClassCallback(1, 2))); // 对象调用

MyClass.Free;

end;

由于主要的目的是解决Windows 回调函数的兼容问题,所以使用stdcall 调用约定定义类成员函数,如果要在其它情况下使用(我估计不会有其它的情况吧),要修改一些代码。

如何使用上面的代码:

* 按Windows 回调函数格式定义类成员函数

* 在类中定义一个FCallbackObject 成员变量

* 把MakeCallbackObject 函数复制到你的类定义中

* 在类的构造函数中运行MakeCallbackObject

* 修改AbsoluteCallbackAddr: Pointer = @TMyClass.ClassCallback;

相关文档
最新文档