delphifastreportdelphi-10.2-tokyo

FastReport Format function results in Unicode error


I use fastreport 5.4.6 on Delphi 10.2 but fastreport has error when display Format function with Unicode args. Here is error

Create memo with text = [Format('%s' , ['nghìn tỷ'])] nghìn tỷ

It will display "nghìn t? nghìn tỷ"

How to fix it?

Edit

I change function VariantToVarRec in fs_itools.pas of fastreport

procedure VariantToVarRec(v: Variant; var ar: TVarRecArray);
var
...
      varOleStr, varString:
        begin
//          ar[i].VType := vtString;
//          New(ar[i].VString);
//{$IFDEF Delphi12}
//          ar[i].VString^ := AnsiString(v[i]);
//{$ELSE}
//          ar[i].VString^ := v[i];
//{$ENDIF}
          ar[i].VType := vtUnicodeString;
          ar[i].VString := pointer(UnicodeString(v[i]));

       end;
{$IFDEF Delphi12}
      varUString:
        begin
          ar[i].VType := vtUnicodeString;
          New(ar[i].VUnicodeString);
          PUnicodeString(ar[i].VUnicodeString)^ := v[i];
        end;
{$ENDIF}
...
end;

After change

[Format('%s' , ['một nghìn tỷ'])]

will display "một nghìn tỷ". I don't know what will happen if I change function to that (I am a beginner at Delphi).


Solution

  • Fixed. FR 5.6.2 works OK. fs_isysrtti.pas from 5.6.2:

    function FormatV(const Fmt: String; Args: Variant): String;
    var
      ar: TVarRecArray;
      sPtrList: TList;
    begin
      VariantToVarRec(Args, ar, sPtrList);
      Result := Format(Fmt, ar);
      ClearVarRec(ar, sPtrList);
    end;
    

    fs_itools.pas from 5.6.2:

        procedure VariantToVarRec(v: Variant; var ar: TVarRecArray; var sPtrList: Tlist);
        procedure ClearVarRec(var ar: TVarRecArray; var sPtrList: TList);
            ...
        procedure VariantToVarRec(v: Variant; var ar: TVarRecArray; var sPtrList: TList);
        var
          i: Integer;
        {$IFDEF Delphi12}
          pWStr: PWideString;
        {$ELSE}
          pAStr: PAnsiString;
        {$ENDIF}
        begin
          SetLength(ar, VarArrayHighBound(v, 1) + 1);
    
          sPtrList := TList.Create;
          for i := 0 to VarArrayHighBound(v, 1) do
        ...
                        varString:
                        begin
                          ar[i].VType := vtString;
                          New(ar[i].VString);
                {$IFDEF Delphi12}
                          ar[i].VString^ := AnsiString(v[i]);
                {$ELSE}
                          ar[i].VString^ := v[i];
                {$ENDIF}
                        end;
                      varOleStr:
                        begin
                {$IFDEF Delphi12}
                          ar[i].VType := vtWideString;
                          New(pWStr);
                          sPtrList.Add(pWStr);
                          pWStr^ := WideString(v[i]);
                          ar[i].VWideString := PWideString(pWStr^);
                {$ELSE}
                          ar[i].VType := vtAnsiString;
                          //New(ar[i].VAnsiString);
                          New(pAStr);
                          sPtrList.Add(pAStr);
                          pAStr^ := AnsiString(v[i]);
                          ar[i].VAnsiString := PAnsiString(pAStr^);
                {$ENDIF}
                        end;
                {$IFDEF Delphi12}
                      varUString:
                        begin
                          ar[i].VType := vtUnicodeString;
                          New(ar[i].VUnicodeString);
                          PUnicodeString(ar[i].VUnicodeString)^ := v[i];
                        end;
                {$ENDIF}
                      varVariant:
                        begin
                          ar[i].VType := vtVariant;
                          New(ar[i].VVariant);
                          ar[i].VVariant^ := v[i];
                        end;
                    end;
        ...
    
    procedure ClearVarRec(var ar: TVarRecArray; var sPtrList: TList);
    var
      i: Integer;
    begin
      for i := 0 to Length(ar) - 1 do
        if ar[i].VType in [vtExtended, vtString, vtVariant {$IFDEF Delphi6}, vtInt64 {$ENDIF}] then
          Dispose(ar[i].VExtended);
      for i := 0 to sPtrList.Count - 1 do
        Dispose(sPtrList[i]);
      sPtrList.Free;
      Finalize(ar);
    end;