The Wiert Corner – irregular stream of stuff

Jeroen W. Pluimers on .NET, C#, Delphi, databases, and personal interests

  • My badges

  • Twitter Updates

  • My Flickr Stream

  • Pages

  • All categories

  • Enter your email address to subscribe to this blog and receive notifications of new posts by email.

    Join 2,092 other followers

Delphi Mobile (NEXTGEN) compiler: the risk of a changed TSymbolName; unsupported data types means unsupported RTTI as well

Posted by jpluimers on 2013/09/05

The NEXTGEN family of Delphi compilers for the Mobile platforms changed quite a bit of things.

Most of it has been covered by various blogs posts. A non exhaustive list of ones I liked:

Those articles do not contain two things I had’t found about yet though that are important when you do RTTI using NEXTGEN in Delphi XE4:

1. The TSymbolName changed from a types string[255] to Byte

Though TSymbolName is still documented as being a ShortString (classic Turto Pascal style non reference counted single byte string of maximum 255 characters with a length byte as very first (zeroth?) byte), it is not:

{$IFDEF NEXTGEN}
TSymbolName = Byte;
{$ELSE NEXTGEN}
TSymbolNameBase = string[255];
TSymbolName = type TSymbolNameBase;
{$ENDIF NEXTGEN}

view raw
TSymbolName.pas
hosted with ❤ by GitHub

This creates all kinds of havoc, especially when you use System.SysUtils.Format or Exceptions to format readable RTTI output like this: as the %s will break when a Byte is passed.

function EnumerationName(const Value: Integer; const Info: PTypeInfo): string;
//
begin
if Info^.Kind <> tkEnumeration then
raise Exception.CreateFmt('Info %s is not an enumerated type', [Info^.Name]);
//
end;

view raw
EnumerationName.pas
hosted with ❤ by GitHub

So I worked around it using the SetString and Utf8ToUnicode methods: a NEXTGEN compatible GetShortStringString method.

function GetShortStringString(const ShortStringPointer: PByte): string;
var
ShortStringLength: Byte;
FirstShortStringCharacter: MarshaledAString;
ConvertedLength: Cardinal;
UnicodeCharacters: array[Byte] of Char; // cannot be more than 255 characters, reserve 1 character for terminating null
begin
if not Assigned(ShortStringPointer) then
Result := ''
else
begin
ShortStringLength := ShortStringPointer^;
if ShortStringLength = 0 then
Result := ''
else
begin
FirstShortStringCharacter := MarshaledAString(ShortStringPointer+1);
ConvertedLength := UTF8ToUnicode(
UnicodeCharacters,
Length(UnicodeCharacters),
FirstShortStringCharacter,
ShortStringLength
);
// UTF8ToUnicode will always include the null terminator character in the Result:
ConvertedLength := ConvertedLength-1;
SetString(Result, UnicodeCharacters, ConvertedLength);
end;
end;
end;

Now the exception is raised like this:

function EnumerationName(const Value: Integer; const Info: PTypeInfo): string;
//
begin
if Info^.Kind <> tkEnumeration then
raise Exception.CreateFmt('Info %s is not an enumerated type', [GetTypeInfoName(Info)]);
//
end;

view raw
EnumerationName.pas
hosted with ❤ by GitHub

2. Despite the absence of some types in the NEXTGEN compiler, the TTypeKind declaration in the TypInfo unit has not changed:

The TTypeKind is still declared to be this:

//NEXTGEN does declare this in the TypInfo unit:
TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray, tkUString,
tkClassRef, tkPointer, tkProcedure);

view raw
TTypeKind.pas
hosted with ❤ by GitHub

But in fact these TTypeKind values are not supported in NEXTGEN:

  • tkWString: Identifies a WideString (wide string without reference counting) type.
  • tkLString: Identifies an AnsiString (single byte string with reference counting) type.
  • tkChar: Identifies a AnsiChar single-byte character type.
  • tkString: Identifies a ShortString short string type or subtype.

That lead me to this code snippet:

const
UnsupportedTypeKinds: TTypeKinds = [
{$IFDEF NEXTGEN}
tkWString,
tkLString,
tkChar,
tkString
{$ENDIF NEXTGEN}
];

–jeroen

2 Responses to “Delphi Mobile (NEXTGEN) compiler: the risk of a changed TSymbolName; unsupported data types means unsupported RTTI as well”

  1. Regarding the symbol name…
    Have a look at TTypeInfoFieldAccessor in unit TypeInfo, it does exactly what you do with your code. And you have already GetTypeName declared as function there.

Leave a Reply to jpluimers Cancel reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

 
%d bloggers like this: