AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Multilingual mit DLLs u. Unicode - so richtig?
Thema durchsuchen
Ansicht
Themen-Optionen

Multilingual mit DLLs u. Unicode - so richtig?

Ein Thema von TheMiller · begonnen am 31. Aug 2011 · letzter Beitrag vom 3. Sep 2011
Antwort Antwort
Seite 1 von 2  1 2      
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#1

Multilingual mit DLLs u. Unicode - so richtig?

  Alt 31. Aug 2011, 20:35
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:
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.
Haupt-Programm
Delphi-Quellcode:
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.
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.

Danke im Voraus
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#2

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 31. Aug 2011, 21:16
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 MSDN-Library durchsuchenLoadString mit dem Handle der DLL.


PS:
Zitat:
Delphi-Quellcode:
    BUTTON1_C:
      result:='Einloggen';
    BUTTON1_H:
      result:='Hier klicken, um einzuloggen';
Besser über globale Konstanten lösen, denn die loklen Konstanten sind begrenzt (ab einer gewissen Anzahl kann der Compiler nimmer)

Delphi-Quellcode:
const // oder gar resourcestring statt const
  sLogin = 'Einloggen'

...

BUTTON1_C:
      result:=sLogin;
Ein array of string, als globale Konstante, ginge auch.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (31. Aug 2011 um 21:20 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#3

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 31. Aug 2011, 22:37
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!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#4

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 31. Aug 2011, 23:15
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: string): String;
var
  s: String; // garnicht verwendet?
begin
  len:=comp(PWideChar(compName), nil, 0);
  try
    GetMem(Buffer, len*2+2);
    len:=comp(PWideChar(compName), Buffer, len*2+2);
    result:=String(Buffer);
  finally
    FreeMem(Buffer);
  end;
end;
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;
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (31. Aug 2011 um 23:28 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#5

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 1. Sep 2011, 14:08
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!
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#6

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 1. Sep 2011, 15:57
"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:
  TLang = function (str: LongInt): UnicodeString;
  TComp = function (const comp: UnicodeString): UnicodeString;
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, ...)


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 Copy , Delete oder + )
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu ( 2. Sep 2011 um 13:48 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#7

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 1. Sep 2011, 19:13
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
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#8

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 2. Sep 2011, 13:41
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
Angehängte Dateien
Dateityp: zip DLL - Mehrsprachig.zip (123,4 KB, 13x aufgerufen)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.071 Beiträge
 
Delphi 12 Athens
 
#9

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 2. Sep 2011, 13:52
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)
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#10

AW: Multilingual mit DLLs u. Unicode - so richtig?

  Alt 3. Sep 2011, 00:08
Ok, vielen Dank für deine Hilfe.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:35 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz