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

How to pass an object method as a callback method to a c++ dll in Delphi

我可以将以下内容传递给旧版本的 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,其中目标对象 method/pointer 存储在每个 thunk 本身中。 thunk 是包含可执行指令和元数据的内存块。您可以使用 PAGE_EXECUTE(_READWRITE) 标志使用 Win32 VirtualAlloc() 函数分配这样一个块,然后将对象指针和一些专门的 x86/x64 指令放入其中,然后将其用作回调。当块被 DLL 像函数一样调用时,它的指令将被执行,然后可以根据需要对存储的指针进行操作。

在幕后,C# delegate 的行为很像 thunk,只是背后有本机编译器支持。

对于 Delphi,如果您想采用 thunk 方法,则必须手动实施 thunk,或寻找第 3 方实施。这是一个相当高级的话题。我相信在 Whosebug 上有一些关于这个主题的问题。我还为 C++Builder Journal 写了一系列关于这个主题的文章,探索 VCL 自己的 MakeObjectInstance() thunk 的内部工作原理,它被 TWinControlAllocateHWnd() 内部使用。逻辑(不是代码)可以应用于您的情况。在 my website 上,“文章”部分是该系列的前 3 篇文章 1

1: 不幸的是,我没有完成最后的第 4 篇文章,因为系统崩溃抹去了我为它编写的所有代码。该期刊不再出版。