首页 文章

尝试向.DLL导出跨单元重载的函数时出现E2276错误

提问于
浏览
1

我一直在将有用的例程收集到一个实用程序单元中,然后我将其编译成.DLL和.DCU,因此我可以选择哪种方法可以方便地访问这些例程 .

例如,我编写了自己的 Lowcase ,它作用于[宽]字符或[宽]字符串以实现明显的功能,奇怪的是Embarcadero没有实现 .

同样,我扩展了 MaxMin 来查找数字数组的最大值/最小值 .

在某些情况下,我基本上只是为现有函数提供了一个别名,例如

function LowCase
         (const st                        : ANSIstring
         )                                : ANSIstring;
          stdcall;
begin
  result := ansilowercase(st);
end;

它将被导出到DLL

exports LowCase
         (const st                        : ANSIstring
          ) name 'lowcaseansistr';

到现在为止还挺好 .

我最近发现了

var
  v_uint64 : uint64;

  v_uint64 := $FFFFFFFFFFFFFFFF;
  writeln('v_uint64=',inttostr(v_uint64));
  v_uint64 := $7FFFFFFFFFFFFFFF;
  writeln('v_uint64=',inttostr(v_uint64));

在第一个实例(-1)中产生了错误的结果 - 实际上,无论MSB设置在哪里,但在MSB清除的第二种情况下都可以 .

所以我找到 uinttostr 并用这个标准函数代替 inttostr 解决了这个问题 .

ISTM如果我可以再简单地执行别名技巧会更方便,所以我试过(实现)

function inttostr
          (p_nb_int                       : uint64
          )                               : string;
          stdcall;
begin
  result := uinttostr(p_nb_int);
end;

(接口)

function inttostr
          (p_nb_int                       : uint64
          )                               : string;
          overload;
          stdcall;

这非常愉快,但实施起来

exports inttostr
          (p_nb_int                       : uint64
          ) name 'uinttostr64';

在项目中生成 E2276 Identifier 'IntToStr' cannot be exported . E2276似乎与 local directive 相关,显然是在声明中由 local; 调用 - 但是在System.Sysutils.pas中由EMBT提供的源中,声明是

function IntToStr(Value: Integer): string; overload;
function IntToStr(Value: Int64): string; overload;

没有 local; 在望!

所以 - 我很难过 . 我该如何解决这个问题? (XE2)


这是一个测试程序:

program countparamsshort;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  dxutypes,
//  dxumethods,
  system.math,windows,vcl.Graphics,classes,System.SysUtils;
//{$I C:\delphi\dxu.inc}

var
  v_int64 : int64 ;           // -2^63..2^63-1
  v_uint64 : uint64;          // 0..2^64-1

procedure showv;
begin
  writeln('v_int64= ',inttostr(v_int64));
  writeln('v_uint64=',inttostr(v_uint64));
end;

begin
  writeln('min values');
  v_int64  := -214748364999;
  v_uint64 := 0;
  showv;
  writeln('max values');
  v_int64  := $FFFFFFFFFFFFFFFF;
  v_uint64 := $FFFFFFFFFFFFFFFF;
  showv;
  writeln('max 63-bit values');
  v_int64  := $7FFFFFFFFFFFFFFF;
  v_uint64 := $7FFFFFFFFFFFFFFF;
  showv;
//  writeln(inttostr(max(10,3)),' & ',inttostr(max([1,12,7,9,11,4])));
  writeln('procedure finished');
  readln;
end.

使用.dcu dxumethods运行并包含文件C:\ delphi \ dxu.inc注释掉调用 inttostr 的system.math实现以及生成的报告

min values
v_int64= -214748364999
v_uint64=0
max values
v_int64= -1
v_uint64=-1
max 63-bit values
v_int64= 9223372036854775807
v_uint64=9223372036854775807
procedure finished

哪个 NOT 对于 v_uint64 是正确的 . 为 uint64 调用 uinttostr 可以解决问题,但这意味着要记住这样做 .

从dxumethods元素中删除注释意味着包含我的 inttostr 版本 - 实际执行 uinttostr . 结果是:

min values
v_int64= -214748364999
v_uint64=0
max values
v_int64= -1
v_uint64=18446744073709551615
max 63-bit values
v_int64= 9223372036854775807
v_uint64=9223372036854775807
10 & 12
procedure finished

现在正确显示 v_uint64 的值 . 这意味着我可以使用 inttostr 并且可以忘记所有关于 uinttostr 的内容,所以我没有想过它,现在编译器可以在将来完成这项工作 .

我还没有注释掉 MAX 调用,它使用相同的方法让我找到一个数组的 max - 这意味着我可以忘记所有关于maxintvalue和maxvalue(它调用那些例程)但是我再一次只需使用 max - 无论是传统版本还是相同的数组概念 . 当一个人做的时候,不要用三个例程(和MIN等价的另外3个)混淆思维 .

最后,重新评论dxumethods并取消注释包含文件的包含文件

function inttostr
      (p_nb_int                       : uint64
      )                               : string;
      overload;
      stdcall;
      external 'dxuproject.dll' name 'uinttostr64';

产生了相同的结果,这次来自.DLL - 关键是在构造.DLL时限定函数名,否则你会错过 E2276 错误 .

现在 - 为什么会发生这种情况,当这些事情发生在理论家身上时 - 以及它与'local'声明似乎是一个Kylix宿醉的事情 - 好吧,那是在众神的圈数(或者可能是失效) AFAICS .

无论如何 - 好结果;问题解决了 . 季节的问候...

2 回答

  • 0

    也许当涉及到重载函数和名称错误时,Delphi编译器无法告诉 Int64 来自 Uint64 参数 . 因此,请尝试精确指定您要导出的函数,而不依赖于自动解析 .

    exports UnitName.FunctionName(Params);
    
  • 2

    我不太明白你的总体目标 . 唯一可以导入这样一个函数的东西是使用与DLL相同的编译器构建的Delphi代码 . 而且该代码可以直接调用 UIntToStr .

    而且您似乎也在重新实现RTL已经具有的功能 . 例如, AnsiStrings 单元将为8位文本提供案例切换功能 . 在 Math 中,您会发现 MinValue/MaxValue 表示浮点值数组,而 MinIntValue/MaxIntValue 表示整数数组 . 它看起来好像你正在重新发明轮子 .

    也就是说,从表面上看问题,以下是导出函数的方法:

    library Project1;
    
    uses
      SysUtils;
    
    exports
      UIntToStr(Value: UInt64) name 'uinttostr64';
    
    begin
    end.
    

    这将从 SysUtils 导出函数,因此使用 register 调用约定 . 当然,这对你来说没问题,因为你只能从Delphi调用这个函数 .

    如果您急于导出 IntToStr ,那么您应该使用完全合格的单位名称 . 例如,假设函数在 Unit1 中声明,那么你会写:

    exports
      Unit1.IntToStr(Value: UInt64) name 'uinttostr64';
    

相关问题