字元unicode與windows
1 軟體的本地化要解決的真正問題,實際上就是如何來處理不同的字元集。以前我們習慣與用單一位元組字元集來編程.
2 單字元集:將文本串作為一系列單位元組字元來進行編碼,並在結尾處放上一個零。(每個字元用一個位元組來表示)
3 雙位元組字元集(D B C S ):在雙位元組字元集中,字串中的每個字元可以包含一個位元組或包含兩個位元組。
4 unicode字元集:U n i c o d e 提供了一種簡單而又一致的表示字串的方法。U n i c o d e 字串中的所有字元都是1 6 位的(兩個位元組)。
5 當M i c r o s o f t 公司將C O M 從1 6 位Wi n d o w s 轉換成Wi n 3 2 時,公司作出了一個決定,即需要字串的所有C O M 介面方法都只能接受U n i c o d e 字串。
6 c運行期庫支援unicode,即使是windows98也支援.
7 Windows 2000 的N o t e p a d (記事本)應用程式允許你既能開啟U n i c o d e 檔案,也能開啟A N S I 檔案,並且可以建立這些檔案。
8 I s Te x t U n i c o d e 函數能夠協助進行區分ANSIC字元和unicode:
DWORD IsTextUnicode(CONST PVOID pvBuffer, int cb,PINT pResult);
第一個參數p v B u ff e r 用於標識要測試的緩衝的地址。該資料是個無效指標,因為你不知道你擁有的是A N S I 字元數組還是U n i c o d e
字元數組。
第二個參數c b 用於設定p v B u ff e r 指向的位元組數。同樣,由於你不知道緩衝中放的是什麼,因此c b 是個位元組數,而不是字元數。請注意,不必設定緩衝的整個長度。當然,I s Te x t U n i c o d e能夠測試的位元組越多,得到的結果越準確。
第三個參數p R e s u l t 是個整數的地址,必須在調用I s Te x t U n i c o d e 之前對它進行初始化。對該整數進行初始化後,就可以指明你要I s Te x t U n i c o d e 執行哪些測試。也可以為該參數傳遞N U L L ,在這種情況下,I s Te x t U n i c o d e 將執行它能夠進行的所有測試(詳細說明請參見Platform SDK 文檔)。
9 對D B C S 字串進行操作的協助函數
函數 |
描述 |
PTSTR CharNext(PCTSTR pszCurrentChar); |
返回字串中的下一個字元的地址 |
PTSTR CharPrev (PCTSTR pszStart,PCTSTR p s z C u r r e n t C h a r); |
返回字串中的上一個字元的地址 |
BOOL IsDBCSLeadByteTRUE(BYTE bTestChar); |
如果該位元組是DBCS 字元的第一個位元組,則返回 |
10 “M i c r o s o f t 公司對U n i c o d e 支援的情況”:
• Windows 2000 既支援U n i c o d e ,也支援A N S I ,因此可以為任意一種開發應用程式。
• Windows 98 只支援A N S I ,只能為A N S I 開發應用程式。
• Windows CE 只支援U n i c o d e ,只能為U n i c o d e 開發應用程式。
11 Wi n d o w s 標頭檔定義de Uincode 資料類型
資料類型 |
說明 |
W C H A R |
U n i c o d e 字元 |
P W S T R |
指向U n i c o d e 字串的指標 |
P C W S T R |
指向一個恒定的U n i c o d e 字串的指標 |
使用執行個體如下:
#ifdef UNICODE#define CreateWindowEx CreateWindowExW#else#define CreateWindowEx CreateWindowExA#endif //!UNICODE
在Unicode與ANSI之間轉換字串
Wi n d o w s 函數M u l t i B y t e To Wi d e C h a r 用於將多位元組字串轉換成寬字元串。下面顯示了M u l t i B y t e To Wi d e C h a r 函數。
int MultiByteToWideChar( UINT CodePage, //code page DWORD dwFlags, //character-type options LPCSTR lpMultiByteStr, //address of string to map int cchMultiByte, //number of bytes in string LPWSTR lpWideCharStr, //address of wide-character buffer int cchWideChar //size of buffer);
u C o d e P a g e 參數用於標識一個與多位元組字串相關的字碼頁號。d w F l a g s 參數用於設定另一個控制項,它可以用重音符號之類的區分標記來影響字元。這些標誌通常並不使用,在d w F l a g s參數中傳遞0 。p M u l t i B y t e S t r 參數用於設定要轉換的字串,c c h M u l t i B y t e 參數用於指明該字串的長度(按位元組計算)。如果為c c h M u l t i B y t e 參數傳遞- 1 ,那麼該函數用於確定源字串的長度。
轉換後產生的U n i c o d e 版本字串將被寫入記憶體中的緩衝,其地址由p Wi d e C h a r S t r 參數指定。必須在c c h Wi d e C h a r 參數中設定該緩衝的最大值(以字元為計量單位)。如果調用M u l t i B y t e To Wi d e C h a r ,給c c h Wi d e C h a r 參數傳遞0 ,那麼該參數將不執行字串的轉換,而是返回為使轉換取得成功所需要的緩衝的值。一般來說,可以通過下列步驟將多位元組字串轉換成U n i c o d e 等價字串:
1) 調用M u l t i B y t e To Wi d e C h a r 函數,為p Wi d e C h a r S t r 參數傳遞N U L L ,為c c h Wi d e C h a r 參數傳遞0 。
2) 分配足夠的記憶體塊,用於存放轉換後的U n i c o d e 字串。該記憶體塊的大小由前面對M u l t B y t e To Wi d e C h a r 的調用返回。
3) 再次調用M u l t i B y t e To Wi d e C h a r ,這次將緩衝的地址作為p Wi d e C h a r S t r 參數來傳遞,並傳遞第一次調用M u l t i B y t e To Wi d e C h a r 時返回的緩衝大小,作為c c h Wi d e c h a r 參數。
4. 使用轉換後的字串。
5) 釋放U n i c o d e 字串佔用的記憶體塊。
函數Wi d e C h a r To M u l t i B y t e 將寬字元串轉換成等價的多位元組字串,如下所示:
int WideCharToMultiByte( UINT CodePage, // code page DWORD dwFlags, // performance and mapping flags LPCWSTR lpWideCharStr, // address of wide-character string int cchWideChar, // number of characters in string LPSTR lpMultiByteStr, // address of buffer for new string int cchMultiByte, // size of buffer LPCSTR lpDefaultChar, // address of default for unmappable // characters LPBOOL lpUsedDefaultChar // address of flag set when default // char. used);
該函數與M u l t i B i t e To Wi d e C h a r 函數相似。同樣,u C o d e P a g e 參數用於標識與新轉換的字串相關的字碼頁。d w F l a g s 則設定用於轉換的其他控制項。這些標誌能夠作用於帶有區分符號的字元和系統不能轉換的字元。通常不需要為字串的轉換而擁有這種程度的控制手段,你將為d w F l a g s 參數傳遞0 。
p Wi d e C h a r S t r 參數用於設定要轉換的字串的記憶體位址,c c h Wi d e C h a r 參數用於指明該字串的長度(用字元數來計量)。如果你為c c h Wi d e C h a r 參數傳遞- 1 ,那麼該函數用於確定源字串的長度。
轉換產生的多位元組版本的字串被寫入由p M u l t i B y t e S t r 參數指明的緩衝。必須在c c h M u l t i B y t e參數中設定該緩衝的最大值(用位元組來計量)。如果傳遞0 作為Wi d e C h a r To M u l t i B y t e 函數的c c h M u l t i B y t e 參數,那麼該函數將返回目標緩衝需要的大小值。通常可以使用將多位元組字串轉換成寬位元組字串時介紹的一系列類似的事件,將寬位元組字串轉換成多位元組字串。
你會發現,Wi d e C h a r To M u l t i B y t e 函數接受的參數比M u l t i B y t e To Wi d e C h a r 函數要多2 個,即p D e f a u l t C h a r 和p f U s e d D e f a u l t C h a r 。只有當Wi d e C h a r To M u l t i B y t e 函數遇到一個寬位元組字元,而該字元在u C o d e P a g e 參數標識的字碼頁中並沒有它的標記法時,Wi d e C h a r To M u l t i B y t e 函數才使用這兩個參數。如果寬位元組字元不能被轉換,該函數便使用p D e f a u l t C h a r 參數指向的字元。如果該參數是N U L L (這是大多數情況下的參數值),那麼該函數使用系統的預設字元。該預設字元通常是個問號。這對於檔案名稱來說是危險的,因為問號是個萬用字元。
p f U s e d D e f a u l t C h a r 參數指向一個布爾變數,如果寬字元串中至少有一個字元不能轉換成等價多位元組字元,那麼函數就將該變數置為T R U E 。如果所有字元均被成功地轉換,那麼該函數就將該變數置為FA L S E 。當函數返回以便檢查寬位元組字串是否被成功地轉換後,可以測試該變數。同樣,通常為該測試傳遞N U L L 。
關於如何使用這些函數的詳細說明,請參見Platform SDK 文檔。
如果使用這兩個函數,就可以很容易建立這些函數的U n i c o d e 版本和A N S I 版本。例如,你可能有一個動態連結程式庫,它包含一個函數,能夠轉換字串中的所有字元。可以像下面這樣編寫該函數的U n i c o d e 版本:
BOOL StringReverseW(PWSTR pWideCharStr){ //Get a pointer to the last character in the string. PWSTR pEndOfStr=pWideCharStr+wcslen(pWideCharStr)-1; wchar_t cCharT; //Repeat until we reach the center character //in the string. while (pWideCharStr < pEndOfStr) { //Save a character in a temporary variable. cCharT=*pWideCharStr; //Put the last character in the first character. *pWideCharStr =*pEndOfStr; //Put the temporary character in the last character. *pEndOfStr=cCharT; //Move in one character from the left. pWideCharStr++; //Move in one character from the right. pEndOfStr--; } //The string is reversed; return success. return(TRUE);}
你可以編寫該函數的A N S I 版本以便該函數根本不執行轉換字串的實際操作。你也可以編寫該函數的A N S I 版本,以便該函數它將A N S I 字串轉換成U n i c o d e 字串,將U n i c o d e 字串傳遞給S t r i n g R e v e r s e W 函數,然後將轉換後的字串重新轉換成A N S I 字串。該函數類似下面的樣子:
BOOL StringReverseA(PSTR pMultiByteStr) { PWSTR pWideCharStr; int nLenOfWideCharStr; BOOL fOk = FALSE; //Calculate the number of characters needed to hold //the wide_character version of string. nLenOfWideCharStr = MultiRyteToWideChar(CP_ACP, 0, pMultiByteStr, -1, NULL, 0); //Allocate memory from the process's default heap to //accommodate the size of the wide-character string. //Don't forget that MultiByteToWideChar returns the //number of characters,not the number of bytes,so //you must multiply by the size of wide character. pWideCharStr = HeapAlloc(GetProcessHeap(), 0, nLenOfWideCharStr * sizeof(WCHAR)); if (pWideCharStr == NULL) return(fOk); //Convert the multibyte string to a wide_character string. MultiByteToWideChar(CP_ACP, 0, pMulti8yteStr, -1, pWideCharStr, nLenOfWideCharStr); //Call the wide-character version of this //function to do the actual work fOk = StnngReverseW(pWideCharStr); if (fOk) { //Convert the wide-character string back //to a multibyte string. WideCharToMultiByte(CP_ACP, 0, pWideCharStr, -1, pMultiByteStr, strlen(pMultiByteStr), NULL, NULL); } //Free the momory containing the wide-character string. HeapFree(GetProcessHeap(), 0, pWideCharStr); return(fOk),}
最後,在用動態連結程式庫分配的標頭檔中,可以像下面這樣建立這兩個函數的原型:
BOOL StringReverseW (PWSTR pWideCharStr);BOOL StringReverseA (PSTR pMultiByteStr);#ifdef UNICODE#define StnngReverse StringReverseW#else#define StringRevcrsc StringReverseA#endif // UNICODE