Eine MFC-Anwendung unicodefähig machen



  • Eine MFC-Anwendung unicodefähig machen

    Inhaltsverzeichnis

    1. Einleitung
    2. Was ist Unicode?
    3. Woran erkennt man eine Unicode-Datei?
    4. Wie kann man Unicode in einer eigenen MFC-Anwendung nutzen?
    5. Worauf muss nun in der MFC-Anwendung geachtet werden?
    6. Kleines Beispiel anhand einer Unicode-Textdatei
    7. Speziellen Dank an Alexander Müller

    1 Einleitung

    Dieser Artikel handelt von dem so genannten Unicode-Standard.
    Hier wird nur auf den Unicode-Standard UTF 16 eingegangen. Neben diesem existieren noch die UTF-Standards 32, 8, 7 (veraltet), EBCDIC. Wer weitere Informationen zu den in diesem Artikel nicht genannten UTF-Standards benötigt, kann auf der Internetseite von Wikipedia ( http://de.wikipedia.org/wiki/UTF ) mehr darüber erfahren. Ebenfalls sollte man hier die Organisation der Webseite http://www.unicode.org erwähnen, die sich um die Standardisierung des Unicodes kümmert.
    Für das erzeugte Beispiel wurde Visual Studio C++ 6.0 genutzt.

    2 Was ist Unicode?

    Bisher wurde stets davon ausgegangen, dass ein Zeichen in ein Byte hineinpasst, und dies hat auch einige Jahre problemlos funktioniert. Nun lassen sich in einem Byte aber maximal 256 verschiedene Zeichen darstellen. Unser Alphabet hat zwar nur 26 Zeichen, aber die übrigen Zeichen waren ebenfalls schnell reserviert, sei es für Steuerzeichen, Leerzeichen, Symbole und so weiter. Die ersten 127 Zeichen sind als "ASCII"-Tabelle bekannt und enthalten alle Klein- und Großbuchstaben des lateinischen Alphabets. Häufige Verwendung findet auch die "ANSI"-Tabelle, die in den ersten 127 Zeichen mit ASCII übereinstimmt, und in den hinteren 128 Zeichen weitere Zeichen enthält, unter anderem auch die deutschen Umlaute.

    Es hat sich jedoch gezeigt, dass ein Byte einfach zu wenig ist, um alle möglichen Zeichen der Alphabete aus aller Welt einheitlich darzustellen. Also wurde Unicode als Standard erfunden. Unicode ist eine Zeichentabelle, die 32767 verschiedene Zeichen ermöglicht, weil jedes Zeichen 2 Byte (= 16 Bit) groß ist. Auch Symbole wie Euro, Dollar und britisches Pfund haben dort ihren eindeutigen Platz. Der Nachteil ist jedoch, dass jedes Zeichen 16 Bit Platz braucht und dass dies natürlich Texte und Strings auf die doppelte Größe aufbläht.

    3 Woran erkennt man eine Unicode-Datei?

    Woher weiß jetzt eine Textverarbeitung wie Word oder Notepad, ob in einer Textdatei, die geöffnet werden soll, Unicode oder 1-Byte-Zeichen verwendet werden? Es hat sich durchgesetzt, dass Unicode-Textdateien stets mit den beiden Bytes "FF FE" beginnen. Daran wird diese Erkennung festgemacht. Daher sollte man diesen Code auch selbst verwenden, wenn man Unicode-Dateien erzeugt.

    4 Wie kann man Unicode in einer eigenen MFC-Anwendung nutzen?

    Im ersten Schritt müssen wir dem Compiler mitteilen, dass wir in unserer Anwendung Unicode nutzen wollen und dass er dies beim Kompilieren berücksichtigen soll. Dies erreichen wir durch das Definieren des Makros _UNICODE!

    Da wir Unicode nutzen wollen, benötigen wir für die MFC-Anwendung einen anderen Einstiegspunkt (wWinMainCRTStartup). Diesen können wir ebenfalls über die Projekteinstellungen definieren.

    5 Worauf muss in einer MFC-Anwendung geachtet werden?

    Wir müssen beim Programmieren darauf achten, dass wir unsere Texte, die wir im Quellcode Hard kodieren, mit dem Makro _T("") umschließen. Dieses Makro kümmert sich um die Konvertierung der Zeichen, wenn _UNICODE definiert ist.

    Aus

    CString szText = "Hallo Welt";
    

    wird

    CString szText = _T("Hallo Welt");
    

    Die CString-Klassen können wir ganz normal weiternutzen, da diese unicodefähig sind. Bei manchen Befehlen ist es möglich, dass wir diese durch die unicodefähigen Alternativen ersetzen müssen. Beispiel hierfür wäre der Befehl strcpy, der durch den Befehl wcscpy zu ersetzen wäre. Für die meisten klassischen Funktionen ist eine eine wchar_t Version vorhanden.

    Hier ein paar Beispiele solcher Befehle:
    Funktionsname => wchar_t Version

    strcpy => wcscpy
    strcat => wcscat
    fopen => _wfopen

    Manche Klassen wie die CString-Klasse nutzen automatisch die richtige Funktion. Dies wird durch eine Define-Anweisung in der Klasse geregelt.

    6 Kleines Beispiel anhand einer Unicode-Textdatei

    Da wir zum Laden einer Unicode Datei nicht mehr die normale Klasse CStdioFile nutzen können, benötigen wir nun eine neue Klasse die mit Unicode umgehen kann. In diesem Beispiel verwende ich die CStdioFileEx-Klasse von der Webseite http://www.codeproject.com/file/stdiofileex.asp. Mit Hilfe dieser Klasse lassen sich Unicode-Dateien komfortabel einlesen und schreiben. Die oben genannte Klasse wurde speziell für die Arbeit mit Unicode-Dateien erstellt.
    Hier seht ihr die kleine GUI, anhand derer ich euch dieses kleine Beispiel demonstrieren möchte.

    Die Funktion des Buttons "Lade Unicode-Datei" enthält folgenden Quellcode:

    void CMFCUnicodeExampleDlg::OnLadeUnicodeDatei() 
    {
    	// Variable deklarieren
    	CString szText;
    	CStdioFileEx readfile; 
    
    	// Datei öffnen
    	readfile.Open(_T("Hallo_Welt.txt"),CFile::modeRead|CFile::typeText);
    
    	// Zeile einlesen
    	readfile.ReadString(szText);
    
    	// Datei schließen
    	readfile.Close();
    
    	// Text dem CStatic-Element zuordnen
    	GetDlgItem(IDC_STATIC_UNICODE_AUSGABE)->SetWindowText(szText);
    }
    

    Würden wir nun die Applikation ausführen, würden wir Folgendes erhalten:

    Wie ihr seht, steht unser Text leider nicht korrekt in dem CStatic-Feld, sondern stattdessen lauter kleine schwarze Kästchen. Der Fehler hierfür liegt an der Schriftart, die das CStatic-Feld nutzt. Daraus schließen wir, dass wir die Schriftart des CStatic-Feldes ändern müssen.

    Um dies zu bewerkstelligen, deklarieren wir eine private Membervariable in der Headerdatei (.h Datei) unseres Dialoges mit dem Namen m_Font.

    CFont m_Font; // Font-Variable deklarieren
    

    Sobald der Dialog geöffnet wird, erstellen wir die neue Schrift und weisen diese dem CStatic-Feld zu. Hier bietet sich die OnInitDialog-Funktion an, da diese direkt nach dem Aufruf des Dialogs aufgerufen wird.

    Folgender Ausschnitt muss dieser Funktion hinzugefügt werden.

    // Font-Struktur deklarieren
    LOGFONT logf;
    
    // Struktur mit NULL füllen
    ZeroMemory(&logf,sizeof(LOGFONT));
    
    // Schriftgröße festlegen
    logf.lfHeight = 16;
    
    // Schriftart festlegen
    wcscpy(logf.lfFaceName,_T("Arial"));
    
    // Schrift erstellen
    m_Font.CreateFontIndirect(&logf);
    
    // Schrift dem CStatic-Element zuweisen
    GetDlgItem(IDC_STATIC_UNICODE_AUSGABE)->SetFont(&m_Font);
    

    Würden wir nun unseren Dialog erneut ausführen und die Textdatei laden, würde der Text aus der Textdatei korrekt dargestellt. Dieser Text bedeutet nichts anderes als "Hallo Welt".

    Ich hoffe, ich konnte euch mit diesem Artikel bezüglich Unicode ein wenig weiterhelfen.

    Mit freundlichen Grüßen
    euer Günni

    7 Speziellen Dank an Alexander Müller

    Ein spezieller Dank geht an den Autor Alexander Müller, der mir erlaubte, einige Textfragmente von seinem Artikel über Unicode in diesem Artikel zu verwenden.
    Der Originalartikel von Alexander Müller ist unter http://www.a-m-i.de/tips/strings/strings.php zu erreichen.

    Das Beispielprojekt ist downloadbar unter
    http://www.c-plusplus.net/magazin/bilder/mfc_application_unicode/MFC_Unicode_Example.zip


Log in to reply