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

Delphi7调用Delphi11编写的DLL字符串函数触发无效指针错误求助

问题根源

你遇到的问题核心在于Delphi 7和Delphi 11的字符串类型不兼容:

  • Delphi 7默认使用AnsiString(单字节字符),而Delphi 11默认使用UnicodeString(双字节字符),两者内部存储结构完全不同。
  • 虽然两边都引入了ShareMem共享内存管理器,但ShareMem仅能保证同版本Delphi的字符串内存管理兼容。跨版本场景下,宿主(Delphi7)尝试释放DLL(Delphi11)分配的字符串内存时,因内存块元数据不匹配,直接触发EInvalidPointer错误。
  • 整数相加函数正常,是因为整数是值类型,不需要跨模块的内存分配/释放操作,不存在内存管理冲突。
解决方案

以下是几种可行的解决方式,按推荐程度排序:

方案1:使用PChar+标准内存分配函数(最稳妥的跨版本方案)

避免直接传递Delphi原生字符串,改用PChar作为参数和返回值,同时用系统标准内存分配函数(如CoTaskMemAlloc/CoTaskMemFree)管理内存,确保跨模块内存操作一致。

DLL端(Delphi11)代码:

library MergeDLL;

uses
  SysUtils, Classes, ActiveX;

function MergeText(t1, t2: PChar): PChar; stdcall;
var
  MergedStr: string;
begin
  MergedStr := string(t1) + string(t2);
  // 用CoTaskMemAlloc分配内存,宿主可用CoTaskMemFree释放
  Result := CoTaskMemAlloc(Length(MergedStr) * SizeOf(WideChar) + 1);
  StringToWideChar(MergedStr, Result, Length(MergedStr) + 1);
end;

exports
  MergeText name 'MergeText';

begin
end.

宿主端(Delphi7)代码:

type
  TMergeText = function(t1, t2: PChar): PChar; stdcall;

procedure TForm1.btnMergeClick(Sender: TObject);
var
  handle: THandle;
  MergeText: TMergeText;
  LNewText: string;
  P: PChar;
begin
  handle := LoadLibrary(PChar(dll_path));
  if handle <> 0 then
  begin
    @MergeText := GetProcAddress(handle, 'MergeText');
    if @MergeText <> nil then
    begin
      P := MergeText(PChar(edText1.Text), PChar(edText2.Text));
      if P <> nil then
      begin
        LNewText := P;
        CoTaskMemFree(P); // 必须释放DLL分配的内存
        edMerged.Text := LNewText;
      end;
    end;
    FreeLibrary(handle);
  end;
end;

方案2:统一使用AnsiString(简单但仅支持ANSI字符)

在Delphi11中显式使用AnsiString作为参数和返回值,让两边字符串类型一致,配合ShareMem实现内存管理兼容。

DLL端(Delphi11)代码:

library MergeDLL;

uses
  ShareMem, SysUtils, Classes;

function MergeText(t1, t2: AnsiString): AnsiString; stdcall;
begin
  Result := t1 + t2;
end;

exports
  MergeText name 'MergeText';

begin
end.

宿主端(Delphi7)代码:

// 注意:TMergeText的参数和返回值要改成AnsiString
type
  TMergeText = function(t1, t2: AnsiString): AnsiString; stdcall;

procedure TForm1.btnMergeClick(Sender: TObject);
var
  handle: THandle;
  MergeText: TMergeText;
  LNewText: AnsiString;
begin
  handle := LoadLibrary(PChar(dll_path));
  if handle <> 0 then
  begin
    @MergeText := GetProcAddress(handle, 'MergeText');
    if @MergeText <> nil then
    begin
      LNewText := MergeText(AnsiString(edText1.Text), AnsiString(edText2.Text));
      edMerged.Text := string(LNewText);
    end;
    FreeLibrary(handle);
  end;
end;

注意:此方案仅适用于不需要Unicode字符的场景,因为AnsiString无法正确存储多字节Unicode字符。

方案3:使用COM接口(面向对象的优雅方案)

通过COM接口封装字符串操作,COM的内存管理模型跨平台/跨版本兼容,Delphi对COM接口的支持完善。

DLL端(Delphi11)代码:

library MergeDLL;

uses
  SysUtils, Classes, ComObj;

type
  IMergeService = interface(IUnknown)
    ['{YOUR-GUID-HERE}'] // 用Delphi工具生成唯一GUID
    function MergeText(const t1, t2: WideString): WideString; stdcall;
  end;

  TMergeService = class(TInterfacedObject, IMergeService)
  public
    function MergeText(const t1, t2: WideString): WideString; stdcall;
  end;

function TMergeService.MergeText(const t1, t2: WideString): WideString;
begin
  Result := t1 + t2;
end;

function CreateMergeService: IMergeService; stdcall;
begin
  Result := TMergeService.Create;
end;

exports
  CreateMergeService name 'CreateMergeService';

begin
end.

宿主端(Delphi7)代码:

type
  IMergeService = interface(IUnknown)
    ['{YOUR-GUID-HERE}'] // 必须和DLL中的GUID完全一致
    function MergeText(const t1, t2: WideString): WideString; stdcall;
  end;

  TCreateMergeService = function: IMergeService; stdcall;

procedure TForm1.btnMergeClick(Sender: TObject);
var
  handle: THandle;
  CreateMergeService: TCreateMergeService;
  MergeService: IMergeService;
  LNewText: WideString;
begin
  handle := LoadLibrary(PChar(dll_path));
  if handle <> 0 then
  begin
    @CreateMergeService := GetProcAddress(handle, 'CreateMergeService');
    if @CreateMergeService <> nil then
    begin
      MergeService := CreateMergeService;
      if Assigned(MergeService) then
      begin
        LNewText := MergeService.MergeText(WideString(edText1.Text), WideString(edText2.Text));
        edMerged.Text := string(LNewText);
      end;
    end;
    FreeLibrary(handle);
  end;
end;

注意:生成GUID可使用Delphi的Tools->Create GUID工具,确保两边接口的GUID完全一致。

内容的提问来源于stack exchange,提问作者Stefan van Roosmalen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 12:03:29