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.
- Delphi 2007: Char = AnsiChar (8-bit).
- Delphi 2009: Char = WideChar (16-bit).
Type | Delphi 2007 | Delphi 2009, XE -------+-------------+---------------- 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:- 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.
- 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.GetStringto properly decode data. // 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;
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.-
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 CompilerVersion >= 20.0} // Delphi 2009 and higher ... {$ELSE} ... {$IFEND}
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 | |
const
C ='...'; |
const
C: AnsiString ='...'; |
| CompareText | AnsiCompareText |
| CompareStr | AnsiCompareStr |
Delphi 2007 and Delphi 2009+ difference in string types. Migration
To be continued
