Difference between revisions of "LCL Unicode Support/de"

From Free Pascal wiki
Jump to navigationJump to search
Line 198: Line 198:
 
Was Lazarus betrifft, ist die interne String-Kommunikation an den Schnittstellen "Anwendungscode <--> LCL" und "LCL <--> Widgetsets". Beide basieren nämlich auf den klassischen byte-orientierten Strings. Logisch sollten diese String konvertiert werden zu dem Code [[UTF-8]].
 
Was Lazarus betrifft, ist die interne String-Kommunikation an den Schnittstellen "Anwendungscode <--> LCL" und "LCL <--> Widgetsets". Beide basieren nämlich auf den klassischen byte-orientierten Strings. Logisch sollten diese String konvertiert werden zu dem Code [[UTF-8]].
  
=== Migration to Unicode ===
+
=== Migration zu Unicode ===
  
Most existing Lazarus use Ansi encodings, because that was the default for Gtk1 and win32 interfaces till 0.9.24. With 0.9.25 all widgetsets will use [[UTF-8]] by default (with the exception of gtk1, which only supports [[UTF-8]] when the system encoding is [[UTF-8]] and it has some limitations). So all applications that pass strings directly to the interface (be written on code or on the object inspector) will need to be converted to utf-8.
+
Die meisten existierenden Versionen von Lazarus benutzen die ANSI-Kodierung, weil dies der Standard war für die Gtk1 und win32 Interfaces bis zur Version 0.9.24. Ab 0.9.25 verwenden alle Interfaces [[UTF-8]] als Standard (mit Ausnahme von gtk1, das [[UTF-8]] nur dann unterstützt, wenn auch die Systemkodierung [[UTF-8]] ist, und selbst damit gibt es Einschränkungen). Deshalb müssen alle Anwendungen, die Zeichenketten direkt an das Interface übergeben (sei es geschrieben im Code oder im Objektinspektor) diese Zeichenketten zu UTF-8 konvertieren.
  
Currently we have various groups of widgetsets, according to the encoding:
+
Derzeit haben wir verschiedene Gruppen von Interfaces, je nach Kodierung:
  
*Interfaces that use ANSI encoding: gtk (1) on ansi systems.
+
*Interfaces die die ANSI-Kodierung verwenden: gtk (1) auf ANSI Systemen.
  
*Interfaces that use [[UTF-8]] encoding: gtk (1) on UTF-8 systems, gtk2, qt, [[fpGUI]], carbon, win32, wince, all others
+
*Interfaces die die [[UTF-8]]-Kodierung verwenden: gtk (1) auf UTF-8 Systemen, gtk2, qt, [[fpGUI]], carbon, win32, wince, alle anderen
  
Notice that gtk 1 is on both ANSI and UTF-8 groups. That´s because the encoding is controlled by an environment variable on Gtk 1.
+
Beachten Sie, dass gtk (1) sowohl in den Gruppen ANSI als auch UTF-8 aufscheint. Das ist, weil die Kodierung von einer Umgebungsvariablen unter Gtk 1 kontrolliert wird.
  
The IDE was extended to load/save/edit files of different encodings (one encoding per file). It has a built in heuristic to determine the encoding and you can change the encoding of a file at any time (Source Editor / Popup Menu / File Settings/ Encoding). So the IDE can open old files and projects and can be used to convert the encoding.
+
Die IDE wurde erweitert für das Laden/Speichern/Bearbeiten von Dateien mit unterschiedlichen Kodierungen (1 Kodierung pro Datei). Sie hat eine eingebaute Heuristik um die Kodierung zu ermitteln und Sie können die Kodierung einer Datei zu jedem Zeitpunkt ändern (Quelltexteditor / Popup-Menü / Dateieinstellungen / Kodierung). So kann die IDE alte Dateien und Projekte öffnen und auch zum Konvertieren der Kodierung benutzt werden.
  
 
== Roadmap ==
 
== Roadmap ==

Revision as of 21:55, 1 March 2011

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) 한국어 (ko) русский (ru) 中文(中国大陆)‎ (zh_CN) 中文(台灣)‎ (zh_TW)

Einleitung

Mit der Version 0.9.25 unterstützt Lazarus Unicode auf allen Plattformen außer auf Gtk 1. Diese Seite liefert Informationen für Anwender, die Strategie der Entwickler und eine Beschreibung der Konzepte und deren Anwendungsdetails.

