Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Erläuterung was "native unicode string" ist? (https://www.delphipraxis.net/161517-erlaeuterung-native-unicode-string-ist.html)

torud 7. Jul 2011 09:31

Delphi-Version: 7

Erläuterung was "native unicode string" ist?
 
Hallo Wissende,

ich habe ein Riesen-Problem. Ich ziehe mir aus einer XML-Datei Teamnamen. Die XML-Datei ist in UTF-8 formatiert. Zum Anzeigen im Programm benutze ich die TntControls. Da sieht das alles super aus. Nun sende ich diese Inhalte (WideStrings und TWideStringlist) via TCP-Protokoll an eine Empfangende Software, die mir die inhalte visualisiert.

Leider wird dabei aus dem gesendeten String: Widzew Łódź
Das hier: Widzew Łó

Es fehlen also Zeichen. Es kann nicht an der Schriftart liegen, da die Anbieter der Rendering-software auch einen Designer haben. Wenn ich dort den String reinkopiere, wird der Inhalt korrekt gerendert. Es muss also an der Übermittlung irgendwo haken.

Der Programmierer, den ich daraufhin angeschrieben habe, teilte mir folgendes mit:
"Please double check that the value passed to Tk5 has proper value.
It should be native unicode string, not UTF-8."

Ich bin jetzt natürlich etwas ratlos und würde mich über ein paar Ratschläge freuen.

jaenicke 7. Jul 2011 09:43

AW: Erläuterung was "native unicode string" ist?
 
Für den Zweck würde sich zwar eine neuere Delphiversion (2009+) als die bei dir angegebene Version Delphi 7 wegen voller Unicodeunterstützung besser eignen, aber nichtsdestotrotz sollten WideStrings auch in Delphi 7 bereits funktionieren, da sie vom Betriebssystem verwaltet werden.

WideStrings sind auch nicht UTF-8, sondern benutzen tatsächlich die 2 Byte pro Zeichen.

Kannst du vielleicht einmal exakt die Bytes posten wie du sie via TCP versendest? Und wie verschickst du diese?

torud 7. Jul 2011 09:59

AW: Erläuterung was "native unicode string" ist?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo Sebastian,

meine Angaben waren wohl nicht ganz korrekt.

Also die Strings aus dem XML visualisiere ich als WideStrings z.B. in einem TTntEdit
Das Sammeln der Daten geschieht über TWideStrinlists aus der Unit JclUnicode.

Dann übergebe ich die Liste an eine selbst geschriebene Komponente, die die Daten dann an ein ComObjekt (GSTK5Lib_TLB) übergibt. Das Ding connected sich zum Renderer. Der Fehler liegt wohl definitiv auf meiner Seite, nur weiss ich noch nicht genau wo. Ich könnte den Code der Komponente und das Sender der Daten hier Posten, aber die Komponente selbst hat 900 Zeilen Code.

Der Programmierer hat mir noch einen Link zu den Delphi-Fundamentals geschickt.

Hier aber mal die XML-Datei, aus der ich auslese.
Was mich eben auch verwirrt, ist der Umstand, dass die Sonderzeichen nicht grundsätzlich NICHT funktionieren, sondern es nur partiell zu Problemen kommt.

Daniela.S 7. Jul 2011 10:56

AW: Erläuterung was "native unicode string" ist?
 
Unicode Zeichen im UTF-8 Format benötigen zwischen 1-4 Byte. Womöglich werden einige Bytes nicht mitgeschickt weil die Längenberechnung des Strings nicht stimmt. SizeOf(...) wäre hier ganz falsch.

UTF-16 braucht 2-4 Bytes, die Länge muss auch hier berechnet werden. Kann passieren, wird aber oft vernachlässigt. Ich nehme wohl an, dass er die Daten in diesem Format erwartet, denn es würde WideString entsprechen.

Dann gibt's noch UTF-32, das hat immer 4 Byte.

jaenicke 7. Jul 2011 11:40

AW: Erläuterung was "native unicode string" ist?
 
Zitat:

Zitat von torud (Beitrag 1110501)
Dann übergebe ich die Liste an eine selbst geschriebene Komponente, die die Daten dann an ein ComObjekt (GSTK5Lib_TLB) übergibt.

Dann ist genau das der entscheidende Code. Wie sehen die Deklaration und der Code an genau dieser Stelle aus (in der Objekt-TLB-Unit und dein Aufruf)?

Wenn du dort einen Haltepunkt setzt: Sind die Daten dort noch korrekt?

torud 7. Jul 2011 13:45

AW: Erläuterung was "native unicode string" ist?
 
ich checks mal und melde mich dann wieder.
danke erstmal soweit.

torud 8. Jul 2011 12:20

AW: Erläuterung was "native unicode string" ist?
 
Also ich habs jetzt mal überprüft.

Der Aufruf in der TLB_Unit sieht so aus:
Delphi-Quellcode:
procedure set_(const address: WideString; const attrName: WideString; value: OleVariant); safecall;
Sprich ich übergebe den Namen des Objektes, dann den Typ (text) und dann den Inhalt des Objektes.

Der Aufruf dieser Procedure in meiner Komponente läuft so ab:
Delphi-Quellcode:
      //AUSSCHNITT
      //hier werden die texte aus der TWideStringlist einzeln übergeben
      for i := 0 to TextString.Count - 1 do
        loc_AkiTitle.set_(TextString.Names[i],'Text',TextString.Values[TextString.Names[i]]);

      //hier werden die logos aus der TWideStringlist einzeln übergeben
      for i := 0 to LogoString.Count - 1 do
        loc_AkiTitle.set_(LogoString.Names[i],'FileName',LogoString.Values[LogoString.Names[i]]);

      //hier werden zusätzliche Eigenschaften aus einer TWideStringlist einzeln übergeben
      for i := 0 to PropList.Count - 1 do
        loc_AkiTitle.set_(PropList.Items[i].str_Name,PropList.Items[i].str_Type,PropList.Items[i].str_Value);
TextString, LogoString sind vom Typ her TWideStringlist

Also sollte das doch so passen.
Oder?

Obwohl, ich sehe gerade, dass der eigentliche Inhalt vom Typ her value: OleVariant ist. Kann hier die Ursache für das Problem liegen?
Inhalte, die ich aus Edits hole, kommen ausschließlich von TTntEdits.
Die TWideStringlist habe ich mir fertig von der JCL geborgt.

Ich hoffe, dass das eventuell etwas hilft, mir bei meinem Problem zu helfen?

jaenicke 8. Jul 2011 14:17

AW: Erläuterung was "native unicode string" ist?
 
Hmm, testweise könntest du TextString.Values[TextString.Names[i]] usw. einmal in WideString Variablen zwischenspeichern bevor du es übergibst.

torud 9. Jul 2011 08:30

AW: Erläuterung was "native unicode string" ist?
 
Nur, um kurz mal sicher zu gehen.

Du meinst, ich soll mir die 2 übermittelten Werte jeweils in einer WideString-Variablen zwischenspeichern und dann der TLB-Funktion übergeben?

Wäre dabei was anders?
Oder soll ich mir das dann loggen?
Was ist der Hintergrund Deines Vorschlags?

FredlFesl 9. Jul 2011 08:47

AW: Erläuterung was "native unicode string" ist?
 
So nebenbei würde ich auch 'ValueFromIndex' verwenden. Tut zwar nix zur Sache, ist aber schneller und übersichtlicher.
Delphi-Quellcode:
for i := 0 to TextString.Count - 1 do
   loc_AkiTitle.set_(TextString.Names[i],'Text',TextString.ValueFromIndex[i]);

RWarnecke 9. Jul 2011 08:50

AW: Erläuterung was "native unicode string" ist?
 
Zitat:

Zitat von torud (Beitrag 1110898)
Nur, um kurz mal sicher zu gehen.

Du meinst, ich soll mir die 2 übermittelten Werte jeweils in einer WideString-Variablen zwischenspeichern und dann der TLB-Funktion übergeben?

Wäre dabei was anders?
Oder soll ich mir das dann loggen?
Was ist der Hintergrund Deines Vorschlags?

Wenn ich Sebastian richtig verstanden habe, will er damit erreichen, wie Dein übergebener Wert im Widestring aussieht. Du setzt an der Stelle wieder einen Haltepunkt und dann schaust Du Dir die temporären Werte an, ob Sie gleich sind mit der Quelle oder nicht.

jaenicke 9. Jul 2011 11:11

AW: Erläuterung was "native unicode string" ist?
 
Nicht nur deshalb. Dadurch wird sichergestellt, dass ein neuer WideString als direkte WideString Variable an den OleVariant Wert übergeben wird.

Eigentlich sollte das keinen Unterschied machen. Aber man weiß ja nie...

torud 11. Jul 2011 10:05

AW: Erläuterung was "native unicode string" ist?
 
Zitat:

Zitat von FredlFesl (Beitrag 1110899)
So nebenbei würde ich auch 'ValueFromIndex' verwenden. Tut zwar nix zur Sache, ist aber schneller und übersichtlicher.
Delphi-Quellcode:
for i := 0 to TextString.Count - 1 do
   loc_AkiTitle.set_(TextString.Names[i],'Text',TextString.ValueFromIndex[i]);

TextString.ValueFromIndex[i] gibt es nicht in einer TWideStringlist;
aber trotzdem danke für den Optimierungsversuch.

torud 11. Jul 2011 10:37

AW: Erläuterung was "native unicode string" ist?
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von jaenicke (Beitrag 1110905)
Nicht nur deshalb. Dadurch wird sichergestellt, dass ein neuer WideString als direkte WideString Variable an den OleVariant Wert übergeben wird.

Eigentlich sollte das keinen Unterschied machen. Aber man weiß ja nie...

Also ich habe testhalber mal den Code so angepasst:

Delphi-Quellcode:
var
  i : integer;
  sName, sValue : WideString;
begin
...
      for i := 0 to TextString.Count - 1 do begin
        sName := TextString.Names[i];
        sValue := TextString.Values[TextString.Names[i]];
        //loc_AkiTitle.set_(TextString.Names[i],'Text',TextString.Values[TextString.Names[i]]);
        loc_AkiTitle.set_(sName,'Text',sValue);
      end;
Habe mir einen Haltpunkt gesetzt und bin mit der Maus über die Variablen gefahren. Scheinbar sind die Hints NICHT UniCode, da ich viele ? zu sehen bekam.

Damit Ihr mal seht, wie sich das Problem visuell darstellt, hier mal ein Bildanhang. Links seht Ihr ein TTnTMemo, welches ja UniCode kann.
Komisch ist hier schon in der Ansicht, dass in Zeile
4 statt subline der Code etwas komisch aussieht. Die 1. wird rechts im Preview auch nicht angezeigt
5 bei Cracovia das hier steht -> Cracoⅵa und in der Anzeige nur Cracoa

Bin kurz vorm verzeifeln.

torud 11. Jul 2011 10:56

AW: Erläuterung was "native unicode string" ist?
 
Ich habe nun mal die WideStringList gespeichert.
Sieht leider nicht gut aus. Das Problem ist also definitiv auf meiner Seite:


header=EKSTRAKLASA
subl㏌e=⒈ kolejka
team_a=Cracoⅵa Kraków
team_b=Legia Warszawa

Das sieht nicht wirklich nach UniCode aus. Muss ich vielleicht bei den TNT-Controls irgendwas am Charset einstellen oder der WideStringlist noch eine spezielle Eigenschaft verpassen?

jaenicke 11. Jul 2011 12:15

AW: Erläuterung was "native unicode string" ist?
 
Zitat:

Zitat von torud (Beitrag 1111109)
Muss ich vielleicht bei den TNT-Controls irgendwas am Charset einstellen oder der WideStringlist noch eine spezielle Eigenschaft verpassen?

Dabei kann ich dir leider nicht helfen, da ich Unicode nur in aktuellen Delphiversionen ohne Verrenkungen benutze. Damals in Delphi 7 habe ich nur AnsiStrings benutzt.

Das Problem ist wie du bemerkt hast natürlich, dass die Delphi IDE durch die fehlende Unicodeunterstützung auch keine Unicodestrings beim Debuggen auswerten kann...
Was du versuchen kannst um definitiv festzustellen, ob die Strings falsch sind, ist, dass du diese einfach einmal ausgibst:
Delphi-Quellcode:
MessageBoxW(0, PWideChar(sName), 'Test: sName', 0);
MessageBoxW(0, PWideChar(sValue), 'Test: sValue', 0);
Das sollte auch mit Delphi 7 problemlos funktionieren.

torud 11. Jul 2011 12:28

AW: Erläuterung was "native unicode string" ist?
 
Sorry, wenn ich mich dämlich anstelle, aber mein Delphi kennt kein MessageBoxW.

jaenicke 11. Jul 2011 12:32

AW: Erläuterung was "native unicode string" ist?
 
Dann fehlt die Unit Windows in der uses Klausel.

torud 11. Jul 2011 12:46

AW: Erläuterung was "native unicode string" ist?
 
Jo, jetzt kommen die MessageBoxen.

---------------------------
Test: sValue
---------------------------
Cracoⅵa Kraków
---------------------------
OK
---------------------------

ist der Inhalt. Hier ist auch wieder das vi im Teamnamen so "komisch".

Und so "baue" ich den Code zusammen:

Delphi-Quellcode:
procedure Tmatchid.btn_showClick(Sender: TObject);
begin
  //hinzufügen der strings
  TextString.Add('header=' + ed_header.Text);
  TextString.Add('subline=' + ed_subline.Text);
  TextString.Add('team_a=' + ed_team_a.Text);
  TextString.Add('team_b=' + ed_team_b.Text);
  TextString.Add('footer_1=' + ed_footer_1.Text);
  TextString.Add('footer_2=' + ed_footer_2.Text);
  TextString.Add('footer_3=' + ed_footer_3.Text);
  //schicken der inhalte zum laden der grafik
  form1.TS_AKI_ProviderUC1.ShowGraphic('match_id.gse',1,TextString,LogoString,PropList,0,'IN',True);
end;
Die Messagbox kommt aus einer UnterRoutine von TS_AKI_ProviderUC1.ShowGraphic.
Dort ist alles auf WideString und TWideStringlist eingestellt.

jaenicke 11. Jul 2011 13:07

AW: Erläuterung was "native unicode string" ist?
 
Funktioniert es denn, wenn du den Inhalt der Editfelder direkt per MessageBoxW ausgibst?
(Gibt es vielleicht noch eine andere Eigenschaft als Text? Also ist Text wirklich WideString?)

Lass doch den Unsinn mit der TWideStringList weg. Wenn du mehrere Werte nicht einzeln übergeben willst, nimm einen Record. Aber das ganze zu einer Liste verwursten und dann wieder auseinanderzubasteln ist Blödsinn...

torud 11. Jul 2011 14:03

AW: Erläuterung was "native unicode string" ist?
 
Hm, ich glaube wir nähern uns dem Ziel, denn

//einzel-ausgabe aus dem Control zeigt mir den Namen korrekt an
MessageBoxW(0, PWideChar(ed_team_a.Text), 'Test: sName', 0);

//stringlist-ausgabe, zeigt mir den Namen verwurschtelt an
MessageBoxW(0, PWideChar(TextString.Text), 'Test: sName', 0);

also ist wohl die stringliste, wie von dir schon vermutet, das problem. jetzt stehe ich natürlich vor nem riesenproblem, weil ich seit ca. 4 jahren alle projekte mit TStringlisten fahre, da sich die daten herrlich sammeln lassen. in der komponente sind ja mehr als eine sub-routine, die alle auf das benutzen der Stringliste abgestimmt sind. Und ganz ehrlich sehe ich gerade den Baum vor lauter Wald nicht. Record ist mir klar, aber eine Liste davon oder einen dynmaischen Record erzeugen, wo ich auch schön den Namen des Objekte und seinen Inhalt übergeben und später einfach auslesen kann, treibt mir gerade viele Fragezeichen über den Kopf.

Grübel...

Und
Zitat:

Zitat von jaenicke (Beitrag 1111143)
(Gibt es vielleicht noch eine andere Eigenschaft als Text? Also ist Text wirklich WideString?)

Die Eigenschaft text ist definitiv WideString und nein es gibt keine andere Eigenschaft.

jaenicke 11. Jul 2011 14:36

AW: Erläuterung was "native unicode string" ist?
 
Zitat:

Zitat von torud (Beitrag 1111151)
jetzt stehe ich natürlich vor nem riesenproblem, weil ich seit ca. 4 jahren alle projekte mit TStringlisten fahre, da sich die daten herrlich sammeln lassen.

Noch herrlicher aber ohne...
Denn der Compiler kann dir dort bei Tippfehlern nicht helfen, so dass sich da leicht versteckte Probleme einschleichen können. Qualitativ guter Quelltext sieht anders aus...

Ein Beispiel nach deinem Quelltext:
Delphi-Quellcode:
type
  TGraphicContents = record
    Header: WideString;
    SubLine: WideString;
    TeamA: WideString;
    TeamA: WideString;
    Footer1: WideString;
    Footer2: WideString;
    Footer3: WideString;
  end;

procedure Tmatchid.btn_showClick(Sender: TObject);
var
  GraphicData: TGraphicContents;
begin
  // Setzen der Daten
  GraphicData.Header := ed_header.Text;
  GraphicData.SubLine := ed_subline.Text;
  GraphicData.TeamA := ed_team_a.Text;
  GraphicData.TeamB := ed_team_b.Text;
  GraphicData.Footer1 := ed_footer_1.Text;
  GraphicData.Footer2 := ed_footer_2.Text;
  GraphicData.Footer3 := ed_footer_3.Text;
  //schicken der inhalte zum laden der grafik
  form1.TS_AKI_ProviderUC1.ShowGraphic('match_id.gse', 1, GraphicData, LogoString, PropList, 0, 'IN', True);
end;
Ganz nebenbei zum Stil:
Unterstriche in Bezeichnern sind äußerst unüblich, es gibt auch Groß- und Kleinschreibung. Statt ed_header wäre edHeader oder edtHeader schöner (auch wenn manche die ungarische Notation an sich schlecht finden, ich finde sie bei Komponenten sehr sinnvoll).

torud 11. Jul 2011 14:46

AW: Erläuterung was "native unicode string" ist?
 
Danke für Dein Beispiel und die anderen belehrenden Hinweise. Ich werde versuchen Sie zu beherzigen.
Ich hatte absichtlich geschrieben, dass ich es dynamisch brauche, weil ich ja mehr als eine Struktur von Inhalten übermitteln muss.

Sagen wir, ich muss ca. 40 verschiedene Grafiken mit unteriedlicher inhaltlicher Struktur anzeigen. Soll ich nun 40 verschiedene Records "bauen"?

Z.B. habe ich auch so was hier am Start:

Delphi-Quellcode:
procedure TForm1.btn_show_matchesClick(Sender: TObject);
var
  i : integer;
begin
  TextString.Add('header=' + ed_header_rounds.Text);

  for i := 1 to 8 do
    begin
      //hier werden 48 inhalte in die strinlist geschrieben
      //geht das auch so einfach mit nem record?
      LogoString.Add('logo_a'+ inttostr(i)+'=' + (FindComponent('cmb_ro_team_a' + inttostr(i)) as TComboBox).Text);
      LogoString.Add('logo_b'+ inttostr(i)+'=' + (FindComponent('cmb_ro_team_b' + inttostr(i)) as TComboBox).Text);
      TextString.Add('team_a'+ inttostr(i)+'=' + (FindComponent('ed_ro_team_a' + inttostr(i)) as TdxDNEdit).Text);
      TextString.Add('team_b'+ inttostr(i)+'=' + (FindComponent('ed_ro_team_b' + inttostr(i)) as TdxDNEdit).Text);
      TextString.Add('result_a'+ inttostr(i)+'=' + (FindComponent('ed_ro_res_a' + inttostr(i)) as TdxDNEdit).Text);
      TextString.Add('result_b'+ inttostr(i)+'=' + (FindComponent('ed_ro_res_b' + inttostr(i)) as TdxDNEdit).Text);
    end;
  TS_AKI_ProviderUC1.ShowGraphic('rounds.gse',1,TextString,LogoString,PropList,0,'IN',True);

end;
Die Komponente weiss im Prinzip nix von alledem und arbeitet nur stur und doof ab, was ich ihr zu füttern gebe. Da liegt meiner Meinung nach der Vorteil. Ich kann völlig frei und flexibel die Stringliste erstellen und übergeben und die Komponente arbeitet alles ab, wenngleich mir auch da schon Probleme auftraten mit falschen Namen in der Stringlist. In dem Punkt bin ich komplett bei Dir.

jaenicke 11. Jul 2011 15:07

AW: Erläuterung was "native unicode string" ist?
 
Zitat:

Zitat von torud (Beitrag 1111158)
Delphi-Quellcode:
      //geht das auch so einfach mit nem record?

Nein, einfacher. :mrgreen:
Delphi-Quellcode:
type
  TDemo = record
    LogoA: array[1..8] of WideString;
    LogoB: array[1..8] of WideString;
    ...
  end;

  MyData.LogoA[i] := (FindComponent('cmb_ro_team_a' + IntToStr(i)) as TComboBox).Text;
  MyData.LogoB[i] := (FindComponent('cmb_ro_team_b' + IntToStr(i)) as TComboBox).Text;
Wobei du solche konstanten Namen wie cmb_ro_team_a am besten als Konstanten deklarierst, dann kannst du Probleme oder Namensänderungen bei Komponenten viel schneller überblicken.

Ganz so dynamisch ist ein Record natürlich nicht, aber es gibt auch variante Records. Leider gehen die wiederum nicht mit WideStrings.

Und ein Dictionary existiert wegen der fehlenden Generics bei deiner alten Delphiversion auch noch nicht. Du würdest dir das Leben an vielen Stellen leichter machen, wenn du dir Delphi XE kaufen würdest. ;-)

