Microsoft對Unicode的支持:
Windows 98 :只支持ANSI
Windows 2000: 即支持Unicode也支持ANSI,但是用Unicode會更快,因爲會有一個內部的轉化過程,比如調用CreateWindowEx函數,參數傳非Unicode字符串,那麼CreateWindowEx必須分配內存(進程的默認堆中),將非Unicode字符轉化成Unicode字符,然後在傳給CreateWindowEx。影響效率。
Windows CE:只支持Unicode
COM:只支持Unicode
C運行時庫對Unicode的支持:
在標準C頭文件String.h中定義:typedef unsigned short wchar_t;
對應strcat、strcpy、strlen這樣的函數都有一組對應的Unicode版本:wcscat、wcscpy、wcslen
對於包含了對str函數和wcs函數進行顯示調用的代碼來說,無法非常容易的同時爲ANSI和Unicode對這些代碼進行編譯。若要建立雙重功能,必須包含頭文件TChar.h,而不是String.h。
TChar.h中定義了很多宏,比如_tcscpy,如果定義了_UNICODE這個宏就調用wcscpy,如果沒有定義就調用strcpy函數。另外TChar.h中還定義了:
定義了_UNICODE:typedef wchar_t TCHAR;define _TEXT(x) L##x
沒有定義 _UNICODE:typedef char TCHAR;define _TEXT(x) x
這樣,無論有沒有定義_UNICODE,都可以這麼用:TCHAR *szError = _TEXT("Error");通過這種方法,只需通過_UNICODE就可以分別編譯出ANSI和Unicode版本。另外: _T("") 等同於 _TEXT("")。
Windows頭文件定義的數據類型:
WCHAR :Unicode字符串
PWSTR:指向Unicode字符串的指針
PCWSTR:指向一個恆定的Unicode字符串的指針
Windows也定義了ANSI/Unicode通過數據類型PTSTR和PCTSTR,這些數據類型可以指ANSI字符串,也可以指Unicode字符串,取決於是否定義了UNICODE宏。(這裏沒有下劃線,跟C運行時庫不同)
Windows提供的函數通常包含兩個版本:比如CreateWindowExA和CreateWindowExW,還有一個宏CreateWindowEx,調用哪裏取決於是否定義了UNICODE。而在Windows 2000下,因爲沒有ANSI版本,CreateWindowExA其實做了從ANSI版本到Unicode版本的轉化工作。
要創建給其他開發人員使用的DLL時可以考慮提供兩個版本的輸出函數:ANSI版本和Unicode版本。在ANSI版本中就進行簡單的字符串轉化,在調用Unicode版本。Windows API中一些函數僅僅爲了實現與16位Windows的兼容,像WinExec和OpenFile,應該用CreateProcess和CreateFile代替。
Windows還提供了一組操作字符串的函數:StrCat、StrChr、StrCmp、StrCpy...這些函數同樣支持ANSI和UNICODE版本,取決於是否定義了UNICODE宏,書上建議使用這些函數代替C運行期字符串函數,因爲這些函數被很多程序使用,比如Explorer.exe,在我們的應用程序運行時,它們可能已經被裝入RAM。但是可惜沒有見到過程序中使用這類函數的,所以也不知道這個說法是否正確。如果要使用這些函數,要包含頭文件ShlWApi.h。
要成爲符合ANSI和Unicode的應用程序,應該符合以下幾條規則:
1. 將文本串視爲字符數組,而不是char數組和字節數組
2. 將通用數據類型(如TCHAR和PTSTR)用於文本字符和字符串
3. 將顯示數據類型(如BYTE和PBYTE)用於字節、字節指針和數據緩存
4. 將TEXT宏用於原義字符和字符串
5. 執行全局性替換(用PTSTR替換PSTR)
6. 修改字符串運算操作(sizeof(szBuffer/sizeof(TCHAR))、maloc(nCharacters*sizeof(TCHAR)))
在Windows中,還提供了一組字符串操作的函數(宏):lstrcat、lstrcmp、lstrcmpi、lstrcpy、lstrlen...他們也根據UNICODE宏選擇調用ANSI版本還是Unicode版本的函數。有兩個函數於C運行時函數是不同的,即lstrcmp和lstrcmpi,C運行期函數strcmp、strcmpi、wcscmp、wcscmpi只是對字符串的代碼點的值進行比較,這就是說,這些函數將忽略實際字符的意義。而Windows版本的函數是通過調用CompareString函數實現的。這個函數的第一個參數是LCID lcid,CompareString使用這個ID來比較這兩個字符串,方法是對照一種特定的語言來查看他們的字符的含義。這個ID是通過調用LCID GetThreadLocale()函數得到的。
其他C運行時函數沒有爲Unicode提供很好的支持。例如,tolower和toupper函數無法正確的轉換帶有重音符號的字符。爲了彌補C運行期庫的不足,可以調用下面的Windows函數:PTSTR CharLower(PTSTR pszString)和PTSTR CharUpper(pszString),這些函數也可用於轉換ANSI字符串。另外Windows還提供了IsCharAlpha(THCR ch)、IsCharLower(TCHAR ch)等函數,與C運行期函數不同的是,這些函數還要考慮用戶在控制面板中指定的語言。另外Microsoft公司還提供了wsprintf等函數使我們能很容易地對ANSI和Unicode進行混合和匹配。
當資源編譯器對你的所有資源進行編譯時,輸出文件是二進制文件。資源(字符串表、對話框模板等)中的字符信息總是Unicode字符串。如果應該程序沒有定義UNICODE,那麼系統會進行內部轉化。比如在編譯源代碼模塊時沒有定義UNICODE,調用LoadString實際上調用了LoadStringA。這時LoadStringA就從你的資源中讀取字符串,並將該字符轉換成ANSI字符串。ANSI形式的字符串將從該函數返回給你的應用程序。
MultiByteToWideChar和WideCharToMultiByte用於多字節字符串和寬字符串之間的轉換。用法比較複雜。可參看核心編程page 24.