首页  编辑  

如何取得类方法的指针

Tags: /超级猛料/Language.Object Pascal/面向对象和类、VCL核心/   Date Created:

可以使用@AClassInstance.MethodName来取得地址,不过有一个缺点,就是在调用作为Callback的时候,不能使用类的变量。

// Converting method pointers into function pointers

// Often you need a function pointer for a callback function. But what, if you want to specify a method as

// an callback? Converting a method pointer to a function pointer is not a trivial task; both types are

// incomatible with each other. Although you have the possibility to convert like this "@TClass.SomeMethod",

// this is more a hack than a solution, because it restricts the use of this method to some kind of a class

// function, where you cannot access instance variables. If you fail to do so, you'll get a wonderful gpf.

// But there is a better solution: run time code generation! Just allocate an executeable memory block, and

// write 4 machine code instructions into it: 2 instructions loads the two pointers of the method pointer

// (code & data) into the registers, one calls the method via the code pointer, and the last is just a return

// Now you can use this pointer to the allocated memory as a plain funtion pointer, but in fact you are

// calling a method for a specific instance of a Class.

type TMyMethod = procedure of object;

function MakeProcInstance(MyMethod: TMyMethod): Pointer;

begin

 // allocate executeable memory

 Result := VirtualAlloc(nil, 13, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

 asm

   // write "move eax, <data pointer constant>"

   mov byte ptr [eax], $B8

   mov ecx, TMethod(M).Data

   mov dword ptr [eax+1], ecx

   // write "move ecx, <code pointer constant>"

   mov byte ptr [eax+5], $B9

   mov ecx, TMethod(M).Code

   mov dword ptr [eax+6], ecx

   // write "call ecx"

   mov byte ptr [eax+10], $FF

   mov byte ptr [eax+11], $D1

   // write "ret"

   mov byte ptr [eax+12], $C3

 end;

end;

// After all, you should not forget to release the allocated memory.

// "TMyMethod" can be modified according your specific needs, e.g. add some parameters for a WindowProc.

// N.B.: Yes, I know, Delphi has those "MakeProcInstance" function in its forms unit.

// But this works a little bit different, has much more overhead,

// and most important, you have to use the forms unit, which increases the size of your exe drastically,

// if all other code doesn't use the VCL (e.g. in a fullscreen DirectX/OpenGl app).

// if you have questions: Florian.Benz@t-online.de