Anweisungen für Benutzer

In Unicode-Interfaces - das anzumerken ist wichtig - ist nicht alles in Unicode. Die Free Pascal Laufzeitbibliothek (RTL) und die Free Pascal FCL-Bibliothek sind ANSI. Es liegt in der Verantwortung des Entwicklers zu wissen, welche Kodierung die Zeichenketten verwenden, und eine saubere Umwandlung durchzuführen zwischen Bibliotheken mit unterschiedlichen Kodierungen.

Normalerweise erfolgt eine Kodierung pro Bibliothek (d. h. eine dynamische Bibliothek 'dll' oder ein Lazarus-Package). Jede Bibliothek erwartet 1 einheitliche Art von Kodierung, also üblicherweise entweder Unicode (UTF-8 für Lazarus) oder ANSI (das bedeutet die Systemkodierung, und kann utf-8 sein oder nicht). Die RTL und die FCL von FPC 2.4 erwarten ANSI-Zeichenketten. FPC 2.5.x derzeit auch.

Sie können zwischen Unicode und ANSI konvertieren mittels der Funktionen UTF8ToAnsi und AnsiToUTF8 aus der Unit 'System' oder mittels UTF8ToSys und SysToUTF8 aus der Unit 'FileUtil'. Die beiden letzteren sind eleganter, stellen aber mehr Code in Ihr Programm.

Beispiele:

Angenommen Sie haben eine Zeichenkette aus einem TEdit und wollen diese an eine Routine aus der RTL übergeben:

<delphi>var

 MyString: string; // utf-8 encoded

begin

 MyString := MyTEdit.Text;
 SomeRTLRoutine(UTF8ToAnsi(MyString));

end;</delphi>

Und in der umgekehrten Richtung:

<delphi>var

 MyString: string; // ansi encoded

begin

 MyString := SomeRTLRoutine;
 MyTEdit.Text := AnsiToUTF8(MyString);

end;</delphi>

Wichtig: UTF8ToAnsi gibt eine leere Zeichenkette zurück, wenn der UTF8-String ungültioge Zeichen enthält.

Wichtig: AnsiToUTF8 und UTF8ToAnsi brauchen einen Widestring-Manager unter Linux, BSD und Mac OS X. Sie können die Funktionen SysToUTF8 und UTF8ToSys (aus der Unit FileUtil) einsetzen oder einen Widestring-Manager indem Sie 'cwstring' als eine der ersten Units zum uses-Abschnitt in Ihrem Programm hinzufügen.


Der Umgang mit UTF8 Zeichenketten und Zeichen

Wenn Sie die Zeichen einer UTF8-Zeichenkette durchlaufen wollen, gibt es dafür zwei unterschiedliche Arten:

  • durchlaufen Sie die Bytes - ist nützlich zum Suchen eines Teilstrings oder wenn Sie nur die ASCII-Zeichen eines UTF8-Strings betrachten wollen. Zum Beispiel beim Parsen einer xml-Datei.
  • durchlaufen Sie die Zeichen - ist nützlich für graphische Komponenten wie Synedit. Zum Beispiel wenn Sie wissen wollen, welches das dritte am Bildschirm dargestellte Zeichen ist.

Suchen eines Teilstrings

Wegen der besonderen Natur von UTF8 können Sie einfach die normalen Stringfunktionen verwenden:

<Delphi>procedure Where(SearchFor, aText: string); var

 BytePos: LongInt;
 CharacterPos: LongInt;

begin

 BytePos:=Pos(SearchFor,aText);
 CharacterPos:=UTF8Length(PChar(aText),BytePos-1);
 writeln('The substring "',SearchFor,'" is in the text "',aText,'"',
   ' at byte position ',BytePos,' and at character position ',CharacterPos);

end;</Delphi>


Zugriff auf einen UTF8-String als Array

Ein Array besteht aus aus Elementen gleicher Größe. Ein UTF8-Zeichen kann aber 1 bis 4 Bytes haben. Deshalb müssen Sie den UTF8-String konvertieren, entweder in ein Array aus Unicode-Werten (longwords) oder in ein Array aus PChar mit einem Zeiger auf jedes Zeichen.

Durchlaufen von Zeichen mittels UTF8CharacterToUnicode

