最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c++ winapi Combo box displaying oriental chars - Stack Overflow

programmeradmin6浏览0评论

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
  • 2 Are you compiling your project with UNICODE enabled or disabled? You are mixing 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:33
  • Unicode enabled. Tried to insert an image to show the dialogs in action but, no success. – jmlima Commented Mar 21 at 22:08
  • 1 But you are calling the non-unicode functions explicitly. Example: MessageBoxA. You can call the unicode versions (MessageBoxW) or let the macro expansion do it for you (MessageBox). Also, those functions expect wchar_t instead of char. – 001 Commented Mar 21 at 22:21
  • The A functions expect CHAR (char) strings, the W functions expect WCHAR (wchar_t) strings, and the macroed functions expect TCHAR (char or wchar_t based on config) strings. – Remy Lebeau Commented Mar 21 at 22:45
  • 1 Thanks everyone, it all works now! In summary, if I'm getting this right, unless there's a specific need top support 9x and if I'm using unicode, always use w suffixed functions and wchar_t. – jmlima Commented Mar 22 at 9:12
 |  Show 6 more comments

1 Answer 1

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));
发布评论

评论列表(0)

  1. 暂无评论