![]() |
Unicode und WideChar API-Funktionen
Hallo ihr :).
Aus bestimmten Gründen versuche ich mich derzeit an Free Pascal. Leider blieb ich sehr schnell an der Thematik Unicode und WideChar API-Funktionen hängen, und auch die vielfältigen Angaben im Internet helfen mir nicht dabei, die Sache für mich zufriedenstellend - mit möglichst wenigen Änderungen am Code - zu lösen. Gegeben sei folgender, auf das Wesentliche reduzierte Beispiel-Code:
Delphi-Quellcode:
Funktioniert einwandfrei. Aber es wird die ANSI-Variante der API-Funktion (ExpandEnvironmentStringsA) importiert. Nun wollte ich die Sache unicodefähig machen, also dachte ich mir, setze ich
program project1;
{$MODE DELPHI} uses Classes, SysUtils, CustApp, Windows; type TMyApplication = class(TCustomApplication) private FStr: string; [...] end; procedure TMyApplication.DoRun; begin [...] SetLength(FStr, 32768); SetLength(FStr, ExpandEnvironmentStrings(PChar('%SystemRoot%\System32'), @FStr[1], Length(FStr))-1); WriteLn(FStr); ReadLn; end;
Delphi-Quellcode:
. Leider Fehlanzeige:
{$MODE DELPHIUNICODE}
Code:
(Der Error wird an der Stelle des Calls der API-Funktion gemeldet.) Soweit ich das bisher verstandenn habe, liegt das daran, dass nur die eigene Unit in Bezug auf Strings und PChars umdefiniert wird, die von FPC mitgebrachten Units aber nicht. Es wird also weiterhin ExpandEnvironmentStringsA benutzt.
Compile Project, Mode: Debug, Target: project1.exe: Exit code 1, Errors: 1, Warnings: 2
project1.lpr(36,14) Warning: Implicit string type conversion from "AnsiString" to "UnicodeString" project1.lpr(38,44) Warning: Implicit string type conversion with potential data loss from "UnicodeString" to "AnsiString" project1.lpr(52,50) Error: Incompatible type for arg no. 1: Got "PWideChar", expected "PChar" Wie kann man das lösen bzw. was ist der empfohlene Weg, dass der Code sowohl in Delphi als auch FPC verwendbar ist? Es kann ja nicht Sinn der Sache sein, den Code mit expliziten Aufrufen der Wide-Funktionen und - bei umfangreicherem Code - zahllosen IFDEFs zuzupflastern... Grüße Dalai |
AW: Unicode und WideChar API-Funktionen
Dann mach es doch explizit als Unicode?
Delphi-Quellcode:
private
FStr: UnicodeString; // oder WideString SetLength(FStr, ExpandEnvironmentStringsW(PWideChar('%SystemRoot%\System32'), @FStr[1], Length(FStr))-1); Als ich zuletzt in FreePascal / Lazarus schautet, dann war da nichts mit "Unicode". Oft wurde aber mit UTF-8 in einem "AnsiString" gearbeitet. Windows benutzt aber UTF-16 bzw. früher UCS-2. |
AW: Unicode und WideChar API-Funktionen
Zitat:
Zitat:
Grüße Dalai |
AW: Unicode und WideChar API-Funktionen
Das Eingangsbeispiel ist wohl etwas zu knapp ausgefallen ist. Hier ein etwas längeres, das die Problematik (hoffentlich) besser verdeutlicht:
Delphi-Quellcode:
Die markierten Zeilen werfen folgende Warnungen:
program project1;
{$MODE DELPHI} uses Classes, SysUtils, CustApp, Windows, IniFiles; type TMyApplication = class(TCustomApplication) private FStr: WideString; FValue: WideString; FFileName: WideString; [...] end; procedure TMyApplication.DoRun; begin [...] FFileName:= 'C:\irgendeine.ini'; FIni:= TIniFile.Create(FFileName); // <-- try FValue:= FIni.ReadString('foo', 'bar', 'blub'); // <-- SetLength(FStr, 32768); SetLength(FStr, ExpandEnvironmentStringsW(PWideChar(FValue), @FStr[1], Length(FStr))-1); finally FIni.Free; end; WriteLn(FStr); ReadLn; end;
Code:
Das heißt, selbst wenn ich explizit WideString nutze, renne ich gegen eine andere Wand. Das muss doch besser gehen.
Compile Project, Mode: Debug, Target: project1.exe: Success, Warnings: 2
project1.lpr(55,35) Warning: Implicit string type conversion with potential data loss from "WideString" to "AnsiString" project1.lpr(57,18) Warning: Implicit string type conversion from "AnsiString" to "WideString" Grüße Dalai |
AW: Unicode und WideChar API-Funktionen
Bei implizitem Cast wird gemeckert,
aber bei expliziten Casts nicht:
Delphi-Quellcode:
Das Zweite wäre kein Problem, da ja Klein zu Groß und es somit rein passen würde.
FIni:= TIniFile.Create(AnsiString(FFileName));
try FValue:= WideString(FIni.ReadString('foo', 'bar', 'blub')); Beim Ersten, sieht es anders aus ... also problematisch, wenn Unicodezeichen im Dateiname vorkommen würden, welche außerhalb des jeweiligen ANSI-Zeichenraumes liegen. ABER, ist das wirklich AnsiString, oder nicht vielleicht doch z.B. UTF-8 String? Ich dachte der FPC hätte in seiner RTL schon "Unicode" und eben nicht ANSI. Wenn z.B. ein UTF8-String, dann wäre es schon unpraktisch, wenn FPC keine automatische Konvertierung zwischen den String-Typen bietet. Wie genau sind denn TIniFile.Create und TIniFile.ReadString "wirklich" deklariert? ![]() Wenn tatsächlich "String" und String = AnsiString, dann ... Wo bitte hat FPC denn seine unicode-fähige INI-Klasse versteckt? |
AW: Unicode und WideChar API-Funktionen
Es gibt bei Lazarus eine Includedatei für Ansi und eine für Unicode für den Zugriff auf die API. Ich habe aber keine Ahnung, wie man die Unicodeversion aktiviert. Der Schalter in den Projekteinstellungen scheint es nicht zu sein.
Ich habe aktuell Lazarus nicht installiert und kann nicht nachschauen. Ich hatte aber mal gesucht. Soweit ich das sehe, wird intern zwar UTF-8 verwendet, aber statt dieses dann umgewandelt in UTF-16 automatisch an die Unicode-API zu füttern, wird offenbar (mit den Standarddirektiven) fest Ansi verwendet. Das war bei Delphi 7, an das ja auch die Oberfläche von Lazarus angelehnt ist, aber auch nicht anders. Insofern... |
AW: Unicode und WideChar API-Funktionen
Bitte entschuldigt die längere Funkstille meinerseits. Die vergangenen Tage hab ich damit verbracht, einen Teil meiner Units für Free Pascal umzuschreiben. Leider sind die Ergebnisse alles andere als zufriedenstellend. Die Sache ist so undurchsichtig und stellenweise widersprüchlich, dass bei mir einige Fragen aufgetaucht sind und ich die Hoffnung habe, dass jemand sie eindeutig beantworten kann.
Grüße Dalai |
AW: Unicode und WideChar API-Funktionen
Also, wenn man mit Pointer rumpfuscht, anstatt PWideChar zu benutzen ... wenn irgendwann der Typ nicht mehr stimmt, dann beschwere dich bitte nicht, wenn der Compiler dir nichts sagen wird.
Zitat:
Ich rate mal. Die Letzte? (mit dem Result:=) Und nun überleg mal was du dort machst. :wink:
Delphi-Quellcode:
Aber wenn du sowie so kein Unicode haben willst, dann
SetLength(Buffer, GetModuleFileNameW(Module, nil, 0));
GetModuleFileNameW(Module, PWideChar(Buffer), Length(Buffer)+1);
Delphi-Quellcode:
Im Delphi war String früher AnsiString und GetModuleFileName ein Alias für GetModuleFileNameA, bzw. PChar ein PAnsiChar,
function GetModuleName(Module: HMODULE): string; // oder eben UnicodeString und nachfolgend PWideChar
begin SetLength(Result, GetModuleFileName(Module, nil, 0)); GetModuleFileName(Module, PChar(Result), Length(Result)+1); end; und nun ist String ein UnicodeString und GetModuleFileName ein Alias für GetModuleFileNameW mit PWideChar. Eventuell gibt es sowas mit dem genannten
Delphi-Quellcode:
auch für Lazarus?
{$ModeSwitch UnicodeStrings}
Delphi-Quellcode:
Mit Cast oder implitzt kommt erstmal das Gleiche bei raus, also vom Inhalt ... nur das Letzteres eben keine Cast-Warnung wirft.
Result := Buffer;
Result := String(Buffer); Ich weiß nicht wie Lazarus/FPC das macht. Vermutlich wie Delphi früher. Da wurde die Codepage des Types verwendet, also von der Variable. Delphi seit 2009, hat die Codepage zusätzlich im String gespeichert und Verwendet vorzugsweise Dieses. (auch wenn man mal z.B. UTF-8 in einem "AnsiString" drin hat und nicht den UTF8String benutzte) Zitat:
vorher irgendwo
Delphi-Quellcode:
{$ModeSwitch UnicodeStrings}
und später dann mit
Delphi-Quellcode:
testen.
{$IFDEF UseUTF16}
|
AW: Unicode und WideChar API-Funktionen
![]() oder ein anderer ansatz, {$modeswitch m_default_unicodestring} |
AW: Unicode und WideChar API-Funktionen
Zitat:
Zitat:
Zitat:
Es sei noch ergänzt, dass ich die Funktion nur aus Neugier und Verwunderung ins eigene Projekt kopiert habe. Beim Lesen der Funktion tauchten sofort die Fragen auf, warum Pointer statt PWideChar benutzt wird und warum ohne Cast/Konvertierung ein UnicodeString an String zugewiesen wird. Ich wollte herausfinden, ob bzgl. des (Unicode)Strings eine Warnung auftaucht oder nicht. Sie taucht auf, und nun würde ich gern wissen, ob die berechtigt ist oder nicht. Zitat:
Zitat:
Delphi-Quellcode:
, aber das Ergebnis ist dasselbe wie mit
{$Mode DelphiUnicode}
Delphi-Quellcode:
. Dabei hab ich festgestellt, dass die Funktionen/Klassen aus der FPC RTL eben nicht alle mit UnicodeString verfügbar sind. Das ist ja der Grund für den Thread hier und meine Fragen.
{$ModeSwitch UnicodeStrings}
Zitat:
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
Und im Code dieser Unit wird dann an bestimmten Stellen
// For testing the UTF16 version.
{$IF DEFINED(FPC) and DEFINED(UseUTF16)} {$ModeSwitch UnicodeStrings} // Sets also FPC_UNICODESTRINGS. {$ENDIF} {$IF DEFINED(FPC_UNICODESTRINGS) or not DEFINED(FPC)} {$DEFINE ReallyUseUTF16} // FPC with UTF-16 or Delphi {$ENDIF}
Delphi-Quellcode:
benutzt.
{$IFDEF ReallyUseUTF16
Grüße Dalai |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:04 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz