2012-08-09 77 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設置。