从Delphi 7中的c ++ DLL接收字符串数组

时间:2014-03-06 16:23:00

标签: c++ arrays delphi dll

我正在用C ++创建一个DLL,它将在Delphi 7项目中使用。

这个问题与this one有关,我只提出两个函数ValidateGetToken,现在它们将在C ++中完成,字符串数组GetToken生成将被送回德尔福。

问题是我不知道如何在dll中创建将在c ++中返回字符串数组的函数,我不知道它将如何存储以便在Delphi中进一步使用。

该功能的声明如下:

function GetToken(Chain:string):Arrayofstring;

1 个答案:

答案 0 :(得分:2)

根据您的代码审查,Delphi代码希望该函数具有以下签名:

function GetToken(Chain: AnsiString): array of AnsiString;

你不能用C ++编写这样的函数。 C ++不知道Delphi字符串是什么,也不知道Delphi动态数组是什么。这两种类型都需要从Delphi的内存管理器中分配,而C ++ DLL无法访问它。此外,C ++不知道如何使用Delphi的register调用约定。

DLL接口的设计很差。 DLL不应该使用特定于语言的类型,除非设计者的意图排除所有其他语言。 (在这种情况下,甚至更高版本的相同语言被排除在外,因为AnsiString的定义在Delphi 2009中发生了变化,包含了Delphi 7无法正确处理的更多元数据。)最安全的调用约定通常是stdcall。这就是Windows API中的所有内容。

更好的界面将使用所有语言共有的类型,并且它将规定使用可普遍访问的内存管理。有几种常见的方法可以做到这一点。例如:

  • 字符串作为简单的以空字符结尾的字符数组返回 - 在Delphi中为PAnsiChar; C ++中的char*。 DLL为字符串分配缓冲区,并为这些字符串的数组分配缓冲区。当主机应用程序使用数组和字符串完成时,它调用DLL导出的另一个函数,其中DLL释放它分配的内存。这是例如FormatMessage使用的模型;当主机程序使用消息字符串完成时,它会调用LocalFree

    type
      PStringArray = ^TStringArray;
      TStringArray = array[0..Pred(MaxInt) div SizeOf(PAnsiChar)] of PAnsiChar;
    function GetToken(Char: PAnsiChar): PStringArray; stdcall;
    procedure FreeStringArray(StringArray: PStringArray); stdcall;
    
    char** __stdcall GetToken(char const* Chain);
    void __stdcall FreeStringArray(char** StringArray);
    
  • 使用COM返回BStr对象的safearray。它类似于以前的技术,但内存管理是由COM而不是你的DLL定义的,所以接口的任何一方都需要定义的东西较少。

  • 将回调函数传递给DLL,因此DLL不会返回一个字符串数组,而只是为它识别的每个字符串调用一次函数。然后你不必定义任何数组的外观,并且每个字符串的生命周期可以只是回调调用的生命周期 - 如果主机应用程序想要一个副本,它就可以这样做。新的函数签名看起来像这样:

    type
      TTokenCallback = procedure(Token: PAnsiChar); stdcall;
    procedure GetToken(Chain: PAnsiChar; ProcessToken: TTokenCallback); stdcall;
    
    typedef void (__stdcall* TokenCallback)(char const* Token);
    void __stdcall GetToken(char const* Chain, TokenCallback ProcessToken);
    

如果您不是设计DLL接口的人,那么您需要依靠那些做过的人并将其更改为非Delphi代码更易于访问。如果你不能这样做,那么最后的替代方法是在Delphi中编写一个DLL,它包装你的DLL,将参数按照每个方面都能理解的东西。