从Delphi 7中的c ++ DLL接收一个字符串数组 [英] Receive an array of string from a c++ DLL in Delphi 7

查看:322
本文介绍了从Delphi 7中的c ++ DLL接收一个字符串数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



这个问题与这一个,其中我介绍两个功能验证 GetToken 只有现在他们将在C ++和字符串数组 GetToken 生成将被发送回Delphi。



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



函数的声明如下:



function GetToken(Chain:string):Arrayofstring;

解决方案

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

 函数GetToken(Chain:AnsiString):数组的AnsiString; 

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



DLL界面设计不佳。 DLL不应该使用特定于语言的类型,除非是设计者的意图来排除所有其他语言。 (在这种情况下,即使以后版本的同一种语言也被排除在外,因为在Delphi 2009中更改了 AnsiString 的定义,以包含更多的元数据,Delphi 7将无法正确处理。 )最安全的通话方式一般为 stdcall 。这是Windows API中的所有内容。



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




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

     键入
    PStringArray = ^ TStringArray;
    TStringArray =数组[0..Pred(MaxInt)div SizeOf(PAnsiChar)]的PAnsiChar;
    函数GetToken(Char:PAnsiChar):PStringArray;标准
    程序FreeStringArray(StringArray:PStringArray);标准



      char ** __stdcall GetToken (char const * Chain); 
    void __stdcall FreeStringArray(char ** StringArray);


  • 使用COM返回BStr对象的safearray。它类似于以前的技术,但内存管理由COM而不是由DLL定义,所以有更少的东西需要由接口的任一方定义。


  • 将回调函数传递给DLL,因此,它不会返回一个字符串数组,而是为其标识的每个字符串调用该函数一次。那么你不必定义任何数组的样子,每个字符串的生命周期只能是回调调用的生命周期 - 如果主机应用程序想要一个副本,它可以这样做。新功能签名将如下所示:

     键入
    TTokenCallback = procedure令牌:PAnsiChar);标准
    程序GetToken(Chain:PAnsiChar; ProcessToken:TTokenCallback);标准



      typedef void(__stdcall * TokenCallback)(char const * Token); 
    void __stdcall GetToken(char const * Chain,TokenCallback ProcessToken);




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


I am creating a DLL in C++, it would be used in a Delphi 7 project.

This question is related to this one, where I present two functions Validate and GetToken only that now they will be done in C++ and the array of strings GetToken produces would be sent back to Delphi.

The problems is I don't know how to create the function in the dll that will return the array of string in c++, and I don't know how it would be stored for further use in Delphi.

The declaration of the function is as follows:

function GetToken(Chain:string):Arrayofstring;

解决方案

According to your code review, the Delphi code expects the function to have the following signature:

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

You cannot write such a function in C++. C++ doesn't know what Delphi strings are, and it doesn't know what Delphi dynamic arrays are, either. Both types need to be allocated from Delphi's memory manager, which your C++ DLL won't have access to. Furthermore, C++ doesn't know how to use Delphi's register calling convention.

The DLL interface was designed poorly. DLLs should never use language-specific types unless it was the designer's intention to exclude all other languages. (And in this case, even later versions of the same language are excluded because the definition of AnsiString changed in Delphi 2009 to include more metadata that Delphi 7 won't handle properly.) The safest calling convention to choose is generally stdcall. It's what everything in the Windows API uses.

A better interface would use types that are common to all languages, and it would dictate the use of memory management that's accessible universally. There are several common ways to do that. For example:

  • The strings are returned as simple nul-terminated arrays of characters — PAnsiChar in Delphi; char* in C++. The DLL allocates buffers for the strings, and also allocates a buffer for the array of those strings. When the host application is finished using the array and the strings, it calls another function exported by the DLL wherein the DLL frees the memory it allocated. This is the model used by, for example, FormatMessage; when the host program is finished the with message string, it calls 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);
    

  • Use COM to return a safearray of BStr objects. It's similar to the previous technique, but the memory management is defined by COM instead of by your DLL, so there's less stuff that needs to be defined by either party of the interface.

  • Pass a callback function to the DLL, so instead of returning an array of strings, the DLL just calls the function once for each string it identifies. Then you don't have to define what any array looks like, and the lifetime of each string can be just the lifetime of the callback call — if the host application wants a copy, it can do so. The new function signature would look something like this:

    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);
    

If you're not the one who designed the DLL interface, then you need to lean on the folks who did and get it changed to be more accessible to non-Delphi code. If you can't do that, then the final alternative is to write a DLL in Delphi that wraps your DLL to massage the parameters into something each side understands.

这篇关于从Delphi 7中的c ++ DLL接收一个字符串数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