Delphi thiscall调用约定

Delphi thiscall calling convention

本文关键字:约定 调用 thiscall Delphi      更新时间:2023-10-16

我需要调用非静态c++成员函数

因此我需要使用thiscall调用约定。

Delphi不支持这个调用约定。

因此,在调用任何成员函数之前,我必须手动将参数压入堆栈。

  asm
    mov ecx, myClassPointer
  end;

这个工作很好,但我正在寻找一个更好的方法来做到这一点。

在调用函数之前,我每次都用类指针调用asm代码,这不是很好。

由于我不是Delphi专家,我想知道您是否可以声明自己的调用约定或自动调用这些thiscall类方法。

您有以下选项:

    在asm中编写适配器以调用该函数。这是您当前的解决方案,正如您所知,这种方法既脆弱又笨拙。写一个c++适配器,提供一个互操作友好的界面。

在我看来,后一个选项是正确的解决方案。c++代码不适合互操作。通过互操作公开c++类是完全错误的。它对消费者提出了不合理的要求。合理的方法包括在Win32中发现的COM和纯C风格的互操作。

编写一个自适应的c++ DLL,消耗不合理的c++类,并提供适当的互操作友好界面。适配器是用c++编写的,因此能够使用c++代码。但随后它导出了一个对互操作友好的接口变体,可以从任何工具链中轻松调用。

Delphi的register调用约定为前三个参数使用寄存器。前两个是EAXEDX,它们在thiscall调用约定中不使用,可以设置为您喜欢的任何值。第三个寄存器是ECX

thiscall在堆栈上传递所有参数,register在堆栈上传递剩余参数。registerthiscall都有在堆栈上传递的被调用者cleanup参数。

所以你可以做的是声明一个register函数,为EAXEDX使用虚拟参数。您仍然可以将其包装在一个不同的函数中,以使其更容易调用,但至少现在可以将包装器函数声明为inline

请注意,在thiscallregister之间,参数在堆栈上被压入的顺序是不同的,所以你需要反转参数来匹配。

正如David已经说过的,您可以继续使用汇编器,但是还有更好的方法。我写了一篇名为"在Delphi中使用c++对象"的文章,用代码详细描述了如何使用这两种可行的替代方法:

  • 编写一个C层,导出C风格的函数,这些函数只使用c++类,并将每个方法作为简单函数公开。这是相当简单的,但是从Delphi端使用有点尴尬。写一个COM层,这并不像听起来那么容易。我需要一位c++大师的帮助才能把它做好。本文描述了这些步骤,您可以将它们一对一地应用到您的类中。

我个人更喜欢com层。从Delphi端使用它要容易得多。

本文还描述了在编写此类代码或使用此类对象时可能遇到的一些问题。通读