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.
The change was a major shift to include full Unicode support and has significant implications for the legacy code written in Delphi <= 2007 that is being migrated to Delphi 2009 or later.
Key Differences and Migration Implications
In Delphi 2007 and older (ANSI) Length() returns number of bytes, in Delphi 2009 and newer (Unicode) returns number of characters (elements).
- 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 / Function | Delphi 7, 2007 | Delphi 2009, XE |
| byte | byte | byte (no change) |
| String | AnsiString | UnicodeString |
| Char | AnsiChar | WideChar |
| PChar | PAnsiChar | PWideChar |
| SizeOf(Char) | 1 byte | 2 bytes |
Data Handling:
- Direct assignments between AnsiString and the new UnicodeString 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 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. - 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; - Compiler directives and conditional code if code must support both old and new Delphi versions simultaneously.
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 WeaverAnother way to use the
Prefer to useUNICODEdirective:
{$IFDEF UNICODE} // Delphi 2009+ logic {$ELSE} // Legacy Delphi logic {$ENDIF}CompilerVersionthan 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.
Use code with caution! - Compile and watch Fix Warnings: Pay close attention to "Implicit string cast" warnings. They highlight where the compiler is silently converting between ANSI and Unicode strings, which can cause data loss or unplanned behavior.
- Character Buffer Allocations with
SetLengthandGetMem
If code allocates memory based on the assumption that 1 character equals 1 byte, it will allocate only half the required memory in Delphi 2009+, leading to buffer overflows.Lengthreturns the number of elements in the string or in an array.Lengthfor the strings with 8 bit element types (ANSI, UTF-8) gives the number of bytes since the number of bytes is the same as the number of elements, but theLengthfor the strings with 16 bit elements (UTF-16) is half the number of bytes because each element has 2 bytes.
Wrong Code:
GetMem(Buffer, Length(MyString));// Allocates half the needed bytes!
Correct Code
GetMem(Buffer, Length(MyString) * SizeOf(Char)); - File I/O (BlockRead / BlockWrite & TStream) in reading or writing strings directly to files using raw byte streams will now write 2 bytes per character, breaking backwards compatibility with old file formats.
Fix, if you need to save text files in traditional ANSI/ASCII format, explicitly useAnsiStringor passTEncoding.ANSI(e.g.,StringList.LoadFromFile('file.txt', Tencoding.ANSI)) toTStringList.SaveToFileorTStringList.LoadFromFile.var LegacyStr: AnsiString; begin LegacyStr := AnsiString(MyUnicodeString); Stream.Write(LegacyStr[1], Length(LegacyStr)); end; - Windows API Calls brings surprises out of (
PCharcasting)
Delphi automatically maps Windows API functions to their Unicode (W) variants instead of ANSI (A) variants.
For example:SetWindowTextcalls theSetWindowTextW.
IfPAnsiCharis explicitly being passed to an API that now expectsPWideChar, the compiler will give error. Types must be updated toPCharto let Delphi handle it natively, or explicitly callSetWindowTextAif the ANSI is used. CharInSetappeared in Delphi 2009 to avoid warning: "WideChar reduced to byte char in set expressions". Sets in Delphi can contain a maximum of 256 elements.
Implementation of the CharInSet function analogue for older versions of Delphi 6-2007:function CharInSet(AChar: Char; ASet: TSysCharSet): Boolean; begin Result := AChar in ASet; end;- Pointer math must be reviewed: if a
PCharpointerInc(P)is incremented, it now jumps by 2 bytes instead of 1. If there is manual byte-level parsing, the pointer type must be changed toPByteorPAnsiChar. - If old code used string or
AnsiStringas binary Data buffers to load raw binary data, encrypted data, or file streams, this will now break because the runtime will try to parse or convert invalid UTF-16 surrogate pairs.
Change the variable type from string toRawByteStringorTBytes(an array of bytes) to fix and completely bypass Unicode conversion logic. - Ensure that database drivers and components are updated to versions that support Unicode data types (
TWideStringFieldinstead ofTStringFieldif storing non-ASCII data).
Delphi 2009 has got the unit
AnsiStrings.pas appeared in ..\source\Win32\rtl\common.The ANSI function to Ansi-fy
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