2010-12-13 20 views
1

我目前在學習Win32,使用的是this tutorial,而且我很難用我顯示的字符。我的字符集(Win32 API)有什麼問題

就拿這段代碼在創建時增加了一個菜單,我的窗口:

case WM_CREATE: { 
      HMENU hMenu, hSubMenu; 
      HICON hIcon, hIconSm; 

      hMenu = CreateMenu(); 
      hSubMenu = CreatePopupMenu(); 

      AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit"); 
      AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "File"); 

      hSubMenu = CreatePopupMenu(); 
      AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&GO"); 
      AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Stuff"); 

      SetMenu(hwnd, hMenu); 

      hIcon = LoadImage(NULL, "Stuff.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE); 

      if (hIcon) 
       SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon); 
      else 
       MessageBox(hwnd, "Could not load large icon!", "Load Error", MB_OK | MB_ICONERROR); 

      hIconSm = LoadImage(NULL, "Stuff.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE); 

      if(hIconSm) 
       SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm); 
      else 
       MessageBox(hwnd, "Could not load small icon!", "Load Error", MB_OK | MB_ICONERROR); 
     } 
     break; 

這是一個switch塊裏面我WndProc功能處理來自消息循環收到的Windows消息內。

每個字符串,它是要顯示:

"Exit" 
"File" 
"&GO" 
"&Stuff" 

在運行時不可讀的,因爲它們顯示爲小廣場,就像代碼頁是不正確的或類似的東西。當我運行本教程時,所有字符串都正確顯示。我傾向於完全按照教程所說的來幫助我正確理解事情,其教學法是好的。 !反正......

我使用:

  1. 微軟的Visual Studio 2008 Team System的;
  2. Microsoft Windows Server 2003使用RDP;
  3. 本地操作系統是Windows Vista旗艦版。

任何人都有線索嗎?

回答

6

Unicode與Windows ANSI字符編碼存在問題。從歷史上看,Windows使用擴展的ASCII,它們錯誤地命名爲ANSI。這帶來了對代碼頁的需求,因爲即使是8位字符也不能提供足夠的代碼點來代表所有的歐洲書寫系統,更不用說世界其他地方了。當開發Win32時,他們將Unicode作爲首選字符集。 (實際上,他們對Unicode字符集的UTF-16LE編碼進行了解析,但這一細節目前並不完全相關)。但是,現有代碼太多,需要考慮要求從Win16移植到Win32也需要更改所有字符串的字符編碼。

他們的解決方案很聰明(有人認爲它太聰明瞭)。每個採用字符串的Win32 API入口點都有兩種口味。第一種風格採用ANSI字符串,並在內部處理向UTF-16LE的轉換。第二種(現在是首選)的風格直接採用UTF-16LE字符串。他們還與Visual C團隊合作將wchar_t定義爲16位類型,並確保L""字符串文字使用ASCII文本到UTF-16LE的映射。

爲了從現有的Win16代碼容易,MessageBox函數和每個其他Win32 API,它需要字符串由宏在編譯時被映射到MessageBoxAMessageBoxW取決於預處理器符號UNICODE是否被定義的移植。

該映射無法修復字符串文字,因此他們還引入了一個宏來指定根據UNICODE而變窄或變寬的字符串文字,以及一個匹配的typedef,以便可以聲明變量以保存指向他們。

因此,爲了獲得最佳的便攜性,並從Win16的,你會#include <tchar.h>,代替charwchar_t使用TCHAR,包裹在_T()宏都包含文本字符串文字,並與非後綴上的Win32 API調用像MessageBox這樣的名字。

但是,這不是一個完美的解決方案。當代碼需要操作或計算將顯示給用戶的字符串時,您會發現很難編寫在TCHAR機制中完全可移植的代碼。對所有操縱TCHAR的標準字符串函數都有替換,但很難通過自動化測試來驗證您是否正確地使用了它們,以便代碼能夠在定義的UNICODE的情況下正確編譯和工作。

如果今天寫新的Win32代碼,我的建議是在項目定義UNICODE,補充說,它是在一個共同的頭文件確實規定了檢查,並使用L""串並明確所有包裹的呼叫W口味。

最後,您的代碼將顯示缺少的字符字形(空白方框字符是字體缺少特定字符時顯示的字形)。發生這種情況的原因是,您的ASCII字符串文字被Win32代碼解釋爲UTF-16LE,因此字符串「Exit」將被視爲兩個Unicode字符,即U+7845U+7469,它們都是統一漢字表意形式。除非你安裝了漢字字體,否則這兩種字體都不太可能出現在你的系統中的任何字體上,因此你可以改爲缺少字符字形。

發生這種情況是因爲您正在將包裝宏與ASCII字符串文字混合在一起。您有:

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit"); 

但你應該具備以下之一:

AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, _T("Exit")); 
AppendMenuA(hSubMenu, MF_STRING, ID_FILE_EXIT, "Exit"); 
AppendMenuW(hSubMenu, MF_STRING, ID_FILE_EXIT, L"Exit"); 

,我更願意推薦過去的例子。

+0

+1和接受的答案,因爲你比客戶的要求更多地回答詳細信息。因爲你,我現在知道這些具有「A」和「W」味道的功能,因此我將更改我的代碼以反映這些寶貴的信息。非常感謝! – 2010-12-14 00:55:48

4

由於小廣場的所有奇怪之處,您的代碼是錯誤的。它不符合Unicode。你應該用L前綴所有字符串(如在L「string」中),並將編譯設置改爲Unicode(這使得windows函數接受UTF-16編碼)。這是Windows原生編碼,這是文本如何在Windows上完成的。

另一種方法是在調用API時使用廣泛的API並轉換爲UTF-16。它在http://utf8everywhere.org中描述。

+0

嗯,我不明白爲什麼教程會顯示錯誤的代碼?另外,它工作正常,除了編碼。正如你所提到的,我會注意到編碼。 – 2010-12-13 21:25:47

+0

當我寫'L'字符串「'時,這是有效的。 – 2010-12-13 21:32:45

+1

根據網頁上的版權日期判斷,該教程是在Win32應用程序中Unicode爲標準之前編寫的。如果項目設置爲ANSI字符集,則該代碼仍將編譯(右鍵單擊VS中的項目,屬性,常規下)。代碼將大致在ANSI和Unicode上工作的原因是,AppendMenu被定義爲AppendMenuA for ANSI,AppendMenuW for Unicode(寬字符),根據該設置進行切換。如果查看-A和-W函數的聲明,則會看到參數除了字符串參數以外都是相同的。 – 2010-12-13 21:46:24