![]() |
Multilingual mit DLLs u. Unicode - so richtig?
Hallo,
ich habe jetzt ein System für Mehrsprachenunterstützung fertig, welches auch für Unicode geeignet sein sollte. Ich würde gerne wissen, ob das alles so richtig/in Ordnung ist. Ich weiß, dass es gnugetext etc gibt, ich mag aber nicht noch mehr Abhängigkeiten im Programm haben. Anmerkungen: Ist angelehnt an Luckies Artikel StringDLLs und an Unicode angepasst (bzw. sollte so sein). Auch habe ich beide Projekte mit FastMM auf Leaks getestet. Hinweis: - Beide Projekte haben eine LanguageID-Unit eingebunden, die die Konstanten entählt. Hier mal der komplette Quelltext: Von der DLL
Delphi-Quellcode:
Haupt-Programm
library de;
uses SysUtils, LanguageIDs; {$R *.res} function getText(str: Integer): PWideChar; begin case str of BUTTON1_C: result:='Einloggen'; BUTTON1_H: result:='Hier klicken, um einzuloggen'; end; end; function getCompName(str: PWideChar): PWideChar; begin if (str = 'Button1') then result:='Bitte hier nicht drücken'; end; //Ersetzt später Captions und Hints nach Komponentenname function _compName(comp: PWideChar; Buffer: PChar; lenBuffer: Integer): Integer; stdcall; begin if Assigned(Buffer) then StrLCopy(Buffer, PWideChar(getCompName(comp)), lenBuffer); result := length(getCompName(comp)); end; //Ruft einfach nur Text ab. function _lang(str: Integer; Buffer: PWideChar; lenBuffer: Integer): Integer; stdcall; begin if Assigned(Buffer) then StrLCopy(Buffer, PWideChar(getText(str)), lenBuffer); result := length(getText(str)); end; exports _lang, _compName; begin end.
Delphi-Quellcode:
Also. Fehler treten keine auf und es funktioniert eigentlich alles wunderbar. Die Frage ist nur, ob das wirklich so richtig ist. Würde das gerne vorher wissen, bevor ich weitermache. Vielleicht hilft dieser Beitrag ja dem Einen oder Anderen.
type
TForm1 = class(TForm) Button1: TButton; Label1: TLabel; Edit1: TEdit; Memo1: TMemo; procedure FormCreate(Sender: TObject); private { Private-Deklarationen } public function _l(strName: Integer): String; function _cl(compName: String): String; end; TLang = function (str: Integer; Buffer: PChar; lenBuffer: Integer): Integer; stdcall; TComp = function (comp: PChar; Buffer: PChar; lenBuffer: Integer): Integer; stdcall; var Form1: TForm1; hLib: THandle; s: String; Lang: TLang; Comp: TComp; len: Integer; Buffer: PChar; implementation {$R *.dfm} {****** Holt den Text aus der DLL **********} function TForm1._l(strName: Integer): String; begin len:=lang(strName, nil, 0); try // Hier Unicode-Anpassung: jeweils 2 Byte pro Char + 2 Bytes für Stopp: \0 GetMem(Buffer, len*2+2); // Hier Unicode-Anpassung: jeweils 2 Byte pro Char + 2 Bytes für Stopp: \0 len:=lang(strName, Buffer, len*2+2); result:=String(Buffer); finally FreeMem(Buffer); end; end; {****** Holt einen Componentennamen aus der DLL **********} function TForm1._cl(compName: string): String; var s: String; begin len:=comp(PWideChar(compName), nil, 0); try // Hier Unicode-Anpassung: jeweils 2 Byte pro Char + 2 Bytes für Stopp: \0 GetMem(Buffer, len*2+2); // Hier Unicode-Anpassung: jeweils 2 Byte pro Char + 2 Bytes für Stopp: \0 len:=comp(PWideChar(compName), Buffer, len*2+2); result:=String(Buffer); finally // Speicher wieder freigeben FreeMem(Buffer); end; end; procedure TForm1.FormCreate(Sender: TObject); var i: Integer; begin hLib := LoadLibrary('de.dll'); // Beim Laden ist ein Fehler aufgetreten if hLib = 0 then begin Str(GetLastError, s); ShowMessage(SysErrorMessage(GetLastError)); exit; end; //Funktion laden @lang := GetProcAddress(hLib, '_lang'); //Beim Laden der Funktion ist ein Fehler aufgetreten. if (not Assigned(lang)) then begin Str(GetLastError, s); ShowMessage(SysErrorMessage(GetLastError)); exit; end; //Funktion laden @comp := GetProcAddress(hLib, '_compName'); //Beim Laden der Funktion ist ein Fehler aufgetreten. if (not Assigned(comp)) then begin Str(GetLastError, s); ShowMessage(SysErrorMessage(GetLastError)); exit; end; //Spezielle Komponententexte ersetzen. for i:=0 to Form1.ComponentCount-1 do begin if (Form1.Components[i].ClassName = 'TButton') then begin (Form1.Components[i] as TButton).Caption:=_cl(Form1.Components[i].Name); end; end; FreeLibrary(hlib); end; end. Danke im Voraus |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Binde die Unit SimpleShareMem in deine EXE und DLLs ein. (als Erstes in den DPRs)
Und schon kannst du Strings direkt übergeben. Ich wäre hier aber eher auf Resource-DLLs übergegangen. - die Texte als Resourcen in die DLLs eingebunden - und dann läd die EXE jeweils die gewünschte DLL und nutzt ![]() PS: Zitat:
Delphi-Quellcode:
Ein array of string, als globale Konstante, ginge auch.
const // oder gar resourcestring statt const
sLogin = 'Einloggen' ... BUTTON1_C: result:=sLogin; |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Hallo,
danke für deine ausführliche Antwort. Ich habe mich bewusst gegen einen Speicherverwalter entschieden, da ich nichts zusätzliches mit ausliefern möchte. Und das Tutorial von Luckie kannte ich schon lange und habe es auch oft erfolgreich umgesetzt. Was die DLL als solche angeht: Mit Ressourcen-DLLs habe ich noch nie gearbeitet - da müsste ich mich erstmal umschauen. Also gehe ich davon aus, dass du mir von meiner Methode abraten würdest, oder? Ich habe auch späterhin noch bemerkt, dass FastMM doch meckert. Und zwar immer nach FreeMem mit der Meldung "corrupt block during a Freemem-Operation" (ich habe leider die Meldung gerade nicht parat). Danke für eure/deine Hilfe! |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Solange DLL und EXE Delphi geschrieben sind, brauchst du nichts Zusätzliches.
Wobei andere Sprachen auch den Speichermanager der EXE mit benutzen könnten, da hier die EXE ja zuerst geladen wird. Bei ShareMem mußte man noch eine weitere DLL mitgeben (die mit dem globalen Speichermanager ... BorlndMM.dll oder so) Der FastMM, in deinem Delphi, ist aber so ausgelegt, daß er von sich aus den Speicher sharen kann, welches die besagte Unit für dich erledigt. > Die EXE/DLL welche hierbei zuerst geladen wird, stellt ihren MM den Anderen zur Verfügung. [add] Ach ja ... *aufpfotenhau* Was suchen z.B. len und buffer in den globalen? Du kombinierst String mit PWideChar :!: String + PChar + SizeOf(Char) WideString|UnicodeString + PWideChar + 2|SizeOf(WideChar) AnsiString + PansiChar + 1|SizeOf(AnsiChar) und untereinander niemals vermischen! PS: Zitat:
Delphi-Quellcode:
function TForm1._cl(compName: UnicodeString): UnicodeString;
begin SetLength(Result, comp(PWideChar(compName), nil, 0)); comp(PWideChar(compName), PWideChar(Result), (Length(Result) + 1) * SizeOf(WideChar)); end; |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Danke für deine Hilfe. Das mit den globalen Vars und dem nicht verwendeten s kam vom Testen. Das mit dem WideString etc ist mir dann auch aufgefallen und an UnicodeString habe ich garnicht gedacht....
Also verstehe ich dich richtig, dass ich die o.g. Unit einbinden soll, und dann einfach die Strings übergeben soll, WENN ich schon die Version mit der DLL durchziehen möchte? Ich würde - warum auch immer, ich weiß es selbst nicht - gerne bei den DLLs bleiben. Finde ich irgendwie übersichtlicher und mit Ressourcen habe ich noch nicht viel gearbeitet. Was spricht gegen DLLs? Danke! |
AW: Multilingual mit DLLs u. Unicode - so richtig?
"Sollen" nicht unbedingt, aber es würde bestimmt Einiges vereinfachen.
- du kannst direkt UnicodeString als parameter angeben (entspricht seit 2009 ja dem string, also keinerlei Konvertierungen im Betrieb) - und du kannst die Vorzüge der Strings nutzen ... keine "unsicheren" Speicheropertationen und PWideChar-hinundherkopiere
Delphi-Quellcode:
UnicodeString anstatt String, da man solche Interfaces besser mit statischen Typen deklariert ... nicht daß sich das Interface urplötzlich verändert, wenn man auf ein anderes Delphi umsteigt oder für ein anderes System kompiliert (32 Bit und 64 Bit, ANSI und Unicode, ...)
TLang = function (str: LongInt): UnicodeString;
TComp = function (const comp: UnicodeString): UnicodeString; Würde am Ende auch ein bissl der Performance zu Gute kommen, wenn da öfters mal was ausgelesen würde. Bzw. die UnicodeStrings verbrauchen keinerlei Arbeitsspeicher, da sie, über einen Spezialfall der Referenzzählung als Konstante im "Speicher" liegen. Die Stringdaten verbleiben in der Datasektion (oder wo auch immer die liegen) und es werden immer nur Zeiger darauf weitergegeben. (solange man den String nicht manipuliert, ala
Delphi-Quellcode:
,
Copy
Delphi-Quellcode:
oder
Delete
Delphi-Quellcode:
)
+
|
AW: Multilingual mit DLLs u. Unicode - so richtig?
Hi!
Super Erklärung - hat auch alles soweit super funktioniert. Ist ja wirklich so, als würde man Strings zwischen zwei Formularen austauschen. Aber eine Frage habe ich noch... Habe ich jetzt noch die Möglichkeit, nach MemoryLeaks über FastMM zu suchen? Eigentlich ja nicht, weil sich FastMM ja nicht mehr laden kann, weil ja schon ein anderer MemoryManager installiert ist. Hast du da zufälligerweise auch noch einen Tipp für mich? Vielen Dank |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Liste der Anhänge anzeigen (Anzahl: 1)
Moin!
Habe jetzt mal soweit alles fertig. Würde es euch aber gerne nochmal zeigen. Zum einen, dass ihr mir noch Vorschläge geben könnt und zum anderen hilft es vielleicht ja jemand anderen noch. Es ist jetzt so, dass beim Sprachenwechsel alle gewünschten Objekttypen automatisch ersetzt werden. D.h., ich trage in die Änderungsliste den Typ TButton ein und alle Buttons auf der Form werden übersetzt. Vielleicht ist das auch zu kompliziert und ihr habt noch andere Ideen. Es würde mich freuen, wenn ich nochmal drüberschaut. Es ist nicht viel Quelltext, wollte aber dennoch nicht alles in den Beitrag posten - sonst muss man wieder Kilometer runterscrollen. Danke |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Das Ding nutzt ja den FastMM, welcher im Delphi integriert ist ... du mußt nur noch dort die Speicherprüfung aktivieren, wo er geladen ist.
Je nach dem, was zuerst geladen wird, da wird er verwendet. - statisch geladene DLLs/BPLs werden vo der EXE geladen - dynamisch (manuell ... LoadLibrary) geladene DLLs/BPLs werden nach der aufrufenden EXE/DLL geladen. ("nochmal drüberschaut" ... nach Feierabend dann) |
AW: Multilingual mit DLLs u. Unicode - so richtig?
Ok, vielen Dank für deine Hilfe.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:24 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