Das Folgende demonstriert wie Sie die 32bit Unicode-Werte von Zeichen in einem UTF8-String durchlaufen:

<Delphi>uses LCLProc; ... procedure IterateUTF8Characters(const AnUTF8String: string); var

 p: PChar;
 unicode: Cardinal;
 CharLen: integer;

begin

 p:=PChar(AnUTF8String);
 repeat
   unicode:=UTF8CharacterToUnicode(p,CharLen);
   writeln('Unicode=',unicode);
   inc(p,CharLen);
 until (CharLen=0) or (unicode=0);

end;</Delphi>

Der Umgang mit Verzeichnis- und Dateinamen

Die Steuerelemente und Funktionen in Lazarus erwarten Dateinamen und Verzeichnisnamen in UTF-8 Kodierung, aber die RTL benutzt ANSI-Strings für Verzeichnisse und Dateinamen.

Betrachten Sie beispielsweise eine Schaltfläche, die die Eigenschaft 'Directory' einer TFileListBox auf das aktuelle Verzeichnis setzt. Die RTL-Funktion GetCurrentDir ist ANSI, und nicht Unicode, deswegen muss man konvertieren:

<delphi>procedure TForm1.Button1Click(Sender: TObject); begin

 FileListBox1.Directory:=SysToUTF8(GetCurrentDir);
 // or use the functions from the FileUtil unit
 FileListBox1.Directory:=GetCurrentDirUTF8;

end;</delphi>

Die Unit 'FileUtil' definiert allgemeine Dateifunktionen mit UTF-8 Strings:

<Delphi>// Basisfunktionen ähnlich zur RTL, aber arbeiten mit UTF-8 anstelle der // Systemkodierung

// AnsiToUTF8 und UTF8ToAnsi brauchen einen Widestring-Manager unter Linux, BSD, Mac OS X, // aber normalerweise nehmen diese Betriebssysteme UTF-8 als Systemkodierung, dann ist // ein Widestring-Manager nicht nötig. function NeedRTLAnsi: boolean;// wahr, wenn die Systemkodierung nicht UTF-8 ist procedure SetNeedRTLAnsi(NewValue: boolean); function UTF8ToSys(const s: string): string;// wie UTF8ToAnsi, aber unabhängig von einem Widestring-Manager function SysToUTF8(const s: string): string;// wie AnsiToUTF8, aber unabhängig von einem Widestring-Manager

// Dateioperationen function FileExistsUTF8(const Filename: string): boolean; function FileAgeUTF8(const FileName: string): Longint; function DirectoryExistsUTF8(const Directory: string): Boolean; function ExpandFileNameUTF8(const FileName: string): string; function ExpandUNCFileNameUTF8(const FileName: string): string; {$IFNDEF VER2_2_0} function ExtractShortPathNameUTF8(Const FileName : String) : String; {$ENDIF} function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec): Longint; function FindNextUTF8(var Rslt: TSearchRec): Longint; procedure FindCloseUTF8(var F: TSearchrec); function FileSetDateUTF8(const FileName: String; Age: Longint): Longint; function FileGetAttrUTF8(const FileName: String): Longint; function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint; function DeleteFileUTF8(const FileName: String): Boolean; function RenameFileUTF8(const OldName, NewName: String): Boolean; function FileSearchUTF8(const Name, DirList : String): String; function FileIsReadOnlyUTF8(const FileName: String): Boolean; function GetCurrentDirUTF8: String; function SetCurrentDirUTF8(const NewDir: String): Boolean; function CreateDirUTF8(const NewDir: String): Boolean; function RemoveDirUTF8(const Dir: String): Boolean; function ForceDirectoriesUTF8(const Dir: string): Boolean;

// Umgebung function ParamStrUTF8(Param: Integer): string; function GetEnvironmentStringUTF8(Index : Integer): String; function GetEnvironmentVariableUTF8(const EnvVar: String): String; function GetAppConfigDirUTF8(Global: Boolean): string;</Delphi>

Mac OS X

Die Dateifunktionen der Unit 'FileUtil' berücksichtigen eine Besonderheit von Mac OS X: OS X normalisiert Dateiname. Zum Beispiel kann der Dateiname 'ä.txt' in Unicode mit zwei unterschiedlichen Sequenzen (#$C3#$A4 und 'a'#$CC#$88) kodiert werden. Unter Linux und BSD können Sie einen Dateinamen mit beiden Kodierungen erzeugen. OS X konvertiert automatisch den a-Umlaut in die drei Byte Sequenz. Das bedeutet:

<Delphi>if Filename1=Filename2 then ... // reicht nicht aus unter OS X if AnsiCompareFileName(Filename1,Filename2)=0 then ... // reicht nicht aus unter fpc 2.2.2, nicht einmal mit 'cwstring' if CompareFilenames(Filename1,Filename2)=0 then ... // dies funktioniert immer (Unit FileUtil oder FileProcs)</Delphi>

UTF8 und Quelltextdateien - die fehlende BOM

Wenn Sie mit Lazarus Quelltextdateien erzeugen und einige Nicht-ASCII-Zeichen eintippen, dann wird diese Datei mit UTF( gespeichert. Es verwendet keine BOM (Byte-Ordnungs-Markierung). Sie können die Kodierung ändern mittels eines Rechtsklicks im Quelltexteditor / Dateieinstellungen / Zeichenkodierung. Der Grund für die fehlende BOM ist die Art, wie FPC ANSI-Strings behandelt. Für die Kompatibilität benutzt die LCL ANSI-Strings und für die Portabilität benutzt die LCL UTF8.

Anmerkung: Einige MS Windows Texteditoren verarbeiten diese Dateien mit der System-Codepage und zeigen dann ungültige Zeichen an. Fügen Sie keine BOM hinzu. Wenn Sie eine BOM einfügen, müssen Sie alle Stringzuweisungen ändern.

Zum Beispiel:

<Delphi>Button1.Caption := 'Über';</Delphi>

Wenn keine BOM vorliegt (und kein Codepage-Parameter übergeben wurde), dann behandelt der Compiler die Zeichenkette wie systemkodiert und kopiert jedes Byte unkonvertiert in die Zeichenkette. Genau so erwartet die LCL die Zeichenketten.

<Delphi>// Quelltextdatei gespeichert als UTF ohne BOM if FileExists('Über.txt') then ; // falsch, weil 'FileExists' Systemkodierung erwartet if FileExistsUTF8('Über.txt') then ; // richtig</Delphi>

Widestrings und Ansistrings

Wenn Sie Ansistrings an Widestrings übergeben, müssen Sie die Kodierung konvertieren.

<Delphi>var

 w: widestring;

begin

 w:='Über'; // falsch, weil der FPC die System-Codepage zu UTF16 konvertiert
 w:=UTF8ToUTF16('Über'); // richtig
 Button1.Caption:=UTF16ToUTF8(w);

end;</Delphi>

Quelltextdatei mit UTF8 BOM

Wenn Sie in einer Unit zahlreiche Konvertierungen von Widestrings durchführen, könnte der Code dadurch lesbarer werden, dass Sie den Quelltext als UTF8 mit BOM abspeichern. Der Compiler erlaubt pro Unit eine Kodierung.


Ostasiatische Sprachen unter Windows

Die Vorgabeschriftart (Tahoma) für Benutzerinterface-Steuerelemente unter Windows XP kann verschiedene Sprachen korrekt anzeigen, darunter Arabisch, Russisch und westliche Sprachen, aber nicht ostasiatische Sprachen, wie Chinesisch, Japanisch oder Koreanisch. Gehen Sie zur Systemsteuerung, wählen Sie 'Region und Sprache' aus, klicken Sie auf die Sprachformate und installieren Sie das East Asia Language Pack. Dadurch wird die Vorgabeschriftart ab jetzt diese Sprachen korrekt anzeigen. Natürlich haben Windows XP Versionen, die für diese Sprachen lokalisiert wurden, dieses Sprachpaket bereits installiert. Genauere Instruktionen gibt es hier.

Implementierungsrichtlinien

Voraussetzungen

Die Vision von Lazarus ist: "Write once, compile everywhere." Das bedeutet im Idealfall, eine Applikation, die Unicode eingeschaltet hat, hat nur einen Source-Code, der für alle Plattformen gültig ist, ohne irgendwelche konditionalen Definitionen.

Der "Interface" Teil der LCL sollte Unicode für die Zielplattform bereitstellen, die Zielplattform sollte Unicode selber unterstützen, ohne den Anwendungsprogrammierer mit Details zu belästigen.

Was Lazarus betrifft, ist die interne String-Kommunikation an den Schnittstellen "Anwendungscode <--> LCL" und "LCL <--> Widgetsets". Beide basieren nämlich auf den klassischen byte-orientierten Strings. Logisch sollten diese String konvertiert werden zu dem Code UTF-8.

Migration zu Unicode

Die meisten existierenden Versionen von Lazarus benutzen die ANSI-Kodierung, weil dies der Standard war für die Gtk1 und win32 Interfaces bis zur Version 0.9.24. Ab 0.9.25 verwenden alle Interfaces UTF-8 als Standard (mit Ausnahme von gtk1, das UTF-8 nur dann unterstützt, wenn auch die Systemkodierung UTF-8 ist, und selbst damit gibt es Einschränkungen). Deshalb müssen alle Anwendungen, die Zeichenketten direkt an das Interface übergeben (sei es geschrieben im Code oder im Objektinspektor) diese Zeichenketten zu UTF-8 konvertieren.

Derzeit haben wir verschiedene Gruppen von Interfaces, je nach Kodierung:

  • Interfaces die die ANSI-Kodierung verwenden: gtk (1) auf ANSI Systemen.
  • Interfaces die die UTF-8-Kodierung verwenden: gtk (1) auf UTF-8 Systemen, gtk2, qt, fpGUI, carbon, win32, wince, alle anderen

Beachten Sie, dass gtk (1) sowohl in den Gruppen ANSI als auch UTF-8 aufscheint. Das ist, weil die Kodierung von einer Umgebungsvariablen unter Gtk 1 kontrolliert wird.

Die IDE wurde erweitert für das Laden/Speichern/Bearbeiten von Dateien mit unterschiedlichen Kodierungen (1 Kodierung pro Datei). Sie hat eine eingebaute Heuristik um die Kodierung zu ermitteln und Sie können die Kodierung einer Datei zu jedem Zeitpunkt ändern (Quelltexteditor / Popup-Menü / Dateieinstellungen / Kodierung). So kann die IDE alte Dateien und Projekte öffnen und auch zum Konvertieren der Kodierung benutzt werden.

Roadmap

Da wir nunmehr Richtlinien haben, ist es an der Zeit eine "Roadmap" auszuarbeiten und diese Realität werden zu lassen. Vor diesem Hintergrund wurde der nachfolgend dargestellte Plan aufgestellt. Dieser Plan teilt die Aufgaben in zwei Gruppen ein. Eine Gruppe für primäre, eine für sekundäre Aufgaben.

Alle primären Aufgaben müssen vollständig umgesetzt sein, bevor wir davon sprechen können, dass Lazarus Unicode-fähig ist. Diesen primären Aufgaben gilt daher unser Hauptaugenmerk. An Ihnen werden wir bevorzugt arbeiten.

Sekundäre Aufgaben sind zwar wünschenswert, werden aber erst umgesetzt, wenn sich für die Aufgabe jemand findet, der sie umsetzt.


Primäre Aufgaben

Ziel: Win32 Widgetset unterstützt UTF-8

Anmerkungen: On this step we will target all 32-bits Windows versions at the same time. All code produced on this effort will be isolated from the current win32 interface by IFDEFs, to avoid introducing bugs on this primary interface. After the transition time, the IFDEFs will be removed and only the Unicode code will remain.

Status: vollständig implementiert


Aktualisieren der GTK2 Tastaturfunktionen, damit sie mit UTF-8 funktionieren

Anmerkungen:

Status: fast vollendet. Some pre-editing features of the gtk2 are not yet supported in custom controls. I don't know, which language needs them.


Make sure the Lazarus IDE runs correctly with Win32 Unicode widgetset and supports UTF-8

Anmerkungen:

Status: vollendet. Mit Ausnahme der Zeichentabelle ("Character-Map"), sie zeigt weiterhin lediglich 255 Zeichen. Aber alle modernen Betriebssysteme bieten ohnehin schöne Unicode-Zeichentabellen.


Make sure the Lazarus IDE runs correctly with Gtk 2 widgetset and supports UTF-8

Anmerkungen:

Status: vollendet. Es gibt noch GTK2 intf bugs, aber diese haben nichts mit UTF-8 zu tun.

Sekundäre Aufgaben

Update Windows CE widgetset so it uses UTF-8

Anmerkungen: String-Umwandlungsroutinen konzentrieren sich auf die winceproc.pp file. Hier sind noch viele Tests notwendig.

Status: nicht implementiert


Aktualisieren der GTK1 Tastaturfunktionen, damit sie mit UTF-8 funktionieren

Anmerkungen:

Status: vollendet


RTL in synedit vervollständigen

Anmerkungen: RTL meint von rechts nach links (right to left) wie es z.B. im Arabischen verwendet wird

Status: nicht implementiert.

Unicode essentials

Unicode standard maps integers from 0 to 10FFFF(h) to characters. Each such mapping is called a code point. In other words, Unicode characters are in principle defined for code points from U+000000 to U+10FFFF (0 to 1 114 111).

There are three schemes for representing Unicode code points as unique byte sequences. These schemes are called Unicode transformation formats: UTF-8, UTF-16 and UTF-32. The conversions between all of them are possible. Here are their basic properties:

                           UTF-8 UTF-16 UTF-32
Smallest code point [hex] 000000 000000 000000
Largest code point  [hex] 10FFFF 10FFFF 10FFFF
Code unit size [bits]          8     16     32
Minimal bytes/character        1      2      4
Maximal bytes/character        4      4      4

UTF-8 has several important and useful properties: It is interpreted as a sequence of bytes, so that the concept of lo- and hi-order byte does not exist. Unicode characters U+0000 to U+007F (ASCII) are encoded simply as bytes 00h to 7Fh (ASCII compatibility). This means that files and strings which contain only 7-bit ASCII characters have the same encoding under both ASCII and UTF-8. All characters >U+007F are encoded as a sequence of several bytes, each of which has the two most significant bits set. No byte sequence of one character is contained within a longer byte sequence of another character. This allows easy search for substrings. The first byte of a multibyte sequence that represents a non-ASCII character is always in the range C0h to FDh and it indicates how many bytes follow for this character. All further bytes in a multibyte sequence are in the range 80h to BFh. This allows easy resynchronization and robustness.

UTF-16 has the following most important properties: It uses a single 16-bit word to encode characters from U+0000 to U+d7ff, and a pair of 16-bit words to encode any of the remaining Unicode characters.

Finally, any Unicode character can be represented as a single 32-bit unit in UTF-32.

Für weitere Informationen siehe: Unicode FAQ - Basic questions, Unicode FAQ - UTF-8, UTF-16, UTF-32 & BOM, Wikipedia: UTF-8 [1]

Lazarus component library architecture essentials

Die LCL besteht aus zwei Teilen:

  1. A target platform independent part, which implements a class hierarchy analogous to Delphi VCL;
  2. "Interfaces" - a part that implements the interface to APIs of each target platform.

The communication between the two parts is done by an abstract class TWidgetset. Each widgetset is implemented by its own class derived from TWidgetset.

The GTK 1 widgetset is the oldest. In this widgetset the string encoding is determined by the LANG environment variable, which is usually a iso The ISO-8859-n group of single byte encodings. Recently (as of Mandriva 2007, for example), many distributions have being shipping Gtk 1 configured for UTF-8. Our Gtk 1 interface lacks proper support for UTF-8 on the keyboard handling routines, so this is a big problem, that increases the need for Lazarus to implement cross-platform Unicode support.

Gtk2 widgetset only works with UTF-8 encoding and supports UTF-8 completely.

As of Lazarus 0.9.28 the Windows and Windows CE interfaces support Unicode fully.

Qt interface is prepared for UTF-8. Qt itself uses UTF-16 as native encoding, but the lazarus interface for Qt converts from UTF-8 to UTF-16.

For more, see: Internals of the LCL

Unicode-enabling the win32 interface

Richtlinien

First, and most importantly, all Unicode patches for the Win32 interface must be enclosed by IFDEF WindowsUnicodeSupport, to avoid breaking the existing ANSI interface. After this stabilizes, all ifdefs will be removed and only the Unicode part will remain. At this moment all existing programs that use ANSI characters will need migration to Unicode.

Windows platforms <=Win9x are based on ISO code page standards and only partially support Unicode. Windows platforms starting with WinNT and Windows CE fully support Unicode. Win 9x and NT offer two parallel sets of API functions: the old ANSI enabled *A and the new, Unicode enabled *W. *W functions accept wide strings, i.e. UTF-16 encoded strings, as parameters. Windows CE only uses Wide API functions.

Wide functions present on Windows 9x

Some Wide API functions are present on Windows 9x. Here is a list of such functions: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mslu/winprog/other_existing_unicode_support.asp

Conversion example:

  GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption),
Length(ButtonCaption), TextSize);

