我可以将以下内容传递给旧版本的dll
type
PCallbackList = ^TCallbackList;
TCallbackList = record
arg: Pointer;
CallBack1: procedure(arg: Pointer; p1: Pointer; error: PAnsiChar); cdecl;
CallBack2: procedure(arg: Pointer; error: PAnsiChar); cdecl;
end;
当回调被触发时,我将arg传递给了我通过回调列表之前分配给它的对象实例。
现在,dll已更改,新的签名为:
type
PCallbackList = ^TCallbackList;
TCallbackList = record
CallBack1: procedure(p1: Pointer; error: PAnsiChar); cdecl;
CallBack2: procedure(error: PAnsiChar); cdecl;
end;
因此现在删除了arg指针,并且我无法将对象实例的引用传递给具有列表的dll,因此我无法知道回调属于哪个实例。
那么如何将对象方法作为回调方法传递呢?
如果DLL的新版本不提供对旧arg
参数的任何替代,那么您基本上只有2个选择:
为每个对象实例使用不同的回调函数集。例如,如果您有5个对象,则定义5组单独的回调函数,每个对象一组。将对象指针存储在回调可以到达的全局变量中。或者,为减轻全局变量的使用,如果DLL是线程安全的,则可以为每个对象创建一个单独的线程,将每个对象指针存储在threadvar
变量中,并根据需要在适当的线程中调用回调。
为每个回调使用一个thunk,目标对象的方法/指针存储在每个thunk自身中。重排是包含可执行指令和元数据的内存块。您可以VirtualAlloc()
使用Win32函数使用这些PAGE_EXECUTE(_READWRITE)
标志来分配这样的块,然后将对象指针和一些专门的x86 / x64指令放入其中,然后将其用作回调。当DLL通过函数调用该块时,将执行其指令,然后可以根据需要对存储的指针进行操作。
在幕后,C#的delegate
行为很像重击,只是背后有本机编译器支持。
对于Delphi,如果您想使用重排方法,则必须手动实施重排,或者找到第三方实现。这是一个非常高级的主题。我相信在StackOverflow上对此主题存在一些疑问。我还为《 C ++ Builder Journal》撰写了有关此主题的系列文章,探讨了VCL自己的MakeObjectInstance()
thunk的内部工作原理,该内部thunk由TWinControl
和使用AllocateHWnd()
。逻辑(不是代码)可以应用于您的情况。在我的网站的“文章”部分中,是该系列的前3篇文章1。
1:不幸的是,由于系统崩溃使我为之编写的所有代码全部消失,我没有完成最后的第四篇文章。并且该期刊不再出版。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句