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

时间:2013-12-24 08:32:59

标签: delphi dll delphi-xe2 dllexport overloading

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

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

同样,我扩展了 Max Min 来查找数字数组的最大值/最小值。

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

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 注释掉 system.math inttostr与结果报告的实施

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

对于v_uint64更正。为uinttostr调用uint64可以解决问题,但这意味着要记住这样做。

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错误。

现在 - 为什么会发生这种情况,当MAX/MIN周围的类似阴谋不会扰乱编译器时,我会留给理论家 - 以及它与“本地”声明有什么关系,这似乎是一个Kylix宿醉 - 嗯,那是在神AFAICS的圈数(或者可能是失效)。

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

2 个答案:

答案 0 :(得分:2)

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

  exports UnitName.FunctionName(Params);

答案 1 :(得分:0)

我无法理解你的总体目标。唯一可以导入这样一个函数的东西是使用与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';