Es gibt immer wieder Momente in denen einen die Win32 API in größtes Erstaunen versetzt.
Meistens ist dies allerdings in diesen Momenten nichts positives. Das zweite Erstaunen folgt, dann wenn man in der MSDN nachliest und das Verhalten als dokumentiert vorfindet. Meistens endet solch eine Kette dann in einem Kopfschütteln und dem Gedanken: Das darf doch gar nicht sein.
Genug der langen Vorworte:
- Gegeben ein normales MFC Projekt. (WinAPI pur tut es auch 😉 )
- Ein Dialog
- Darin eine Combobox als Dropdown mit Eingabemöglichkeit
- Die Combobox wird mit einigen Variablen Werten gefüllt mit CComboBox::Addstring/InsertString, was letzten Endes nur ein Wrapper für CB_ADDSTRING/CB_INSERTSTRING ist.
- Das ganze sieht also in OnInitDialog in etwa wie folgt aus
cb.AddString(CString(MAKEINTRESOURCE(IDS_DATA1)));
cb.AddString(CString(MAKEINTRESOURCE(IDS_DATA2)));
cb.AddString(CString(MAKEINTRESOURCE(IDS_DATA3)));
cb.AddString(strSomeDynamicData);
cb.InsertString(0,_T(""));
Alles OK… Als letztes noch den Stil CBS_UPPERCASE dazu – weil hier eben nur Eingaben in Großbuchstaben erlaubt sein sollen und Sinn machen – und… Peng!
Das Programm schmiert ab. 😮
Was ged’n hier ab Alder ❓
In den tiefen des Aufrufs von cb.InsertString(0,_T(„“)); schmiert mein Programm ab. UAE
Nun aber doch großes Erstaunen, denn der selbe Code funktioniert in einem MBCS Programm.
Es liegt eindeutig an der Nutzung von CBS_UPPERCASE und Unicode.
Jetzt habe ich schon gedacht einen Bug in Vista und XP gefunden zu haben, denn auf beiden schmiert bersagter Code ab. Und wahrscheinlich ist es auch ein Bug! Aber das genauere Nachlesen der MSDN belehrt mich eines besseren. Dieses dämliche Verhalten ist dokumentiert, zumindest für CB_ADDSTRING (der Zusatz fehlt in der CB_INSERTSTRING Doku):
Comclt32.dll version 5.0 or later: If CBS_LOWERCASE or CBS_UPPERCASE is set, the Unicode version of CB_ADDSTRING alters the string. If using read-only global memory, this causes the application to fail. ❗
Unfassbar! Die Nachricht ist dabei selbst so beschrieben, wie es sich jeder vernünftige Entwickler auch denkt und vor allem erwartet, eben mit einem LPCTSTR:
lResult = SendMessage( // returns LRESULT in lResult
(HWND) hWndControl, // handle to destination control
(UINT) CB_ADDSTRING, // message ID
(WPARAM) wParam, // = 0; not used, must be zero
(LPARAM) lParam // = (LPARAM) (LPCTSTR) lParam;
);
Aber was nützt schon ein vernünftiger Gedanke eines Entwicklers wenn es um das irrwitzige Eigenleben der Win32 API geht.
Und denke nie einen Bug gefunden zu haben, bevor Du nicht jede Zeile der MSDN studiert hast 😉