Let me preface by saying I have tried to find a solution, seen similar queries but, being new to win32, failed to transport those answers into my own problem. I also noticed that every answer seems to have a common root for the issue (unicode) but slightly different technical solutions.
This is an old game institute tutorial. Objective is to create a dialog(1), which contains a combo box, to be populated via a text box for the user to enter a bit of text. Selecting items from the combo box displays a new dialog(2) showing the contents of the selected item. Everything works, bar the display of the items in the combo box, they don;t display correctly instead displaying oriental chars. Text in dialog (2) displays correctly.
#include <windows.h>
#include <string>
#include "resource.h"
using namespace std;
// Dialog handle.
HWND ghDlg = 0;
// Dialog window procedure.
INT_PTR CALLBACK
MsgDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Text buffer to be filled with string user entered
// into edit control.
char msgText[256];
// Handles to the combo box controls.
static HWND hComboBox = 0;
static HWND hEditBox = 0;
static HWND hAddButton = 0;
int index = 0;
switch (msg)
{
case WM_INITDIALOG:
// Controls are child windows to the dialog they lie on.
// In order to get and send information to and from a
// control we will need a handle to it. So save a handle
// to the controls as the dialog is being initialized.
// Recall that we get a handle to a child control on a
// dialog box with the GetDlgItem.
hComboBox = GetDlgItem(hDlg, IDC_COMBOBOX);
hEditBox = GetDlgItem(hDlg, IDC_EDIT_MSG);
hAddButton = GetDlgItem(hDlg, IDC_ADDBUTTON);
return true;
case WM_COMMAND:
switch (HIWORD(wParam))
{
// User selected a combo box item.
case CBN_SELENDOK:
index = SendMessage(hComboBox, CB_GETCURSEL, 0, 0);
SendMessage(hComboBox, CB_GETLBTEXT, (WPARAM)index,
(LPARAM)msgText);
MessageBoxA(0, msgText, "Combo Message", MB_OK);
return true;
}
switch (LOWORD(wParam))
{
// User pressed the "Add" button.
case IDC_ADDBUTTON:
// Get the text from the edit box.
GetWindowTextA(hEditBox, msgText, 256);
// Add the text to the combo box only if the
// user entered a string that is greater than zero.
if (strlen(msgText) > 0)
SendMessage(
hComboBox,
CB_ADDSTRING,
0,
(LPARAM)msgText);
return true;
}
return true;
case WM_CLOSE:
DestroyWindow(hDlg);
return true;
case WM_DESTROY:
PostQuitMessage(0);
return true;
}
return false;
}
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR cmdLine, int showCmd)
{
// Create the modeless dialog window.
ghDlg = CreateDialog(
hInstance, // Application instance.
MAKEINTRESOURCE(IDD_COMBODLG), // Dialog resource ID.
0, // Parent window--null for no parent.
MsgDlgProc); // Dialog window procedure.
// Show the dialog.
ShowWindow(ghDlg, showCmd);
// Enter the message loop.
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (GetMessage(&msg, 0, 0, 0))
{
// Is the message a dialog message? If so the function
// IsDialogMessage will return true and then dispatch
// the message to the dialog window procedure.
// Otherwise, we process as the message as normal.
if (ghDlg == 0 || !IsDialogMessage(ghDlg, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
Let me preface by saying I have tried to find a solution, seen similar queries but, being new to win32, failed to transport those answers into my own problem. I also noticed that every answer seems to have a common root for the issue (unicode) but slightly different technical solutions.
This is an old game institute tutorial. Objective is to create a dialog(1), which contains a combo box, to be populated via a text box for the user to enter a bit of text. Selecting items from the combo box displays a new dialog(2) showing the contents of the selected item. Everything works, bar the display of the items in the combo box, they don;t display correctly instead displaying oriental chars. Text in dialog (2) displays correctly.
#include <windows.h>
#include <string>
#include "resource.h"
using namespace std;
// Dialog handle.
HWND ghDlg = 0;
// Dialog window procedure.
INT_PTR CALLBACK
MsgDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Text buffer to be filled with string user entered
// into edit control.
char msgText[256];
// Handles to the combo box controls.
static HWND hComboBox = 0;
static HWND hEditBox = 0;
static HWND hAddButton = 0;
int index = 0;
switch (msg)
{
case WM_INITDIALOG:
// Controls are child windows to the dialog they lie on.
// In order to get and send information to and from a
// control we will need a handle to it. So save a handle
// to the controls as the dialog is being initialized.
// Recall that we get a handle to a child control on a
// dialog box with the GetDlgItem.
hComboBox = GetDlgItem(hDlg, IDC_COMBOBOX);
hEditBox = GetDlgItem(hDlg, IDC_EDIT_MSG);
hAddButton = GetDlgItem(hDlg, IDC_ADDBUTTON);
return true;
case WM_COMMAND:
switch (HIWORD(wParam))
{
// User selected a combo box item.
case CBN_SELENDOK:
index = SendMessage(hComboBox, CB_GETCURSEL, 0, 0);
SendMessage(hComboBox, CB_GETLBTEXT, (WPARAM)index,
(LPARAM)msgText);
MessageBoxA(0, msgText, "Combo Message", MB_OK);
return true;
}
switch (LOWORD(wParam))
{
// User pressed the "Add" button.
case IDC_ADDBUTTON:
// Get the text from the edit box.
GetWindowTextA(hEditBox, msgText, 256);
// Add the text to the combo box only if the
// user entered a string that is greater than zero.
if (strlen(msgText) > 0)
SendMessage(
hComboBox,
CB_ADDSTRING,
0,
(LPARAM)msgText);
return true;
}
return true;
case WM_CLOSE:
DestroyWindow(hDlg);
return true;
case WM_DESTROY:
PostQuitMessage(0);
return true;
}
return false;
}
int WINAPI
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR cmdLine, int showCmd)
{
// Create the modeless dialog window.
ghDlg = CreateDialog(
hInstance, // Application instance.
MAKEINTRESOURCE(IDD_COMBODLG), // Dialog resource ID.
0, // Parent window--null for no parent.
MsgDlgProc); // Dialog window procedure.
// Show the dialog.
ShowWindow(ghDlg, showCmd);
// Enter the message loop.
MSG msg;
ZeroMemory(&msg, sizeof(MSG));
while (GetMessage(&msg, 0, 0, 0))
{
// Is the message a dialog message? If so the function
// IsDialogMessage will return true and then dispatch
// the message to the dialog window procedure.
// Otherwise, we process as the message as normal.
if (ghDlg == 0 || !IsDialogMessage(ghDlg, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
Share
Improve this question
edited Mar 21 at 21:44
3CxEZiVlQ
39.5k11 gold badges84 silver badges93 bronze badges
asked Mar 21 at 21:30
jmlimajmlima
32 bronze badges
11
|
Show 6 more comments
1 Answer
Reset to default 1潍楪慢敫
This is Mojibake for "Mojibake
" when its ASCII, ANSI, or UTF-8 encoding is interpreted as UTF-16LE. This should look familiar.
The (unintended) transliteration is instigated here:
char msgText[256];
GetWindowTextA(hEditBox, msgText, 256);
if (strlen(msgText) > 0)
SendMessage(hComboBox, CB_ADDSTRING, 0, (LPARAM)msgText);
GetWindowTextA
instructs the system to return the "window text" and (optionally) convert it to the system default ANSI code page encoding (CP_ACP
). The SendMessage
preprocessor macro expands to SendMessageW
(assuming that UNICODE
is defined), and subsequently fools the recipient into interpreting the lParam
argument as UTF-16-encoded.
This is how to generate Mojiabke (and a potential buffer overrun vulnerability on the side).
The "least amount of keystrokes required to address the issue" solution would be to replace SendMessage
with SendMessageA
. A more rational approach is to acknowledge, that UTF-16 is the internal character encoding pretty much everywhere. The following is both correct as well as computationally cheaper:
wchar_t msgText[256] = {};
if (::GetWindowTextW(hEditBox, msgText, std::size(msgText)) > 0)
::SendMessageW(hComboBox, CB_ADDSTRING, 0, reinterpret_cast<LPARAM>(msgText));
TCHAR
-based APIs with ANSI-based APIs.TCHAR
APIs map to either ANSI (A
) or Unicode (W
) APIs depending on your project setup. Use one set of APIs or the other, don't mix them. You didn't show your actual UI or your text, but you aare likely experiencing Mojibake by using an ANSI string where a Unicode string is expected, or vice versa. – Remy Lebeau Commented Mar 21 at 21:33MessageBoxA
. You can call the unicode versions (MessageBoxW
) or let the macro expansion do it for you (MessageBox
). Also, those functions expectwchar_t
instead ofchar
. – 001 Commented Mar 21 at 22:21A
functions expectCHAR
(char
) strings, theW
functions expectWCHAR
(wchar_t
) strings, and the macroed functions expectTCHAR
(char
orwchar_t
based on config) strings. – Remy Lebeau Commented Mar 21 at 22:45