Multibyte zu Unicode Problem

Sparks

Mitglied
Hallo,

(wenn das hier falsch eingetragen ist, bitte verschieben, danke!)

Es geht um eine Anwendung, die mit einer Übersetzung auch für Multibyte-Sprachen (z. B. japanisch) läuft. Die Texte (Labels usw.) werden aus einer Datenbank-Tabelle ausgelesen (da könnte man drüber diskutieren, ob das der beste Weg ist, das lässt sich jetzt aber nicht ändern!)
Leider bekomme ich aber die deutschen Umlaute und Sonderzeichen (wie ß) nicht genau so wie den ursprünglichen Unicode string zurück.
Zur Veranschaulichung des Problems habe ich einen kleinen Screenshot beigefügt.

Wie kann ich dieses Beispiel "Gr·e" statt "Größe" umsetzen?
Die Win-API-Funktion MulitByteToWideChar (in Kernel32.dll) hat mir nicht geholfen, bzw. ich bekomme eine StackOverflow-Exception: "An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll" beim zweiten Aufruf (Zeile 8.):

C#:
try
{
    // sOriginal enthält den Double-Byte-String
    int nSizeUnicode = MultiByteToWideChar(0, 0, sOrginal, -1, ref cUnicode, 0);
    if (nSizeUnicode > 0)
    {
        cUnicode = new char[nSizeUnicode];
        MultiByteToWideChar(0, 0, sOrginal, -1, ref cUnicode, nSizeUnicode);
        sRueckgabe = cUnicode.ToString();
    }
}
catch (Exception e)
{
    throw;
}
Oder gibt es eine andere Möglichkeit, z. B. mit den System.Text.Encoding-Klassen?
Ich habe an der Stelle gar keine Erfahrungen.

Danke und Gruß,
Sparks
 

Anhänge

  • doublebyte.jpg
    doublebyte.jpg
    16,1 KB · Aufrufe: 54

Norbert Eder

Erfahrenes Mitglied
Also .NET läuft per default mit Unicode. Das was du allerdings vermutlich nicht machst, ist dass du die zu verwendende Culture/Region nicht einstellst. Des weiteren ist das natürlich auch davon abhängig ob du in deiner Datenbank überhaupt Unicode-fähige Typen verwendest.

Von welchem Typ sind denn deine Datenbank-Felder?
 

Sparks

Mitglied
Hallo Norbert,

es ist richtig, dass die Datenbank (zumindest derzeit leider noch) nicht Unicode-fähig ist.
Aber, an diesen Gegebenheiten kann ich nichts ändern.
Die API-Funktion klappt ja (lt. Infos aus dem Internet), ich benötige lediglich die genaue Spezifikation, wie ich die Variablen in C# zu deklarieren habe, daran hapert es ja offenbar bei mir.

Derzeit deklariere ich das im ersten Posting sOriginal genannte Array z. B. wie folgt:
C#:
char[] sOriginal = label20.Text.ToCharArray();
Möglicherweise ist auch die Deklaration (Anzahl der Elemente?!) des zweiten Arrays völlig falsch.
C#:
cUnicode = new char[nSizeUnicode];
// oder:
cUnicode = new char[nSizeUnicode+1];
Die übrigen Parameter sollten lt. MS okay sein.

Das Einbinden der API-Funktion sieht bei mir so aus:
C#:
[DllImport("kernel32.dll")]
public static extern int WideCharToMultiByte(int CodePage, int dwfFags, 
char[] lpWideCharString, int nSize, ref char[] cMultiByteChar, int nReturnSize, 
char[] cDefault, ref bool bDefault);
(wobei ich die beiden letzten Variablen in meinen Aufrufen im ersten Posting unterschlagen habe. Aber daran sollte es nicht liegen, die können NULL sein.)

Vielen Dank für Deine Antwort, frohes Fest!
Gruß Sparks
 

Norbert Eder

Erfahrenes Mitglied
WideCharToMultiByte wird dir hier auch nicht helfen. WideChar ist ein Unicode-Character, den du ja gar nicht hast, da du kein Unicode in der DB ablegst.

