Search code examples
stringpointersdelphicharpchar

String to PAnsiChar conversion trouble


These are a C DLL function example and its Delphi translation:

C definition:

DLL_EXPORT int AR_dll_function (const char *terminal_no, const char *description);

Delphi definition:

function Ar_Dll_Function(const TerminalNo: PAnsiChar; const Description: PAnsiChar):Integer;

...

function Ar_Dll_Function(const TerminalNo: PAnsiChar; const Description: PAnsiChar):Integer;
var
  MyFunct : function(const TerminalNo: PAnsiChar; const Description: PAnsiChar):Integer;cdecl;
begin
  Result := 0;
  @MyFunct:=GetProcAddress(HInst,'ar_dll_function');
  if Assigned(MyFunct) then
    Result := MyFunct(TerminalNo, Description);
end;

I use the above Delphi function like this:

function SP(const s:string): PAnsiChar;
var
  UTF8Str: RawByteString;
begin
  Result := #0;
  SetCodePage(UTF8Str, 0, False);
  UTF8Str := UTF8Encode(s);
  Result := PAnsiChar(AnsiString(UTF8Str));
end;

...

result := Ar_Dll_Function(SP(dTermNo),SP(descr));

The problem is between the two PAnsiChar parameters. When I go into the DLL function in debug mode, I see that the second PAnsiChar usually is the same as the first parameter, or the same as the function name:

//parameter examples in string :
dtermno:='AT0000058863'; descr:='NAKİT'; 

//parameter examples in PAnsiChar :
TerminalNo:='AT0000058863'; const Description:='AT0000058863'; //or
TerminalNo:='AT0000058863'; const Description:='ar_dll_function'; 

How can I solve the problem?


Solution

  • The problem that you have is that SP returns the address of a string buffer that belongs to a local variable in SP. So when SP returns that variable is destroyed, and the pointer is now invalid.

    I would call the function like this:

    var
      dTermNo, descr: string;
    ....
    dTermNo := ...;
    descr := ...;
    retval := Ar_Dll_Function(PAnsiChar(UTF8String(dTermNo)), PAnsiChar(UTF8String(descr)));
    

    Alternatively you could push the UTF-8 encoding down to the Ar_Dll_Function wrapper:

    function Ar_Dll_Function(const TerminalNo, Description: string): Integer;
    var 
      MyFunct: function(TerminalNo, Description: PAnsiChar): Integer; cdecl;
    begin
      Result := 0;
      @MyFunct := GetProcAddress(HInst, 'ar_dll_function');
      if Assigned(MyFunct) then
        Result := MyFunct(PAnsiChar(UTF8String(TerminalNo)), 
          PAnsiChar(UTF8String(Description)));
    end;