可以使用@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