سؤال

I've been gathering useful routines into a utilities unit which I then compile into a .DLL and a .DCU, so I can choose which method is convenient to access those routines.

For instance, I've written my own Lowcase which acts on [wide]chars or [wide]strings to implement the obvious function, bizarrely not implemented by Embarcadero.

Similarly, I've extended Max and Min to find Max/Min of an array of numerics.

In some cases, I've essentially simply provided an alias to an existing function, such as

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

which would be exported to the DLL by

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

So far, so good.

I recently found that

var
  v_uint64 : uint64;

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

produced an incorrect result in the first instance (-1) - in fact, wherever MSB is set, but is fine in the second case where MSB is clear.

So I found uinttostr and substituting this standard function for inttostr solved the issue.

ISTM it would be far more convenient if I could simply perform the alias trick again, so I tried (implementation)

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

(interface)

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

Which worked quite happily, but implementing

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

in the project generated E2276 Identifier 'IntToStr' cannot be exported. E2276 seems to be related to local directive, apparently invoked by local; in the declaration - but in the source provided by EMBT in System.Sysutils.pas, the declaration is

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

No local; in sight!

So - I'm stumped. How do I get around this? (XE2)


Here's a test program:

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.

Running as-is with the .dcu dxumethods and include file C:\delphi\dxu.inc commented-out invokes the system.math implementation of inttostr with the resultant report

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

Which is NOT correct for v_uint64. Invoking uinttostr for a uint64 would cure the problem BUT that means remembering to do so.

Removing the comment from the dxumethods element means that my version of inttostr is included - which actually executes uinttostr. Results are:

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

where the value of v_uint64 is now displayed correctly. This means that I can use inttostr and can forget all about uinttostr, so I don't have to sit here figuring out which I should use when. I've figured it out once, and now the compiler can do the work in future.

I've also un-commented-out the MAX call which uses the same methodology to allow me to find the max of an array - it means I can forget all about maxintvalue and maxvalue (it invokes those routines) but once again, I can simply use max - whether the traditional version or the same concept with regard to arrays. Don't clutter up the mind with three routines (and another 3 for the MIN equivalents) when one will do.

Finally, re-commenting dxumethods and un-commenting the include file, which contains lines like

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

produced identical results, this time from the .DLL - the key being to qualify the function-name when constructing the .DLL else you trip over the E2276 error.

Now - WHY this occurs, when similar machinations around MAX/MIN don't faze the compiler, I'll leave to the theoreticians - and what it has to do with 'local' declarations which seem to be a Kylix hangover - well, that's in the laps (or perhaps lapse) of the gods AFAICS.

Anyhow - good outcome; problem solved. Season's Greetings...

هل كانت مفيدة؟

المحلول

Perhaps when it comes to overloading functions and name mangling Delphi compiler cannot tell Int64 from Uint64 parameters. So try to precisely specify which function you meant to export without relying upon auto-resolving.

  exports UnitName.FunctionName(Params);

نصائح أخرى

I cannot quite understand your overall goal. The only thing that could import such a function is Delphi code built with the same compiler as the DLL. And that code could simply call UIntToStr directly.

And you also seem to be re-implementing functions that the RTL already has. For instance, the AnsiStrings unit will supply your case switching functions for 8 bit text. And in Math you will find MinValue/MaxValue for arrays of floating point values, and MinIntValue/MaxIntValue for arrays of integers. It does look to me as though you are re-inventing the wheel.

That said, taking your question at face value, here is how you export the function:

library Project1;

uses
  SysUtils;

exports
  UIntToStr(Value: UInt64) name 'uinttostr64';

begin
end.

This exports the function from SysUtils and so uses the register calling convention. That's no problem to you of course since you can only call the function from Delphi.

If you are desperate to export your IntToStr, then you should use a fully qualified unit name. For instance, suppose the function is declared in Unit1, then you would write:

exports
  Unit1.IntToStr(Value: UInt64) name 'uinttostr64';
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top