Das hier müsste aber auch schon bei Delphi 7 gehen...
Delphi-Quellcode:
type
  TTest = (tstOne, tstTwo);

  TExample = record
    DataName: WideString;
    MyData: array[TTest] of WideString;
  end;

var
  MyTest: TExample;
begin
  MyTest.MyData[tstOne] := 'a';
  MessageBoxW(0, PWideChar(MyTest.MyData[tstOne]), 'Test', 0);
Da kannst du auch keine Tippfehler machen und das sollte so ca. dem entsprechen was du an dynamischen Inhalten brauchst.

Insgesamt sieht das ganze aber eher so aus als wären Klassen sehr viel besser geeignet...
Denn da kannst du für die verschiedenen Datentypen entsprechend abgeleitete Klassen erstellen und bist da sehr viel flexibler, kannst aber die Basisfunktionalitäten dennoch gemeinsam kapseln.

torud 14. Jul 2011 09:13

AW: Erläuterung was "native unicode string" ist?
 
Hallo Sebastian,

erstmal entschuldigung für die späte antwort. aber da das projekt ziemlich drängt, war ich busy. ich habe in der zwischenzeit eine lösung gefunden, die weiterhin auf Strinlisten beruht.

scheinbar ist so, dass die widestrings der tntcomponente nicht zusammen passen mit den tsringlisten der jcl. ich habe bruno von tms kontaktiert, da die ja die tntcontrols übernommen haben und er hat mir vorgeschlagen es einfach mal mit den TTntStringlist zu versuchen. das hat dann auf anhieb geklappt.

ich bleibe also erstmal, bis ich wieder etwas luft habe, bei der art und weise der internen datenverarbeiteung, wollte dich aber

1. wissen lassen, dass das problem gelöst wurde und
2. dass ich deinen ansatz grundsätzlich gut finde und ich überlege, wie ich das in zukunft für weitere projekte implementieren kann.

also nochmals vielen dank für dein engagement und die angebotene hilfe!


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:32 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