how do i deal with short string in firemonkey?

  

i have created VCL client application with indy, and now i am trying to create a client for android using firemonkey but there is issues with combining the code to work same on firemonkey here is the problem :

i been using shotrstring to packed and read params inside client execute as following

type
TPackedParams = packed record
{ Params: String[250]; } // that how i used it in vcl but this not supported in fmx so i change to the following
Params: array[0..250] of byte;
end;
// unfortunately still have more issues got invalid type cast in compiler when using packedparams here

if ReceiveParams then // params incomming
begin
TCPClient.Socket.ReadBytes(IdBytes, SizeOf(PackedParams), False);
BytesToRaw(IdBytes, PackedParams, SizeOf(PackedParams));
ParamsCount := 0;
repeat
Inc(ParamsCount);
P := Pos(Sep, String(PackedParams.Params));// invalid type cast
Params[ParamsCount] := Copy(String(PackedParams.Params), 1, P – 1);
Delete(PackedParams.Params, 1, P + 4);
until PackedParams.Params = ”;
end;
if ReceiveStream then // stream incomming
begin
Size := TCPClient.Socket.ReadInt64;
TCPClient.Socket.ReadStream(Ms, Size, False);
Ms.Position := 0;
end;

here is my full client code of fmx

interface

uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdGlobal,
FMX.StdCtrls;

const
Sep = ‘#$%^&’;
DefaultPort = 16000;

type
TPackedParams = packed record
Params: array[0..250] of byte;
end;

type
TClientThread = class(TThread)
private
Command: string;
protected
procedure Execute; override;
end;

type
TForm1 = class(TForm)
TCPClient: TIdTCPClient;
Label1: TLabel;
procedure TCPClientConnected(Sender: TObject);
private
{ Private declarations }
UniqueID: DWord;
FRoomID: Integer;
CurrentID : integer;
procedure ProcessCommands(Command: string);
function namerecord: String;
procedure updatecaption;
procedure SendCommandWithParams(TCPClient: TIdTCPClient; Command,
Params: String);

public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

var
Ms: TMemoryStream;

{$R *.fmx}
{$R *.SmXhdpiPh.fmx ANDROID}

{ TForm1 }

function TForm1.namerecord: String;
begin
Result := ‘android_test’;
end;

procedure TForm1.SendCommandWithParams(TCPClient: TIdTCPClient;
Command, Params: String);
var
PackedParams: TPackedParams;
begin
if not TCPClient.Connected then
Exit;
TCPClient.Socket.WriteLn(‘1’ + Command);
PackedParams.Params := ShortString(Params);
TCPClient.Socket.Write(RawToBytes(PackedParams, SizeOf(PackedParams)));
end;

procedure Tform1.updatecaption;
begin
label1.Text := namerecord;
end;

procedure TForm1.ProcessCommands(Command: string);
var
Params: array [1 .. 10] of String;
ParamsCount, P: Integer;
PackedParams: TPackedParams;
PStr: String;
IdBytes: TIdBytes;
ReceiveParams, ReceiveStream: Boolean;
Size: Int64;
begin
Ms := TMemoryStream.Create;
ReceiveParams := False;
ReceiveStream := False;

if Command[1] = ‘1’ then // command with params
begin
Command := Copy(Command, 2, Length(Command));
ReceiveParams := True;
end
else if Command[1] = ‘2’ then // command + memorystream
begin
Command := Copy(Command, 2, Length(Command));
ReceiveStream := True;
Ms.Position := 0;
end
else if Command[1] = ‘3’ then // command with params + memorystream
begin
Command := Copy(Command, 2, Length(Command));
ReceiveParams := True;
ReceiveStream := True;
end;

if ReceiveParams then // params incomming
begin
TCPClient.Socket.ReadBytes(IdBytes, SizeOf(PackedParams), False);
BytesToRaw(IdBytes, PackedParams, SizeOf(PackedParams));
ParamsCount := 0;
repeat
Inc(ParamsCount);
P := Pos(Sep, String(PackedParams.Params));
Params[ParamsCount] := Copy(String(PackedParams.Params), 1, P – 1);
Delete(PackedParams.Params, 1, P + 4);
until PackedParams.Params = ”;
end;
if ReceiveStream then // stream incomming
begin
Size := TCPClient.Socket.ReadInt64;
TCPClient.Socket.ReadStream(Ms, Size, False);
Ms.Position := 0;
end;
Command := Trim(Command);

