String, AnsiString in Delphi 2007, in Delphi 2009. Differences and Migration Implications

CodeGear Delphi 2007, 2009
Official Unicode support was added in Delphi 2009 with code name Tiburón.

In Delphi Versions <= 2007, string was an alias for AnsiString (a single-byte character string type).
In Delphi Versions >= 2009, this changed, and string became an alias for UnicodeString (a multi-byte, UTF-16 character string type), while AnsiString remained available as a type for 8-bit character data.

This change was a major shift to include full Unicode support and has significant implications for code written in Delphi <= 2007 that is being migrated to Delphi 2009 or later.

Key Differences and Migration Implications

String Alias:
  • Delphi 2007 and earlier: String = AnsiString. The data was 8-bit and its interpretation (code page) was generally linked to the operating system's regional settings.
  • Delphi 2009 and later: String = UnicodeString. The data is 16-bit (WideChar), typically using UTF-16 encoding, allowing for a broad range of characters.
Character Types:
  • Delphi 2007: Char = AnsiChar (8-bit).
  • Delphi 2009: Char = WideChar (16-bit).
Type   | Delphi 2007 | Delphi 2009, XE
-------+-------------+----------------
byte   | byte        | byte (no change)
String | AnsiString  | UnicodeString
Char   | AnsiChar    | WideChar
PChar  | PAnsiChar   | PWideChar

Data Handling:
  • Direct assignments between AnsiString and the new UnicodeString (string) in Delphi 2009 involve implicit conversions, which can cause to performance issues or, more importantly, data loss if not handled carefully. The compiler will often issue warnings for these conversions.
  • The internal structure of AnsiString itself changed slightly between versions (e.g., in Delphi 2009, it stores a code page number, which was not present in Delphi 2007's AnsiString), making sharing strings between DLLs compiled with different versions problematic.

Migration pieces of Advice

To migrate code that uses strings between these versions, you generally have preferred approaches:
  1. Explicitly Ansi-fy the Code (Short-term fix): Replace all instances of the generic string, Char, and PChar with their explicit 8-bit equivalents: AnsiString, AnsiChar and PAnsiChar. This retains the old behavior but means your application will not leverage Unicode natively and will still encounter conversion overhead when interacting with the rest of the Unicode VCL/RTL in Delphi 2009.
  2. Resort to Unicode: Update your code to use the native UnicodeString (string) type throughout your application. Use AnsiString only at the boundaries where you interact with legacy data, files, or external APIs that require ANSI encoding (e.g., when saving or loading data from an older database). Use functions like TEncoding.GetString to properly decode data.
  3. The correction isn’t simple recompilation, but to audit every PChar, every SizeOf(Char) assumption, and every place where raw bytes to a file or socket expecting ANSI. // Delphi <= 2007 code — assumes 1 byte per char, breaks silently under Unicode procedure TrimBuffer(var Buf: array of Char; MaxLen: Integer); var P: PChar; begin P := @Buf[0]; Inc(P, MaxLen); // wrong stride Char is 2 bytes P^ := #0; end;
  4. Compiler directives and conditional code
    The Version constants are not intuitive but they may lead to mistakes:
    {$IFDEF VER150} // Delphi 7 {$IFDEF VER185} // Delphi 2007 Win32 has VER180 & VER185 {$IFDEF VER200} // Delphi 2009 Tiburon {$IFDEF VER210} // Delphi 2010 Weaver
    Prefer to use Compiler Version than Version constants
    ...
    If the codebase has already passed one migration, it likely has {$IFDEF} blocks keyed to old version constants. Don’t delete these blindly — audit each one with attention.

The ANSI function to Ansi-fy, syntax for string


Ansi-fy Wide Char, Unicode Units
const C = '...'; const C: AnsiString = '...';
CompareText AnsiCompareText SysUtils; AnsiStrings
CompareStr AnsiCompareStr SysUtils; AnsiStrings
FindWindow FindWindowA FindWindowW
(in Delphi Versions >= 2009 the same as FindWindowW)
GetDiskFreeSpace GetDiskFreeSpaceA GetDiskFreeSpace
(in Delphi Versions >= 2009 calls GetDiskFreeSpaceW)
Windows
GetTempPath GetTempPathA GetTempPath
(in Delphi Versions >= 2009 calls GetTempPathW)
Windows
ShellExecute ShellExecuteA ShellExecuteW
(in Delphi Versions >= 2009 the same as ShellExecute)
ShellApi
ShellExecute ShellExecuteA ShellExecuteW
(in Delphi Versions >= 2009 the same as ShellExecute)
ShellApi
ShellExecuteInfo ShellExecuteInfoA ShellExecuteInfoW
(in Delphi Versions >= 2009 the same as ShellExecuteInfo)
SHGetPathFromIDList SHGetPathFromIDListA SHGetPathFromIDList
(in Delphi Versions >= 2009 calls SHGetPathFromIDListW)
ShlObj
StrAlloc AnsiStrAlloc in Delphi Versions >= 2009 StrAlloc calls WideStrAlloc SysUtils

Delphi 2009 has got the unit AnsiStrings.pas appeared in ..\source\Win32\rtl\common.
This article will not be complete, some text was removed intentionally. If you are unable to apply this, please contact for paid consultation.
Данная статья не будет полной, часть текста была удалена намеренно. Если вам не удалось применить, обращайтесь за платной консультацией.

No comments:

Post a Comment