2012-08-09 22 views
11

的Visual C++ 2012 RC,Win7的C++:为什么这个窗口标题被截断?

中国简化

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

当我运行这个程序,窗口的标题显示了一个字母“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(Project Properties),保持源代码不变,窗口标题显示“Sample”,看起来正确。

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

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

什么使它显示一个单一的“S”,我做错了什么?

追加

如果我把所有不变,即使用多字节,如上图所示使用代码,窗口标题显示字母“S”。 (如果你运行这个程序并在窗口标题上看到“Sample”而不是“S”,那么它更可能是chc版本的vC++ 2012(或OS)上的一个特定问题)。

+2

为什么你发布的版本的代码工作正常?不起作用的版本在诊断问题时会更有用。 – 2012-08-09 13:14:24

+0

这看起来很奇怪。使用的RegisterClass版本决定它是否是Unicode窗口('IsWindowUnicode()')或不是。 Windows可以双向转换Unicode <-> ANSI,因此您应该可以混合使用Unicode和ANSI函数调用。但是:你为什么要这样做?为什么不使用其中的一个,最好是最后没有A和W的那个,这样窗口头文件就映射到项目属性中设置的版本(例如'RegisterClass' - 没有A或W,映射到'RegisterClassA '或'RegisterClassW'自动)? – 2012-08-09 13:24:05

+0

@Joe Gauterin如果上面贴出的代码是正确的,在窗口标题中正确显示“Sample”,那么这可能是VC++ 2012 RC chs中的一个错误。上面显示的代码显示了我的系统上的单个“S”:D – WangZm 2012-08-09 13:29:29

回答

16

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

理想情况下,您应该将您的项目设置更改为使用Unicode,而不是多字节字符集。这将简化一切,您可以使用像CreateWindowExRegisterClassEx这样的宏,而不是像现在这样显式使用Unicode/ANSI版本。

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

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

+0

这显然是最佳做法。但是你在哪里找到一个定义,说你不能混合RegisterClassW和CreateWindowA? “IsWindowUnicode”的MSDN文档说你可以混合Unicode和ANSI(窗口和消息)。不幸的是,他们没有提到CreateWindowExA/W和RegisterClassA/W。 – 2012-08-09 13:28:49

+0

@WernerHenze:你说得对,这不是必要的。事实上,我错了,它是'CreateWindowEx'和'RegisterClassEx'之间的不匹配。它实际上是'RegisterClassEx'和'DefWindowProc'之间的不匹配。 – tenfour 2012-08-09 14:13:38

+0

@tenfour:DefWindowProcW,正好!问题解决了,谢谢!当使用RegisterClassW/CreateWindowExW时,我们必须调用DefWindowProcW。对Werner Henze说:“这显然是最好的做法,但是你在哪里找到一个定义说你不能混合RegisterClassW和CreateWindowA?同意:D – WangZm 2012-08-09 14:28:33

0

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

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

+0

您可以使用'_T()'和'CreateWindowEx'宏。在这里他明确使用'CreateWindowExW',所以这不相关。 – tenfour 2012-08-09 13:08:39

+0

请再次阅读我的文章,我只谈论作者的最后一个案例(他遇到问题)。他在那里使用CreateWindowExA。 – Steed 2012-08-09 13:09:49

+0

原始海报表示,如果他调用CreateWindowExA(“MyWindowClass”,“Sample”),则窗口标题不正确。他不是在那里写L“Sample”。 – 2012-08-09 13:12:34

2

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

+0

另外,不要使用CreateWindowExA或CreateWindowExW,只需使用CreateWindowEx并让预处理器根据你的字符集设置计算出你应该使用哪一个。所有其他Win32函数都一样。 – Pete 2012-08-09 13:09:51

+0

原始海报表示,如果他调用'CreateWindowExA(“MyWindowClass”,“Sample”)',则窗口标题不正确。他不是在写'L'样本“'。 – 2012-08-09 13:11:30

1

我觉得msdn page for RegisterClass暗示了失败的原因就在这里,在备注栏它提到如何,如果您使用宽字符或ANSI支持,那么它将以这种格式传递内部文本参数/消息(宽字符/ ansi)。尽管我们说使用CreateWindowExA,但很可能这就是窗口标题所发生的情况,但这不起作用,因为Windows SDK已将该字符串编码为宽字符字符串,并且CreateWinowExA会尝试输出,就好像它是Ansi字符串。

总之不要混合使用W和A方法,除非你有足够的理由这样做,并让Windows头文件为你处理它,如果你想要宽字符支持定义你的UNICODE宏。

4

这是一个非常不错的学习新东西!

您需要更改

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

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

+0

谢谢!在实践中,我会坚持这些macor Api和TEXT()。至于好玩,我想看起来很奇怪。 :d – WangZm 2012-08-09 14:33:38

0

我很高兴我找到了这个。我一直在寻找一个答案,似乎很难找到正确的谷歌等。我确实发现类似的问题报告的具体方案,总是指责“一些插件”。

它令人生气,因为WndProc的问题远不及CreateWindowEx和RegisterClassEx的调用!

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