Search code examples
delphidelphi-xe5fpc

Strings between FPC & Delphi


I am having problems getting length of String in Delphi from an FPC DLL. Which is weird because I can get the String back from the DLL but I can't get its length.

Delphi:

program Project2;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

function Test(const S: String): Integer; cdecl; external 'c:\Project1.dll';

var
    A: String;
begin 
    A := 'test';
    WriteLn(Test(A)); // 1 ?
    ReadLn;
end.

FPC:

library project1;

{$mode ObjFPC}{$H+}

uses
  Classes;

function Test(const A: String): Integer; cdecl; export;
begin
 Result := Length(A);
end;

exports Test;

end.

Solution

  • String in Delphi 2009+ is UnicodeString, and AnsiString in earlier versions.

    String in FPC is always AnsiString, it never maps to UnicodeString. And AFAIK, FPC's string types are not binary compatible with Delphi's string types anyway. So you cannot pass a Delphi AnsiString to a FPC AnsiString and vice versa, and the same for UnicodeString.

    You should not be passing String values over the DLL boundary anyway, especially when multiple compilers are involved, and especially since you are not using FPC's Delphi mode. You need to redesign your DLL to be more portable, eg:

    FPC:

    library project1;
    
    {$mode ObjFPC}
    {$H+}
    
    uses
      Classes;
    
    function TestA(const A: PAnsiChar): Integer; cdecl; export;
    begin
     Result := Length(A);
    end;
    
    function TestW(const A: PWideChar): Integer; cdecl; export;
    begin
     Result := Length(A);
    end;
    
    exports TestA, TestW;
    
    end.
    

    Delphi:

    program Project2;
    
    {$APPTYPE CONSOLE}
    
    {$R *.res}
    
    uses
      System.SysUtils;
    
    function Test(const S: PChar): Integer; cdecl; external 'Project1.dll' name {$IFDEF UNICODE}'TestW'{$ELSE}'TestA'{$ENDIF};
    
    var
      A: String;
    begin 
      A := 'test';
      WriteLn(Test(PChar(A)));
      ReadLn;
    end.