if Command = ‘SIMPLEMESSAGE’ then
begin
//
end;
if Command = ‘INVALIDPASSWORD’ then
begin
TCPClient.Disconnect;
//
end;

if Command = ‘SENDYOURINFO’ then // succesfully logged in
begin
UniqueID := StrToInt(Params[1]);
PStr := namerecord;
SendCommandWithParams(TCPClient, ‘TAKEMYINFO’, PStr);
//
end;
if Command = ‘DISCONNECTED’ then
begin
//
end;

end;

procedure TForm1.TCPClientConnected(Sender: TObject);
begin
ClientThread := TClientThread.Create(False);
SendCommandWithParams(TcpClient, ‘LOGIN’, namerecord + Sep );
end;

{ TClientThread }

procedure TClientThread.Execute;
begin
inherited;
while not Terminated do
begin
if not Form1.TCPClient.Connected then
Terminate
else
begin
if Form1.TCPClient.Connected then
Command := Form1.TCPClient.Socket.ReadLn(”, 5);
if Command <> ” then
Form1.ProcessCommands(Command);
Command := ”;
end;
end;
end;

end.

Update

i did follow remy comment i installed third-party patch to re-enable short string

then i created a unit for packedparams record with getter and setter property to convert between bytes and strings here , but i still got error and warning in compiler

[DCC Warning] fmxproject.pas(75): W1057 Implicit string cast from
‘ShortString’ to ‘string’

at this code

procedure TForm1.SendCommandWithParams(TCPClient: TIdTCPClient;
Command, Params: String);
var
PackedParams: TPackedParams;
begin
if not TCPClient.Connected then
Exit;
TCPClient.Socket.WriteLn(‘1’ + Command);
PackedParams.Params := ShortString(Params);// here is warning
TCPClient.Socket.Write(RawToBytes(PackedParams, SizeOf(PackedParams)));
end;

and also error

[DCC Error] fmxproject.pas(128): E2197 Constant object cannot be
passed as var parameter

at this code

if ReceiveParams then // params incomming
begin
TCPClient.Socket.ReadBytes(IdBytes, SizeOf(PackedParams), False);
BytesToRaw(IdBytes, PackedParams, SizeOf(PackedParams));
ParamsCount := 0;
repeat
Inc(ParamsCount);
P := Pos(Sep, String(PackedParams.Params));
Params[ParamsCount] := Copy(String(PackedParams.Params), 1, P – 1);
Delete(PackedParams.Params, 1, P + 4);// here is error
until PackedParams.Params = ”;
end;

, here is updated code

unit conmono;

interface
uses System.Types, System.ByteStrings, SysUtils, Math;

const
Sep = ‘#$%^&’;
DefaultPort = 16000;

type
TPackedParams = packed record
private
{ Private declarations }
FParamsLength: Byte;
FParams: array [0..250] of Byte;
function GetParamstring: string;
procedure SetParamstring(const Value: string);

public
{ Public declarations }
property Params: string read GetParamstring write SetParamstring;

end;

TConnection = class(TObject)
UniqueID: DWORD;
Thread: Pointer;
end;

implementation

function TPackedParams.GetParamstring: string;
var
Bytes: TBytes;
begin
SetLength(Bytes, Min(FParamsLength, Length(FParams)));
Move(FParams, Pointer(Bytes)^, Length(Bytes));
Result := TEncoding.ANSI.GetString(Bytes);
end;

procedure TPackedParams.SetParamstring(const Value: string);
var
Bytes: TBytes;
begin
Bytes := TEncoding.ANSI.GetBytes(Value);
FParamsLength := Min(Length(Bytes), Length(FParams));
Move(Pointer(Bytes)^, FParams, FParamsLength);
end;

end.

Comments are closed.