如何在Delphi中将对象方法作为回调方法传递给C ++ dll

纳斯达丁·加尔弗特

我可以将以下内容传递给旧版本的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个选择:

  1. 为每个对象实例使用不同的回调函数集。例如,如果您有5个对象,则定义5组单独的回调函数,每个对象一组。将对象指针存储在回调可以到达的全局变量中。或者,为减轻全局变量的使用,如果DLL是线程安全的,则可以为每个对象创建一个单独的线程,将每个对象指针存储在threadvar变量中,并根据需要在适当的线程中调用回调。

  2. 为每个回调使用一个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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章