You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决C++Builder调用Delphi DLL返回string时的内存错误?

调用返回字符串的DLL函数时出现内存错误,问题出在哪?

问题情况

  • 现象:调用DLL的字符串返回函数时,仅能显示首字符,随后触发内存错误
  • 环境:用Delphi 11.2编写DLL,C++Builder 5编写调用程序

C++Builder 调用代码

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HINSTANCE MyDll;

    typedef AnsiString(__stdcall *pfRes)(int);
    pfRes TestFunction;

    if ((MyDll = LoadLibrary("D:\\MyFirstLibrary.dll")) == NULL){
        ShowMessage("Cannot Load DLL !");
        return;
    }

    if ((TestFunction = (pfRes)GetProcAddress(MyDll,"TestFunction")) == NULL ) {
       ShowMessage("Cannot find DLL function!");
       return;
    }

    ShowMessage(TestFunction(24));
    FreeLibrary(MyDll);
}

Delphi DLL 代码(在Delphi中调用正常)

uses
  System.SysUtils,
  System.Classes,
  System.JSON;

{$R *.res}

function TestFunction(const _a: integer) : String; stdcall;
var
  StrJSon      : string;
begin
  StrJSon := 'TEST STRING';

  Result := StrJSon;
end;

exports
  TestFunction;
begin

end.

问题根源

  1. 字符串类型不兼容:
    Delphi 11.2默认的String是UnicodeString(UTF-16双字节编码),而CBuilder 5的AnsiString是单字节ANSI编码字符串,两者内存布局完全不同——用C的AnsiString接收Delphi的UnicodeString,只能读到第一个字节(首字符),后续内存解析错误直接引发崩溃。

  2. 内存管理不匹配:
    Delphi的原生字符串内存由Delphi自带的内存管理器分配,CBuilder使用独立的内存管理器。当C代码接收Delphi返回的字符串后,ShowMessage或后续操作会尝试用C++的内存管理器释放这块内存,导致内存错误。

解决方案

方案1:使用C兼容的PChar/char*(最直接)

修改Delphi DLL代码,返回C风格字符串,明确内存释放责任:

uses
  System.SysUtils,
  System.Classes,
  System.JSON;

{$R *.res}

function TestFunction(const _a: integer) : PChar; stdcall;
var
  StrJSon      : string;
begin
  StrJSon := 'TEST STRING';
  // 用StrNew在堆上分配内存,调用方必须用StrFree释放
  Result := StrNew(PChar(StrJSon));
end;

exports
  TestFunction;
begin
end.

修改C++Builder调用代码,添加内存释放步骤:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HINSTANCE MyDll;

    typedef char* (__stdcall *pfRes)(int);
    pfRes TestFunction;

    if ((MyDll = LoadLibrary("D:\\MyFirstLibrary.dll")) == NULL){
        ShowMessage("Cannot Load DLL !");
        return;
    }

    if ((TestFunction = (pfRes)GetProcAddress(MyDll,"TestFunction")) == NULL ) {
       ShowMessage("Cannot find DLL function!");
       return;
    }

    char* resultStr = TestFunction(24);
    ShowMessage(resultStr);
    // 必须释放DLL分配的内存,避免内存泄漏
    StrFree(resultStr);
    FreeLibrary(MyDll);
}

方案2:使用跨语言兼容的BSTR(OLE字符串)

BSTR是Windows系统定义的标准字符串类型,所有COM兼容语言都能正确处理,内存由系统统一分配/释放:
Delphi DLL代码:

uses
  System.SysUtils,
  System.Classes,
  System.JSON;

{$R *.res}

function TestFunction(const _a: integer) : WideString; stdcall;
var
  StrJSon      : string;
begin
  StrJSon := 'TEST STRING';
  // WideString在Delphi中对应BSTR类型
  Result := WideString(StrJSon);
end;

exports
  TestFunction;
begin
end.

C++Builder调用代码:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    HINSTANCE MyDll;

    typedef BSTR (__stdcall *pfRes)(int);
    pfRes TestFunction;

    if ((MyDll = LoadLibrary("D:\\MyFirstLibrary.dll")) == NULL){
        ShowMessage("Cannot Load DLL !");
        return;
    }

    if ((TestFunction = (pfRes)GetProcAddress(MyDll,"TestFunction")) == NULL ) {
       ShowMessage("Cannot find DLL function!");
       return;
    }

    BSTR resultStr = TestFunction(24);
    ShowMessage(WideString(resultStr));
    // 用系统API释放BSTR内存
    SysFreeString(resultStr);
    FreeLibrary(MyDll);
}

方案3:使用共享内存管理器(需版本兼容)

在Delphi DLL和C++Builder程序中都引用SharedMem单元,让两者使用同一个内存管理器,可直接传递Delphi的UnicodeString:

  • Delphi DLL:在uses中添加SharedMem
  • C++Builder程序:在工程中添加SharedMem.hpp引用,同时将typedef改为WideString(__stdcall *pfRes)(int)

此方案存在版本兼容风险,不同版本的Delphi/C++Builder的SharedMem可能不兼容,优先推荐方案1或2。


内容的提问来源于stack exchange,提问作者mesutuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 07:10:19