problem mit EnumSystemCodePagesW



  • hola leute

    folgender code:

    #include "./main.hpp"
    #include <Windows.h>
    #include <iostream>
    
    auto main(int, const char **) -> int
    {
       BOOL ret;
    
       ret = EnumSystemCodePagesW([](LPWSTR code_page) -> BOOL
       {
          CPINFOEXW cp_info;
          memset(&cp_info, 0, sizeof(cp_info));
          BOOL ret = TRUE;
          ret = GetCPInfoEx(_wtoi(code_page), 0, &cp_info); //(1)
    
          if(ret != FALSE)
             std::wcout << code_page << L" : " << cp_info.CodePageName << L"\r\n";
          else
             std::wcout << L"FEHLER !!!    ErrorCode: " << GetLastError() << L"\r\n";
    
          return TRUE;
       }, CP_INSTALLED);
    
       return 0;
    }
    

    wenn ich die zeile (1) auskommentiere dann schreibt er mir alle codepages big 65001 UTF-8 raus. wenn die zeile (1) nicht auskommentiert ist,
    dann bricht das programm ungefaehr bei der haelfte mit der ausgabe ab.
    die letzte codepage die nicht vollstaendig ausgegeben wird ist bei mir 55001.
    wenn ich im debugger durch gehe, dann funktionierts wieder.
    kann jemand ausprobieren ob das problem auf einem anderen rechner reproduzierbar ist ?
    ich hab Win10 64 Home VS2015

    danke

    Meep Meep



  • BOOL ret = TRUE;
    ret = GetCPInfoEx(_wtoi(code_page), 0, &cp_info);
    

    ret hat zuerst den Wert TRUE, dann überschreibst du ihn mit der nachfolgenden Zeile. Das heißt, du würdest ihn überschreiben, wenn er nicht auskommentiert ist. Wenn er auskommentiert ist, überschreibst du ihn nicht.

    Wenn ret != FALSE ist, dann gibt die Nummer der Codepage und den Namen, den du vom System bekommen hast, aus. Andernfalls gib einen Fehler aus. Wenn ret jetzt immer TRUE ist, weil du GetCPInfoEx nicht aufrufst ... tja, was dann? Dann gibt er dir natürlich nie einen Fehler aus - ob du das aber "Funktionieren" nennen willst, bezweifele ich mal.

    Abgebrochen wird das Programm bei mir nicht. Geht ja auch schlecht:

    MSDN schrieb:

    Returns TRUE to continue enumeration or FALSE otherwise.

    Und du gibst immer TRUE zurück. Wie soll die Enumeration vorzeitig abbrechen?

    Bei mir werden bei zwei Codepages Fehler ausgegeben, Code Page 20949 und Code Page 1147. Erstere ist irgendsoeine koreanische Codepage, dass die nicht installiert ist, wundert mich nicht wirklich. 1147 ist wohl für IBM01147, keine Ahnung, was mit der los ist - sie sieht aber nicht sonderlich exotisch aus. Was ich exotisch finde, ist dass GetLastError() keinen Fehlercode zurückgibt, wenn GetCPInfoEx fehlschlägt - Bug in Windows?

    Keine Ahnung, aber das beschriebene Verhalten kann ich nicht 100%-ig nachvollziehen.

    EDIT: Rechtschreibfehler.



  • hola

    ich habe nicht gesagt das das programm abgebrochen wird. ich hab geschrieben, das das programm mit der ausgabe abbricht.
    hier ein screenshot wie das dann aussieht: http://250894.webhosting60.1blu.de/abbruch_ausgabe.jpg

    hab das gerade auf meinem laptop ausprobiert, das selbe verhalten.

    wenn die zeile (1) auskommentiert ist, dann ist ret immer TRUE. soll auch so sein, damit er mir alle codepages auflisten kann. daher weiß ich auch wieviele codepages er ungefaehr finden bzw. auflisten muesste.

    wenn nun zeile (1) nicht auskommentiert ist, dann sollte er entweder hinschreiben das ein fehler aufgetaucht ist oder halt den CodePageNamen hinschreiben. aber das macht er eben nicht. nur zum teil. ploetzlich hoert dann bei mir auf beiden rechnern die ausgabe auf.

    ich hab unter die zeile (1) ein Sleep(300); reingetan. bei 55001 hoert die ausgabe auf, dann dauert es knappe 10 sekunden bis das programm zu ende ist und der restliche text "Drücken Sie eine beliebige Taste . . ." kommt.

    also wird die lambda funktion weiterhin aufgerufe.
    Der text mit "Drücken Sie eine beliebige Taste . . ." muesste ohne hin in einer eigenen zeile stehen und nicht wie bei mir im screenshot zu sehen, im text des letzten angezeigten CodePageNamen, weil ja ueberall ein L"\r\n" hinzugefuegt wird.

    Meep Meep



  • hab jetzt mal den source etwas geändert:

    std::vector<int> code_pages;
    
    BOOL CALLBACK EnumCodePagesProc(LPWSTR code_page)
    {
       code_pages.push_back(_wtoi(code_page));
       return TRUE;
    }
    
    auto main(int, const char**) -> int
    {
       BOOL ret;
    
       ret = EnumSystemCodePagesW(EnumCodePagesProc, CP_INSTALLED);
    
       for(const auto &value : code_pages)
       {
          CPINFOEXW cp_info;
          memset(&cp_info, 0, sizeof(cp_info));
          BOOL ret = TRUE;
          ret = GetCPInfoEx(value, 0, &cp_info); 
    
          wchar_t *str = cp_info.CodePageName;
    
          //std::wcout << value << L" : " << cp_info.CodePageName << std::endl; (1)
    
          // wprintf(L"%s\r\n", str); (2)
       }
    
       return 0; 
    }
    

    wenn ich nun zeile (1) aktiviere, dann wird die ausgabe wieder bei der codepage 55001 abgebrochen. wenn ich zeile (2) deaktiviere dann werden alle codepages ausgegeben. liegt also scheinbar irgendwie am wcout.
    wenn ich uebrigens zeile (1) aktiviert habe und einen breakpoint auf zeile (1) setze, dann kann ich alle codepages mit F5 durchschalten und sehe im debugfenster den namen der codepage. die ausgabe selber wird aber wieder bei codepage 55001 abgebrochen.



  • bin grad drauf gekommen, das ich mit aktivierter zeile (1) danach überhaupt nichts mehr mittels wcout ausgeben kann. cout funktioniert jedoch.
    hab mal rdstate von wcout gecheckt. ist auf badbit gesetzt. aber wie kommt es dazu ???
    ich denke das der thread nun im C++ subforum besser aufgehoben ist.

    kann mich jemand verschieben ?

    danke

    Meep Meep



  • Dieser Thread wurde von Moderator/in Martin Richter aus dem Forum WinAPI in das Forum C++ (alle ISO-Standards) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Meep Meep schrieb:

    ich habe nicht gesagt das das programm abgebrochen wird. ich hab geschrieben, das das programm mit der ausgabe abbricht.

    Verzeihung, der Satz war ein wenig missverständlich. Ein "Während der Ausgabe bricht das Programm dann ab, und ich sehe nur noch 'Drücken Sie eine beliebige Taste . . . '" wäre genauer gewesen. Vielleicht noch mit dem Beispiel: "55001 : 55001 (SMS GSM 7bit Drücken Sie eine beliebige Taste . . .".

    Meep Meep schrieb:

    bin grad drauf gekommen, das ich mit aktivierter zeile (1) danach überhaupt nichts mehr mittels wcout ausgeben kann. cout funktioniert jedoch.
    hab mal rdstate von wcout gecheckt. ist auf badbit gesetzt. aber wie kommt es dazu ???
    ich denke das der thread nun im C++ subforum besser aufgehoben ist.

    Habe mich gerade noch mal ein wenig genauer umgeschaut, die GSM 55000 - 55004 Code Pages habe ich nicht, weil ich kein Win10 hab. :p
    Aber wenn rdstate badbit gesetzt hat ... wäre meine erste Vermutung, dass es ein nicht valides Unicode-Zeichen im String gibt und wcout allergisch darauf reagiert, indem es aborted?

    An der Stelle würde ich mir den String mal Byte für Byte als Integer ausgeben lassen und einfach schauen, ob nach dem "7bit "-Teil Bytes vorkommen, die wcout durcheinander bringen könnten.

    EDIT: Ich habe noch dumpf in Erinnerung, dass die Ausgabe auf der Konsole bei Windows ungebuffert ist, wenn es also Probleme gibt, dann sieht man die in der Regel sofort.



  • hola

    bin inzwischen drauf gekommen wo das problem liegt. hast recht gehabt mit dem zeichen: und zwar ist es 0x2013. ist ein langer bindestrich:
    http://www.unicodemap.org/details/0x2013/index.html
    das zeichen kommt in den codepagenames von 55001 bis 55004 vor. wenn ich die codepages nicht rauschreiben lasse, dann bleibt der stream in ordnung.
    ich kann den stream gezielt kaputt machen:

    wchar_t cc = 0x2013;
       std::wcout << cc << std::endl;
    

    das reicht schon, das er das badbit setzt. das problem ist ueberigens auch bei nem filestream. wenn ich das zeichen in einen std::wofstream schreibe, ist der stream auch kaputt.
    das ist natuerlich fatal. somit kann ein zeichen ein programm funktionsuntuechtig machen.

    nur wie geh ich jetzt mit dem problem um ?

    Meep Meep



  • Dann ist das wahrscheinlich irgendwo ein Bug in der streams-Implementierung von Windows, würde ich mal ganz naiv sagen. Zumindest, ohne da jetzt Hintergrundwissen zu besitzen.

    Vielleicht kennt jemand ja bereits das Problem - mal "windows wcout abort" gegoogelt? Da komme ich auf solche Threads, vielleicht hilft das ja schon.

    Ansonsten ... der String ist nicht schreibgeschützt, sprich, du könntest den String vorher nach Unicode-Zeichen, die Windows nicht darstellen kann, durchsuchen und ersetzen. Den langen Bindestrich durch 'nen ASCII-Bindestrich ersetzen. Ja, ist 'ne blöde Lösung, weiß ich selbst, aber besser als nix.

    EDIT:

    Habe gerade eben wieder Zugriff auf 'ne Windows-Machine gehabt. So, dieses Programm gibt den Bindestrich korrekt aus:

    #include <iostream>
    #include <io.h>
    #include <fcntl.h>
    
    int main(void)
    {
    	wchar_t cc = 0x2013;
    	_setmode(_fileno(stdout),_O_U16TEXT);
    	std::wcout << cc << std::endl;
    	std::cin.get();
    	return 0;
    }
    

    Sieht also echt so aus, als müsste man die Standardausgabe noch mal Extra auf UTF-16 setzen, damit es funktioniert. Wahrscheinlich der Abwärtskompatibilität wegen ... 🙄

    EDIT 2: Und für C reicht dann:

    _setmode(_fileno(stdout),_O_U16TEXT);
    wprintf(L"%lc\n",cc);
    

    Ohne _setmode bricht wprintf allerdings nichts ab, sondern gibt nur ein '?' aus. Ich könnt' jetzt gegen C++ stänkern ... 😃

    Egal. Propier' _setmode aus. Bei mir funzt es.


Anmelden zum Antworten