Becomes:

  {$ifdef WindowsUnicodeSupport}
    GetTextExtentPoint32W(hdcNewBitmap, PWideChar(Utf8Decode(ButtonCaption)), Length(WideCaption), TextSize);
  {$else}
    GetTextExtentPoint32(hdcNewBitmap, LPSTR(ButtonCaption), Length(ButtonCaption), TextSize);
  {$endif}

Funktionen die Ansi und Wide Versionen benötigen

First Conversion example:

<delphi> function TGDIWindow.GetTitle: String; var

l: Integer;

begin

  l := Windows.GetWindowTextLength(Handle);
  SetLength(Result, l);
  Windows.GetWindowText(Handle, @Result[1], l);

end; </delphi>

wird:

<delphi> function TGDIWindow.GetTitle: String; var

l: Integer;
AnsiBuffer: string;
WideBuffer: WideString;

begin

{$ifdef WindowsUnicodeSupport}

if UnicodeEnabledOS then
begin
  l := Windows.GetWindowTextLengthW(Handle);
  SetLength(WideBuffer, l);
  l := Windows.GetWindowTextW(Handle, @WideBuffer[1], l);
  SetLength(WideBuffer, l);
  Result := Utf8Encode(WideBuffer);
end
else
begin
  l := Windows.GetWindowTextLength(Handle);
  SetLength(AnsiBuffer, l);
  l := Windows.GetWindowText(Handle, @AnsiBuffer[1], l);
  SetLength(AnsiBuffer, l);
  Result := AnsiToUtf8(AnsiBuffer);
