讀Windows核心編程 - 2

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.

發佈了25 篇原創文章 · 獲贊 0 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章