Dein Weg ans Ziel ist es, die Typen in der Datenbank auf unicode-fähige Typen zu stellen.
 

Sparks

Mitglied
Hallo Norbert,

vielen Dank für Deine Antwort! Dass man nicht so einfach ein Datenbanksystem durch ein anderes ersetzen kann, sollte klar sein.

Natürlich habe ich Unicode, wie Du ja selbst im Deinem ersten Posting geschrieben hast.

Ich habe Unicode im Source, d.h., die Labels sind Unicode.
Im Label wird also "Größe" ausgelesen.

Und selbst wenn ich es andersherum lösen wollte, bräuchte ich die Parameter für die entsprechende API-Funktion, die dann "MultiByteToWideChar()" lautet.

Gruß,
Sparks
 

Norbert Eder

Erfahrenes Mitglied
Leider bekomme ich aber die deutschen Umlaute und Sonderzeichen (wie ß) nicht genau so wie den ursprünglichen Unicode string zurück.

Das Problem ist folgendes:
Wenn du beispielsweise japanische Zeichen (Katakana, Hiragana, von Kanji rede ich jetzt gar nicht) in ein NICHT-Unicode Feld schreibst, dann geht dir einfach die Information verloren. Diese bekommst du auch nicht zurück.

Stell dir einfach einen Filter vor, der dir jedes zweite Zeichen aus deinem Wort herausfiltert und nun versuche in die andere Richtung das ursprüngliche Wort zusammen zu stellen. Funktioniert einfach nicht (lediglich eine vereinfachte Veranschaulichung).

D.h. wenn du schon eine bestehende Datenbank hast (produktives System), dann steht hier wohl eine Migration an.

Eine andere Möglichkeit besteht darin, dass du die Texte einfach wieder aus der DB rausnimmst und die Geschichte via XML löst ...
 

Sparks

Mitglied
Nochmals vielen Dank für Deine Antwort.
Die japanischen Zeichen werden korrekt ausgelesen (sihe meinen Screenshot im ersten Posting).
Wie ich schon schrieb, ist eine Migration der DB derzeit keine Option.

Die Frage ist nicht, wie ich das Problem anders lösen könnte, sondern wie muss ich die Parameter der API-Funktion in C# deklarieren (mein zweites Posting).
Die API-Funktion klappt ja (lt. Infos aus dem Internet), ich benötige lediglich die genaue Spezifikation, wie ich die Variablen in C# zu deklarieren habe, daran hapert es ja offenbar bei mir.
Gruß,
Sparks
 

Sparks

Mitglied
Herzlichen Dank, Norbert, und ein gutes neues Jahr!

Dein Link hat mir sehr geholfen!
Ich habe die Exception behoben, aber wichtiger noch, ich habe etwas mehr Durchblick bei dem Ganzen.
(Und das ist immer besser, als nur irgendetwas per copy & paste zu übernehmen :) ).

Aus welchen Gründen auch immer, ließ sich das konkrete Problem dann zwar doch nicht mit der API-Funktion lösen, aber ich habe es mit der von mir Eingangs angesprochenen Encoding-Klasse geschafft:
Oder gibt es eine andere Möglichkeit, z. B. mit den System.Text.Encoding-Klassen?
Falls jemand ein ähnliches Problem hat, poste ich hier meine Lösung, die zumindest mit den Gegebenheiten hier (Windows-Codepage, Datenbank usw.) funktioniert:
C#:
// sMultiByteString enthält den aus der Datenbank ausgelesenen Text "Gr·e" (siehe Beschreibung und Screenshot im ersten Posting)
string sUnicodeString = System.Text.Encoding.UTF7.GetString(System.Text.Encoding.GetEncoding(932).GetBytes(sMultiByteString));
// sUnicodeString enthält jetzt: "Größe"
Die Win32-Codepage ist 932, Shift_JIS . Das ist eine Double-Byte-Zeichensatz (DBCS) Codepage.

Gruß, Sparks