Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   UTF8 als WideString an ActiveX (LPCTSTR) (https://www.delphipraxis.net/168453-utf8-als-widestring-activex-lpctstr.html)

taveuni 22. Mai 2012 09:51

UTF8 als WideString an ActiveX (LPCTSTR)
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
Ich bin am verzweifeln. Seit Tagen maile ich mit einer Entwicklerin ohne Ergebnis.
Diese pflegt ein ActiveX für deren Subsystem (geschrieben in C++). In diesem besteht seit Jahren eine Funktion
welche als Parameter einen Dateinamen enthält. Beim Import des ActiveX wird in der Typ Bibliothek seit Delphi6
(aktuell bin ich bei XE2) ein WideString definiert. Bisher war kein Problem auszumachen. Neu wird die Anlage
in China eingesetzt und es können auch chinesische Dateinamen übergeben werden.
Ich hoffte mit XE2 diesbezüglich ohne Modifikationen auszukommen.

Nun: Intern wird das ActiveX scheinbar ohne "define Unicode" kompiliert.
Deshalb ist der vom ActiveX erwartete Datentyp ein 8Bit LPCSTR.
http://msdn.microsoft.com/en-us/libr...(v=vs.85).aspx
Also eigentlich ein Array of Char in UTF8 kodierung.

Soweit so gut - Die einzige Möglichkeit welche ich gesehen habe ist den Parameter so zu übergeben: UTF8Encode(DelphiUnicodeString).
Im Debugger des ActiveX sieht die Entwicklerin aber auch so nur ??? (siehe Screenshot)

Ist es auf der Basis überhaupt möglich das wir uns treffen?

Danke für jede Hilfe

himitsu 22. Mai 2012 12:00

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Externe Schnittstellen verändern sich nicht, nur weil du jetzt einen anderen Compiler verwendest.

Sind diese als ANSI deklariert, dann bleiben sie ANSI.

Und wird intern z.B. die ANSI-WinAPI für Dateizugriffe verwendet, dann kann auch nur ANSI verwendet werden, da diese Schnittstellen kein UTF-8 vertehn.
Also ohne die verwendete Komponente intern nicht auf Unicode umzustellen, wirst du auch kein Unicode verwenden können.

Einzige Ausnahme sind Strings, welche nur intern verwendet werden und nirgendwo explizit als ANSI (aktuelle CodePage) vorliegen müssen,
wo man Diesem implizit heimlich einen UTF-8-kodierten Text unterschiebt.

Man kann teilweise die Codepage (des Threads, Prozesses oder gar vom ganzen Windows) umstellen, aber in wie weit das hilft, müßte man ausprobieren.



Alternativ kannst du beim ANSI bleiben und mußt nur dafür sorgen, daß die "langen" Datei- und Pfadnamen in das kurze 8.3-Dateiformat umgewandelt werden.
Das geht natürlich nur für existierende Dateien. (Speichern von Dateien würde ausschließlich als ANSI bleiben)

taveuni 22. Mai 2012 12:17

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Hmhh..

Noch mal für mein Verständnis:
Wenn ich diesem Parameter welchen mir Delphi beim Import als Widestring angelegt hat einen
"AnsiString" als Widestring mitgebe (also z.b. c:\MeineDatei.mov) kommt diese so an.
Wenn ich "MeineDatei" chinesisch mitgebe ( c:\我的档案.mov) kommt auf der anderen Seite c:\????.mov an.

Wenn ich das ActiveX in VisualStudio in C++ importiere ist der Parameter LPCSTR. Dieser ist ja 8Bit.
Ich kann dann dort z.b. für den Dateinamen: c:\下周我要去度假.mov
dies übergeben:
Code:
char tmp[] = {'c', ':', '\\', 0xE4, 0xB8, 0x8B, 0xE5, 0x91, 0xA8, 0xE6, 0x88, 0x91, 0xE8, 0xA6, 0x81, 0xE5, 0x8E, 0xBB, 0xE5, 0xBA, 0xA6, 0xE5, 0x81, 0x87, '.', 'm', 'o', 'v', 0x00 }
Also müsste ich doch aus Delphi auch einen UTF8 codierten (Ansi?-) String übergeben können?
Oder hat die IDE einfach den Typen falsch genieriert?

Die Entwicklerin schreibt mir noch:

Das ActiveX arbeitet intern NUR mit LPCSTR oder array of char. Die Kodierung in UTF-8 macht es möglich mit chinesische oder russische Zeichen zu arbeiten.
Meine Meinung nach versucht den Wrapper 2 Byte Character in 1 Byte Character zu konvertieren und das geht schief wenn der Wert über 255 (oder 127?) liegt.
Daher kommen die ?. Wenn Sie die Dateiname in UTF-8 kodieren funktioniert (ab ActiveX 1.2.4.7 mit richtige Zeichen).
Falls Sie eine Rutine benötigen um die Konvertierung zu machen können Sie folgende benutzen:
Code:
/* utf8_setc:
*  Sets a character in a UTF-8 string.
*/
int utf8_setc(char *s, int c)
{
  int size, bits, b, i;
  if (c < 128)
  {
    *s = c;
    return 1;
  }
  bits = 7;
  while (c >= (1<<bits))
    bits++;
  size = 2;
  b = 11;
  while (b < bits)
  {
    size++;
    b += 5;
  }
  b -= (7-size);
  s[0] = c>>b;
  for (i=0; i<size; i++)
    s[0] |= (0x80>>i);
  for (i=1; i<size; i++)
  {
    b -= 6;
    s[i] = 0x80 | ((c>>b)&0x3F);
  }
  return size;
}

int unicode_to_utf8n(wchar_t* src, char* dst, int srcLength, int maxOutLength)
{
  int i = 0;
  int utfsize = 0;
  int unisize = 0;
  for(i=0; i<srcLength; i++)
  {
    if (srcLength < (maxOutLength - 4))
      utfsize += utf8_setc(dst+utfsize, (int)src[i]);
    else
      break;
  }
  dst[utfsize] = 0;
  return utfsize;
}

himitsu 22. Mai 2012 13:02

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Du darfst den UnicodeStriong/WideString nicht "einfach" nach ANSI umewandeln.
Alles was nicht umgewandelt werden kann, wird automatisch in ein "?" übersetzt. (MSDN-Library durchsuchenWideCharToMultiBye mit '?' als Ersetzungszeichen)

Du mußt schon über die Dateisystem-APIs den Pfad übersetzen lassen.
MSDN-Library durchsuchenGetShortPathName oder Delphi-Referenz durchsuchenExtractShortPathName

Ob du das dann als ANSI oder Unicode (welches hier scheinbar intern nach ANSI umgewandelt wird) weitergibst, ist egal, da die kurzen Dateinamen eh nur ASCII benutzen.



Wenn es intern mit wirklich auch UTF-8 arbeiten kann, dann wirst du wohl ebenfalls selber nach UTF-8 übersetzen müssen.
Mußt dann nur zusehn, daß dabei irgendwo ein WideString dazwischenkommt, welcher die UFT-8-Kodierung zerstören könnte.

taveuni 22. Mai 2012 14:51

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Zitat:

Zitat von himitsu (Beitrag 1167597)
Wenn es intern mit wirklich auch UTF-8 arbeiten kann, dann wirst du wohl ebenfalls selber nach UTF-8 übersetzen müssen.
Mußt dann nur zusehn, daß dabei irgendwo ein WideString dazwischenkommt, welcher die UFT-8-Kodierung zerstören könnte.

:gruebel: Ich glaub nicht das ich das verstanden habe. Was meinst mit "es"?

Vergessen wir mal den Dateinamen.
Es gibt noch andere Funktionen/Parameter welche in Delphi in der *_TLB.pas als WideString definiert sind
und vom ActiveX intern als UTF8 codierte LPCSTR Strings erwartet werden.

Besteht mit der Konstellation wie beschrieben eine Chance oder muss das ActiveX
angepasst werden?

himitsu 22. Mai 2012 18:17

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Und du bist dir wirklich sicher, daß LPCSTR bei dir als UTF-8 verwendet werden kann, bzw. kann man irgendwo den verwendeten Charset einstellen?

Wenn es unter D6 mit LPCSTR nur ANSI verarbeitet wurde, dann wird es, bei gleicher Schnittstelle auch jetzt immernoch nur als ANSI arbeiten.


Wie sieht den die TLB aus?

taveuni 22. Mai 2012 19:07

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Hallo himitsu,

Ich bin mir insofern sicher als dass in anderen Programmiersprachen dieses so dem ActiveX als Array of Char
übergeben kann und dieses (das ActiveX) dies richtig verarbeitet. Allerdings habe ich natürlich die Sourcen des ActiveX nicht.

Auszug aus der TLB

Delphi-Quellcode:
// *********************************************************************//
// DispIntf: _DGeheimeFirmaActiveXControl
// Flags:    (4112) Hidden Dispatchable
// GUID:     {EC277D05-8AA2-41F5-91AA-8EE7DBD55C77}
// *********************************************************************//
  _DGeheimeFirmaXControl = dispinterface
    ['{EC277D05-8AA2-41F5-91AA-8EE7DBD55C77}']

    function DlmXBackup(ulCameraFilter: Integer; ulStartTimeStampSec: Integer;
                        ulStartTimeStampMillis: Integer; ulStopTimeStampSec: Integer;
                        ulStopTimeStampMillis: Integer; const strFilename: WideString;
                        const strFormat: WideString): Integer; dispid 21;

    function DlmXConfig(const strConfigXML: WideString): Integer; dispid 25;
Bei der Funktion DlmXBackup gehts hier um den Parameter strFilename.
In der Funktion DlmXConfig kann/muss ich vorgängig dieses XML mitgeben:

Code:
<DlmSDK><DlmConfig><Display CodePage=“utf-8” /></DlmConfig></DlmSDK>
<DlmSDK><DlmConfig><Display CodePage=“ISO-8859-1” /></DlmConfig></DlmSDK>
<DlmSDK><DlmConfig><Display CodePage=“windows-1251” /></DlmConfig></DlmSDK>
Wird damit vielleicht das Charset eingestellt?

himitsu 22. Mai 2012 22:42

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Hmmm. :gruebel:

Also ein Problem ist ersmal, daß seit mindestens Delphi 2009 (hab nie im 2007er nachgesehn) die Delphi-Strings (AnsiString, RawByteString, UTF8String, also alle AnsiString-Nachfahren und natürlich der neue UnicodeString) über eine CodePage-Information verfügen.

Anhand dieser CodePage wird notfalls eine Convertierung vorgenommen.
Delphi erkennt also, daß du einen UTF-8-kodierten String (AnsiString+CP_UTF8) an einen Unicode-String (WideString) übergeben willst und wandelt den enthaltenen Text "korrekt" um ... macht also aus dem UTF-8 wieder Unicode. :angle:

Das andere Problem ist, daß wir nicht wissen wie Windows das, bzw. deren Code, intern aus dem WideString/PWideChar einen PAnsiChar/LPCSTR macht.
(das müßtest du mal erdebuggen oder eben ausprobieren)

Versuch es mal so:
Delphi-Quellcode:
function WUConvert(const S: string): WideString;
var
  A: UTF8String;
begin
  A := UTF8Encode(S);
  SetCodePage(A, CP_ACP, False);
  Result := A;
end;

// und falls es doch nicht geht, dann eventuell so?

function WUConvert(const S: string): WideString;
var
  A: UTF8String;
begin
  A := UTF8Encode(S);
  SetCodePage(A, $FFFF, False);
  Result := A;
end;

// oder

function WUConvert(const S: string): WideString;
var
  A: UTF8String;
  i: Integer;
begin
  A := UTF8Encode(S);
  SetLength(Result, Length(A));
  for i := 1 to Length(A) do
    Result[i] := A[i];
end;

PS: Dein
Delphi-Quellcode:
<DlmSDK><DlmConfig><Display CodePage="..." /></DlmConfig></DlmSDK>
ist eh nur ASCII, drum kann man sich dort alles sparen und kann es problemlos direkt übergeben.

PPS: Sicher daß “ und ” korrekt sind und nicht eigentlich " dort hingehört?
Ein korrektes XML ist das so jedenfalls nicht.

taveuni 23. Mai 2012 08:43

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
Hallo himitsu,

SetCodePage erwartet einen RawByteString.
Ich habe bei den ersten zwei Funktionen den UTF8String durch diesen ersetzt.
Die letzte lässt sich nicht kompilieren.

Mit der ersten Variante funktionierts!
Es ist mir noch nicht ganz klar weshalb.
Kannst Du mich aufklären?

UTF8Encode(s) hatte ich ja schon gemacht.
Nun ist "nur" noch das SetCodePage hinzugekommen.

Auf jeden Fall danke ich Dir vielmals. Du hast meine Woche gerettet.
Ich hoffe Du kannst Dein profundes Wissen auch beruflich angemessen einsetzen.
:thumb:

himitsu 23. Mai 2012 09:03

AW: UTF8 als WideString an ActiveX (LPCTSTR)
 
UTF8Encode setzt als Codepage CP_UTF8, was eigentlich auch richtig so ist.
Mit SetCodePage wurde die Codepage nun auf $FFFF gesetzt, was einem RawByteString entspricht.
Wenn man jetzt diesen AnsiString/RawByteString an einen UnicodeString oder WideString zuweist, dann nutzt Delphi die Codepage für die Convertierung.
Es macht also implizit paraktisch ein UTF8Decode, da in den WideString Unicode reingehört.
Über den RawByteString, welcher nun dein UTF-8 enthält, aber über SetCodePage+CP_ACP gesagt bekommen hatte er enthält "angeblich" ANSI, wird nun bei der Umcodierung nicht von UTF8 nach Unicode, sondern von ANSI nach Unicode umgewandelt, also so als wenn es ANSI-Zeichen währen.

Intern wird anscheinend ebenfalls immer nur von Unicode nach ANSI umgewandelt, egal was du als Setting vorgegeben hast.
Da hätte die Entwicklerin selber für eine korrekte Konvertierung sorgen müssen.

PS: Bis mindestens Delphi 7 hat Delphi alles in einem AnsiString auch als ANSI angesehn, selbst wenn man vorher ein UTF-8 dort reingeschoben hatte.
Dort gab es die CodePage an jedem String noch nicht und somit hätte man damals UTF-8 problemlos nutzen können, ohne soeinen Krampf durchzumachen.

Aber eigentlich ist die Entwicklerin Schuld, denn wenn die den WideString auch als Unicode nutzen und dann intern korrekt umwandeln würde, dann müßte man nicht versuchen in dem Unicode-String ein verstümmeltes UTF-8 mitgeben zu müssen.


Und du mußt aufpassen, denn wir in Deutschland haben kein MultiByte im ANSI, sondern nur eine SingleByte-Codepage ... jedes Byte ist ein Zeichen.
Die Asiaten haben ein paar mehr Zeichen, drum nutzen sie eine richtige MultiByte-CodePage.

Außerdem gibt es für einige Unicode-Zichen mehrere/verschiedene ANSI-Darstellungen.
Es könnte also Probleme bei der Rückumandlung geben, da das UTF-8 implizit ein gemapptes über ANSI umgeleitet wird, mit Hin- (ANSI>Unicode) und Rückübersetzung (Unicode>ANSI), vobei das UTF-8 eventuell zerstört werden könnte.


So, ich hoffe mal, ich hab jetzt keinen Knoten im Hirn.


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