C ++:为什么这个窗口标题会被截断?

时间:2012-08-09 12:59:26

标签: c++ winapi

Visual C ++ 2012 RC,Win7

简体中文

项目属性>使用多字节字符集

当我运行此程序时,窗口的标题显示单个字母“S”,而不是整个单词“Sample”。

#pragma comment(linker, "/SubSystem:Windows")

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, int) {
    WNDCLASSW wc = { 0 };

    wc.style            = CS_VREDRAW | CS_HREDRAW;
    wc.hInstance        = hInstance;
    wc.hIcon            = LoadIcon(nullptr, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(nullptr, IDC_ARROW);
    wc.hbrBackground    = reinterpret_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
    wc.lpszClassName    = L"MyWindowClass";

    wc.lpfnWndProc = [](HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
        if (uMsg - WM_DESTROY)
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        else {
            PostQuitMessage(0);
            return HRESULT();
        }
    };

    RegisterClassW(&wc);

    CreateWindowExW(0, L"MyWindowClass", L"Sample",
        WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, SW_SHOW, CW_USEDEFAULT, 0,
        nullptr, nullptr, hInstance, nullptr);

    for (MSG msg; GetMessage(&msg, nullptr, 0, 0); DispatchMessage(&msg));
}

如果我使用Unicode(项目属性),保持源代码不变,窗口标题显示“Sample”,看起来正确。

如果我使用多字节,在源代码中我使用WNDCLASS = {...,“MyWindowClass”}和RegisterClassA,保持CreateWindowExW不变,窗口标题显示单词“Sample”,看起来正确。

如果我使用多字节,在源代码中我使用CreateWindowExA(“MyWindowClass”,“Sample”),保持WNDCLASSW和RegisterClassW不变,窗口标题显示字母“S”。

是什么让它显示单个“S”,我做错了什么?

追加

如果我保持不变,即使用多字节,使用上面显示的代码,窗口标题显示字母“S”。

(如果你运行这个程序并在窗口标题上看到“Sample”而不是“S”,那么它更可能是chc版本的vc ++ 2012(或OS)上的特定问题。)

6 个答案:

答案 0 :(得分:21)

您的代码中的问题是您使用的是DefWindowProc而不是DefWindowProcW。更改它将修复代码。

理想情况下,您应该将项目设置更改为使用Unicode,而不是多字节字符集。这将简化所有内容,您可以使用CreateWindowExRegisterClassEx之类的宏,而不是显式使用Unicode / ANSI版本。

正如其他人所说,这是字符集之间的不匹配。

理想情况下,您应该在所有相互交互的API调用之间匹配字符集。因此,如果您使用CreateWindowExW,则还应使用RegisterClassExWDefWindowProcWDispatchMessageW ...

答案 1 :(得分:4)

这是一个非常好的,学到了新东西!

您需要更改

return DefWindowProc(hWnd, uMsg, wParam, lParam);  

if(IsWindowUnicode(hWnd))  
  return DefWindowProcW(hWnd, uMsg, wParam, lParam);  
else  
  return DefWindowProcA(hWnd, uMsg, wParam, lParam);

甚至更好:坚持一个字符编码。最好只使用RegisterClass,CreateWindowEx等,让编译器采用正确的Unicode或ANSI函数。

答案 2 :(得分:2)

CreateWindowExA将字符串解释为8位字符。 L“Sample”的后8位为零,因为它的第一个字符是0x0053 - L表示使用宽字符。因此该函数将其解释为1个字符的空终止字符串。

答案 3 :(得分:1)

我认为msdn page for RegisterClass暗示了失败原因,在备注部分提到了如果你使用宽字符或ansi支持,那么它将以这种格式传递内部文本参数/消息(宽char / ansi)。很可能这就是窗口标题发生了什么,即使我们说使用CreateWindowExA,这在内部不起作用,Windows SDK已将该字符串编码为宽字符串,CreateWinowExA尝试输出就好像它是一个Ansi字符串。

简而言之,不要混合W和A方法,除非你有充分的理由这样做,并让windows header为你处理,如果你想要宽字符支持定义你的UNICODE宏。 / p>

答案 4 :(得分:0)

在你的最后一种情况下你的L“Sample”仍然是Unicode,不是吗?您可以使用_T()宏,它会根据项目的Unuicode设置自动添加或删除L前缀。

正如@Pete所说,Unicode L“Sample”在ascii中是“S \ 0 ...”,这就是为什么只打印一个符号的原因。

答案 5 :(得分:0)

我很高兴我找到了这个。我正在寻找一个答案,而且似乎很难找到正确的Google等。我确实发现了针对特定程序报告的类似问题,总是指责“插件”。

令人抓狂,因为WndProc的问题远不及CreateWindowEx和RegisterClassEx的调用!

顺便说一句,我明确地使用-W后缀,因为我想制作一个适用于以任何方式构建的程序的DLL,或者克服我正在添加的程序的非Unicode设置。

相关问题