end;

{$else}

  l := Windows.GetWindowTextLength(Handle);
  SetLength(Result, l);
  Windows.GetWindowText(Handle, @Result[1], l);

{$endif}

end;

</delphi>

Roadmap

Was bereits mit Unicode funktionieren sollte:

  • TForm, TButton, TLabel
  • die meisten Controls
  • Menüs
  • LCLIntf.ExtTextOut and most other text related winapis
  • TStrings based controls. Examples: TComboBox, TListBox, etc
  • SynEdit shows and can input UTF-8 characters correctly
  • Setting/Getting unicode strings to/from the ClipBoard
  • Setting the Application Title in the project options to (for example) 'Minha Aplicação'.
  • Double clicking words with non-ascii chars in the editor to select them

Bekannte Probleme bei der Unicode Unterstützung:

  • SynEdit unterstützt nicht RTL (right to left, von rechts nach links)
  • Is OpenFileDialogCallBack tested with selection large numbers of files?
    • Is this problem unicode specific? I think it's a generic problem. --Sekelsenmat 13:40, 14 February 2008 (CET)
      • Maybe. I know I tested it with large number of files before the Unicode version was added. If it is a generic problem, then the the non-Unicode version got broken, when the Unicode version was added. Vincent 21:45, 15 February 2008 (CET)
  • class function TWin32WSSelectDirectoryDialog.CreateHandle: Title, FileName and InitialDir should be made Unicode aware.

Possible problems with Unicode support

Based on a code review, the following needs to be tested, because the code doesn't seem to be Unicode aware:

  • class procedure TWin32WSCustomComboBox.SetText
  • TWin32WSCustomTrayIcon.Show: ATrayIcon.Hint is not Unicode aware
  • TWin32WidgetSet.MessageBox doesn't call MessageBoxW.
  • TWin32WidgetSet.TextOut: Is Windows.TextOut supported on windows 9X?
  • MessageBox buttons don't show unicode correctly when they are translated. Tested on the IDE. Could be a problem on the IDE however.
    • Note: I couldn't reproduce using the portuguese translation --Sekelsenmat 22:20, 12 January 2008 (CET)
  • (list of unconfirmed problems, if confirmed can be moved to the list above)


Screenshots

Lazarus Unicode Test.png

Siehe auch

  • UTF-8 - Beschreibung von UTF-8 Zeichenketten