mikerabat 20 Posted June 24, 2021 Hi! I'm currently migrating our projects from Delphi2010 to Delphi 10.4. One of my biggest changes is actually using StrLCopy and other Ansistring functions that used to be in SysUtils. They are now marked as deprecated and moved to System.AnsiStrings so ... I followed the compiler hint. Now the base problem is that the compiler is confused which function to use so I always prefix the call with System.AnsiStrings.StrLCopy ... which fixed that. But that looks actually very "ugly" and I have the feeling that this is not the way to go idera ment to go. Is there a "best" or anticipated way to handle this? kind regards Mike Share this post Link to post
Stefan Glienke 2002 Posted June 24, 2021 1 hour ago, mikerabat said: Is there a "best" [...] way to handle this? Yes, ditch AnsiString. 6 Share this post Link to post
FPiette 383 Posted June 24, 2021 You could create your own function MyStrLCopy() which simply call the original one. If you make it inline, then it will be as fast. Share this post Link to post
mikerabat 20 Posted June 25, 2021 16 hours ago, Stefan Glienke said: Yes, ditch AnsiString. haha... I'd love to but I have file and communication structures that need good old ansi strings. Or do you actually have a better idea than: str8 := UTF8String(SurName); System.AnsiStrings.StrLCopy(@patData.surname[0],PAnsiChar(str8), length(patData.surname)); to bring a normal delphi string (SurName) to a structure (patData) that contains single byte characters? Share this post Link to post
David Heffernan 2345 Posted June 25, 2021 (edited) 1 hour ago, mikerabat said: bring a normal delphi string (SurName) to a structure (patData) that contains single byte characters? TEncoding.UTF8.GetBytes 1 hour ago, mikerabat said: I have file and communication structures that need good old ansi strings. You don't need to use AnsiString. Edited June 25, 2021 by David Heffernan Share this post Link to post
mikerabat 20 Posted June 25, 2021 4 minutes ago, David Heffernan said: TEncoding.UTF8.GetBytes You don't need to use AnsiString. You mean I don't need AnsiCharacters to communicate with a device that only understands Single Byte characters? So... how is that? And tell me then how to use GetBytes to fill a structure like: type TPatData = packed record SurName : Array[0..31] of AnsiChar; FirstName : Array[0..31] of AnsiChar; end; var pat : TPatData; formSurName : String; begin FillChar(pat, sizeof(pat), 0); // code to be filled here.... end; Share this post Link to post
David Heffernan 2345 Posted June 25, 2021 9 minutes ago, mikerabat said: You mean I don't need AnsiCharacters to communicate with a device that only understands Single Byte characters? So... how is that? TEncoding.UTF8.GetBytes Share this post Link to post
mikerabat 20 Posted June 25, 2021 23 minutes ago, David Heffernan said: TEncoding.UTF8.GetBytes Sorry but can you elaborate that? I actually cannot see how I get there a string converted to a field in the record... what am I missing here? Share this post Link to post
David Heffernan 2345 Posted June 25, 2021 That returns a UTF-8 encoded byte array which you can copy into your record. Are you familiar with TEncoding, it's a somewhat import tool for text encodings? Share this post Link to post
Remy Lebeau 1394 Posted June 25, 2021 (edited) 9 hours ago, mikerabat said: Sorry but can you elaborate that? I actually cannot see how I get there a string converted to a field in the record... what am I missing here? The main problem with TEncoding.GetBytes() is that its 'public' overloads all require the output to be a TBytes array, which you would then have to copy into your record afterwards, eg: var patData : TPatData; SurName : String; Bytes: TBytes; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; Bytes := TEncoding.UTF8.GetBytes(SurName); Move(PBytes(Bytes)^, patData.SurName[0], Math.Min(SizeOf(patData.SurName), Length(Bytes))); ... end; The one overload of GetBytes() that would actually let you output directly into your record without using TBytes is declared as 'strict protected', which means you can't use it without involving some hacks, eg: type TEncodingHelper = class(TEncoding) public function GetBytes(const S: string; Bytes: PBytes; ByteCount: Integer): Integer; end; function TEncodingHelper.GetBytes(const S: string; Bytes: PBytes; ByteCount: Integer): Integer; begin Result := GetBytes(PChar(S), Length(S), Bytes, ByteCount); end; var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; TEncodingHelper(TEncoding.UTF8).GetBytes(S, PByte(@patData.SurName[0]), SizeOf(patData.SurName)); ... end; Or: type TEncodingHelper = class helper for TEncoding public function GetBytes(const S: string; Bytes: PByte; ByteCount: Integer): Integer; end; function TEncodingHelper.GetBytes(const S: string; Bytes: PByte; ByteCount: Integer): Integer; begin Result := Self.GetBytes(PChar(S), Length(S), Bytes, ByteCount); end; var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; TEncoding.UTF8.GetBytes(S, PByte(@patData.SurName[0]), SizeOf(patData.SurName)); ... end; The alternative would be to use System.LocaleCharsFromUnicode() instead, eg: var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; LocaleCharsFromUnicode(CP_UTF8, 0, PChar(SurName), Length(SurName), @patData.SurName[0], sizeof(patData.SurName), nil, nil); ... end; Edited June 25, 2021 by Remy Lebeau Share this post Link to post
Vandrovnik 214 Posted June 25, 2021 57 minutes ago, Remy Lebeau said: ... The one overload of GetBytes() that would actually let you output directly into your record without using TBytes is declared as 'strict protected', ... It sounds like a Muprhy's Law: the most useful methods are usualy declared as private. 1 Share this post Link to post
mikerabat 20 Posted June 28, 2021 On 6/25/2021 at 9:06 PM, Remy Lebeau said: The main problem with TEncoding.GetBytes() is that its 'public' overloads all require the output to be a TBytes array, which you would then have to copy into your record afterwards, eg: var patData : TPatData; SurName : String; Bytes: TBytes; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; Bytes := TEncoding.UTF8.GetBytes(SurName); Move(PBytes(Bytes)^, patData.SurName[0], Math.Min(SizeOf(patData.SurName), Length(Bytes))); ... end; The one overload of GetBytes() that would actually let you output directly into your record without using TBytes is declared as 'strict protected', which means you can't use it without involving some hacks, eg: type TEncodingHelper = class(TEncoding) public function GetBytes(const S: string; Bytes: PBytes; ByteCount: Integer): Integer; end; function TEncodingHelper.GetBytes(const S: string; Bytes: PBytes; ByteCount: Integer): Integer; begin Result := GetBytes(PChar(S), Length(S), Bytes, ByteCount); end; var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; TEncodingHelper(TEncoding.UTF8).GetBytes(S, PByte(@patData.SurName[0]), SizeOf(patData.SurName)); ... end; Or: type TEncodingHelper = class helper for TEncoding public function GetBytes(const S: string; Bytes: PByte; ByteCount: Integer): Integer; end; function TEncodingHelper.GetBytes(const S: string; Bytes: PByte; ByteCount: Integer): Integer; begin Result := Self.GetBytes(PChar(S), Length(S), Bytes, ByteCount); end; var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; TEncoding.UTF8.GetBytes(S, PByte(@patData.SurName[0]), SizeOf(patData.SurName)); ... end; The alternative would be to use System.LocaleCharsFromUnicode() instead, eg: var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; LocaleCharsFromUnicode(CP_UTF8, 0, PChar(SurName), Length(SurName), @patData.SurName[0], sizeof(patData.SurName), nil, nil); ... end; Thank you very much much for the great insight! Share this post Link to post
DelphiUdIT 176 Posted June 28, 2021 For a long time ago (it is not the beginning of a fairy tale ) I have been working with communication systems of various types and when I started to collide with unicode (and the various problems at the time), I started using Indy utilities for data management (even if not necessarily coming from Indy components). In particular, I was more than happy with the utilities and definitions in IdGlobal: TIdBytes, RawToBytes, BytesTo ...... (there is also BytesToString). Until now they have always taken me out of any hindrance in handling byte data. I hope I was helpful. Greetings Share this post Link to post
Remy Lebeau 1394 Posted June 28, 2021 (edited) 34 minutes ago, DelphiUdIT said: In particular, I was more than happy with the utilities and definitions in IdGlobal: TIdBytes, RawToBytes, BytesTo ...... (there is also BytesToString). In that regard, Indy's IIdTextEncoding interface has a public GetBytes() method that would be useful in this example, eg: uses ..., IdGlobal; var patData : TPatData; SurName : String; begin FillChar(@patData, sizeof(patData), 0); SurName := ...; IndyTextEncoding_UTF8.GetBytes(PChar(SurName), Length(SurName), PByte(@patData.SurName[0]), SizeOf(patData.SurName)); ... end; Edited June 28, 2021 by Remy Lebeau Share this post Link to post