如何从控件中正确检索Unicode文本?

时间:2017-11-03 21:27:23

标签: c++ winapi unicode

以下是Unicode的示例:为了简洁起见,我避免使用win32应用程序:

在主要内容中,我创建了一个edit控件,一个button用于从中检索文本,并在按下时将其添加到listbox。所以我使用了struct MSG的对象,并在while循环peeking中阻止了来自消息队列的消息。

int main(){

    // An edit control where I can add any unicode text to.
    HWND hEdit = CreateWindowExW(WS_EX_CLIENTEDGE, 
        L"Edit", L"你好! 你好吗?", WS_BORDER | WS_VISIBLE | WS_SYSMENU,
        200, 100, 250, 70, 0, 0, GetModuleHandle(NULL), NULL);

    // A listobx to receive the content of the edit control when pressing the button get text.
    HWND hLstBx = CreateWindowExW(WS_EX_CLIENTEDGE,
        L"Listbox", NULL, WS_BORDER | WS_VISIBLE | WS_OVERLAPPEDWINDOW,
        500, 100, 170, 400, 0, 0, GetModuleHandle(NULL), NULL);

    // A button when pressed adds the content of the edit to the listbox.
    HWND hGetText = CreateWindowExW(WS_EX_CLIENTEDGE,
        L"Button", L"中文", WS_BORDER | WS_VISIBLE,
        450, 300, 100, 70, 0, 0, GetModuleHandle(NULL), NULL);


    // msg struct to pass to GetMessage to receive the messages from the queue.
    MSG msg;


    // blocking and getting messages from the queue.
    while (GetMessageW(&msg, 0, 0, 0)) {
        // some virtual keys translation.
        TranslateMessage(&msg);
        // sending the message to the specified window.
        DispatchMessageW(&msg);

        // Now after the messages sent to the target Window I check which control the message has been passed to, So if it is the button then:
        if (msg.message == WM_LBUTTONDOWN && 
            msg.hwnd == hGetText) {
            std::wstring wstrBuff;

            int txtLen = SendMessageW(hEdit, WM_GETTEXTLENGTH, 0, 0);
        //  SendMessageW(hEdit, WM_GETTEXT, txtLen + 1, (LPARAM)wstrBuff.c_str());
        //  MessageBoxW(0, wstrBuff.c_str(), 0, 0);


            wchar_t lpTxt[MAX_PATH];
            SendMessageW(hEdit, WM_GETTEXT, MAX_PATH, (LPARAM)lpTxt);
            SendMessageW(hLstBx, LB_ADDSTRING, 0, (LPARAM)lpTxt);
            MessageBoxW(0, lpTxt, L"你好! 你好吗?", 0);
            //delete[]lpTxt;
        }
    }

    std::wcout << std::endl << std::endl;
    std::wcin.get();
    return 0;
}

除了以下内容之外,所有内容都可以正常工作:如果我取消注释上面的行,我会遇到断言消息的运行时错误,显示txtLen和编辑控件文本的大小。这是因为有一些字符串重叠吗?

如果我输入一个小文本它可以正常工作,但是有一个大约14个字符的文本我得到了错误。

  • 这也是将std::wstring.c_str()传递给SendMessageW()以获取文字的正确方法吗?

  • 最后一个问题:如何正确有效地从控件中检索Unicode文本?如何将LPWSTR与动态记忆结合使用:我不想耗尽筹码。

  • 注意:我将源文件保存为utf8 /BOM,否则我会收到不可读的字符。感谢为我提供帮助的成员。

1 个答案:

答案 0 :(得分:4)

发送(LPARAM)wstrBuff.c_str()将返回指向只读缓冲区的指针,该缓冲区具有单个空符号,而不是txtLen + 1个符号的缓冲区。如果您使用的是最新的VS(使用C ++ 17标准支持),则可以修改代码以提供正确的指针:

 std::wstring wstrBuff;
 wstrBuff.resize(txtLen + 1);
 const LRESULT copied_symbols_count = SendMessageW
 (
     hEdit
 ,   WM_GETTEXT
 ,   static_cast<WPARAM>(wstrBuff.size())
 ,   reinterpret_cast<LPARAM>(wstrBuff.data())
 );
 if(copied_symbols_count == txtLen)
 {
     assert(L'\0' == wstrBuff.back());
     wstrBuff.pop_back(); // get rid of terminating null
 }
 else
 {
     wstrBuff.clear(); // something went wrong...
 }

请注意,C ++ 17标准添加了非const限定的wstring::data()方法,可以安全地用于获取指向可写缓冲区的指针。