如何解决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.
问题根源
字符串类型不兼容:
Delphi 11.2默认的String是UnicodeString(UTF-16双字节编码),而CBuilder 5的AnsiString是单字节ANSI编码字符串,两者内存布局完全不同——用C的AnsiString接收Delphi的UnicodeString,只能读到第一个字节(首字符),后续内存解析错误直接引发崩溃。内存管理不匹配:
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
相关产品推荐
相关产品推荐

