简体   繁体   中英

Delphi XE7 Android Record with String Element won't compile

In Delphi FMX XE7, Win32, I have a record type:

type TSettingsRec = record
  SessionTimeOut: Word;
  EventString: String[50];
end;

When I change the Target to Android, I get a compiler error:

[DCC Error] MainForm.pas(45): E2029 ';' expected but '[' found

I need to define the length[50] of the EventString element because the TRecord is actually being read from a database (Firebird) which was written to the database by a Delphi 7 program using Bin2Hex (for a reason known only to the author of that program):

var
  rec: TSettingsRec;
  settings: string;

SetLength(settings, SizeOf(rec)*2);
BinToHex(@rec, @settings[1]), SizeOf(rec));

This I decode effectively in using XE7 (win32) using:

var
  rec: TSettingsRec;
  settings: String;

SetLength(settings, SizeOf(rec) * 2);
System.Classes.HexToBin(Pchar(settings), @rec, SizeOf(rec));

But this doesn't work, when I compile for Android. So how do I specify the length [50] of the EventString on the Android platform?

You cannot use short strings on the mobile compilers. You'll need to re-think the code. Perhaps like this:

type
  TSettingsRec = record
  private
    FSessionTimeOut: Word;
    FEventStringLength: Byte;
    FEventString: array [0..49] of Byte; // ANSI encoded
    function GetEventString: string;
    procedure SetEventString(const Value: string);
  public
    property SessionTimeOut: Word read FSessionTimeOut write FSessionTimeOut;
    property EventString: string read GetEventString write SetEventString;
  end;

This replicates the memory layout of the legacy short string. Which is a single byte containing the string length, followed by an array of length 50, of ANSI encoded text containing the payload. The record wraps the legacy layout with more natural properties, which make the type more readily usable.

Of course we still need to write those properties. Like this:

function TSettingsRec.GetEventString: string;
var
  Bytes: TBytes;
begin
  SetLength(Bytes, Min(FEventStringLength, Length(FEventString)));
  Move(FEventString, Pointer(Bytes)^, Length(Bytes));
  Result := TEncoding.ANSI.GetString(Bytes);
end;

procedure TSettingsRec.SetEventString(const Value: string);
var
  Bytes: TBytes;
begin
  Bytes := TEncoding.ANSI.GetBytes(Value);
  FEventStringLength := Min(Length(Bytes), Length(FEventString));
  Move(Pointer(Bytes)^, FEventString, FEventStringLength);
end;

This will work on Windows, but not on mobile compilers because TEncoding.ANSI has no meaning. So you'll need to create an encoding with the desired code page. For instance:

Encoding := TEncoding.Create(1252);

Do note that I've not even compiled this code, so it may have some wrinkles. But I think the concept shown here is the cleanest way to move your code forward. I'll leave you to work out the appropriate details for your setting.

String[50] is not supported on mobile platforms. That is a legacy data type known as a ShortString , consisting of 51 bytes of data, where the first byte is the length of the string and the next 50 bytes are 8-bit characters that define the string value.

The equivalent definition would be array[0..50] of byte , where the first byte defines the length of the actual data. byte is used because the mobile platforms do not support AnsiChar (without a 3rd party patch).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM