Windows Unicode與字元集函數

來源:互聯網
上載者:User

近日閑來無事,前一陣子又被Unicode搞的焦頭爛額,於是想看看MSDN吧!英文的看起來真費勁,為了以後省點勁,翻譯總結了一下,備查。英文水平有限,如有出入,請參見MSDN。

第一個就是寬字元到多位元組字元轉換函式,函數原型如下:

int WideCharToMultiByt(   UINT CodePage,  DWORD dwFlags,  LPCWSTR lpWideCharStr,  int chWideChar,   LPSTR lpMultiByteStr,   int cbMultiByte,   LPCSTR lpDefaultChar,  LPBOOL lpUsedDefaultChar);

此函數把寬字元串轉換成指定的新的字串,如ANSI,UTF8等,新字串不必是多位元組字元集。
參數:

CodePage: 指定要轉換成的字元集字碼頁,它可以是任何已經安裝的或系統內建的字元集,你也可以使用如下所示字碼頁之一。

CP_ACP 當前系統ANSI字碼頁
CP_MACCP 當前系統Macintosh字碼頁
CP_OEMCP 當前系統OEM字碼頁,一種原始裝置製造商硬體掃描碼
CP_SYMBOL Symbol字碼頁,用於Windows 2000及以後版本,我不明白是什麼
CP_THREAD_ACP 當前線程ANSI字碼頁,用於Windows 2000及以後版本,我不明白是什麼
CP_UTF7 UTF-7,設定此值時lpDefaultChar和lpUsedDefaultChar都必須為NULL
CP_UTF8 UTF-8,設定此值時lpDefaultChar和lpUsedDefaultChar都必須為NULL

 

 

 

 

 

我想最常用的應該是CP_ACP和CP_UTF8了,前者將寬字元轉換為ANSI,後者轉換為UTF8。

dwFlags: 指定如何處理沒有轉換的字元, 但不設此參數函數會啟動並執行更快一些,我都是把它設為0。 可設的值如下表所示:

WC_NO_BEST_FIT_CHARS 把不能直接轉換成相應多位元組字元的Unicode字元轉換成lpDefaultChar指定的預設字元。也就是說,如果把Unicode轉換成多位元組字元,然後再轉換回來,你並不一定得到相同的Unicode字元,因為這期間可能使用了預設字元。此選項可以單獨使用,也可以和其他選項一起使用。
WC_COMPOSITECHECK  把合成字元轉換成預製的字元。它可以與後三個選項中的任何一個組合使用,如果沒有與他們中的任何一個組合,則與選項WC_SEPCHARS相同。
WC_ERR_INVALID_CHARS  此選項會致使函數遇到無效字元時失敗返回,並且GetLastError會返回錯誤碼ERROR_NO_UNICODE_TRANSLATION。否則函數會自動丟棄非法字元。此選項只能用於UTF8。
WC_DISCARDNS 轉換時丟棄不佔空間的字元,與WC_COMPOSITECHECK一起使用
WC_SEPCHARS  轉換時產生單獨的字元,此是預設轉換選項,與WC_COMPOSITECHECK一起使用
WC_DEFAULTCHAR  轉換時使用預設字元代替例外的字元,(最常見的如'?'),與WC_COMPOSITECHECK一起使用。

當指定WC_COMPOSITECHECK時,函數會將合成字元轉換成預製字元。合成字元由一個基字元和一個不佔空間的字元(如歐洲國家及漢語拼音的音標)組成,每一個都有不同的字元值。預製字元有一個用於表示基字元和不佔空間字元的合成體的單一的字元值。
當指定WC_COMPOSITECHECK選項時,也可以使用上表列出的最後3個選項來定製預製字元的轉換規則。這些選項決定了函數在遇到寬字元串的合成字元沒有對應的預製字元時的行為,他們與WC_COMPOSITECHECK一起使用,如果都沒有指定,函數預設WC_SEPCHARS。

對於下列字碼頁,dwFlags必須為0,否則函數返回錯誤碼ERROR_INVALID_FLAGS。

50220 50221 50222 50225 50227 50229 52936 54936 57002-57011 65000(UTF7) 42(Symbol)

對於UTF8,dwFlags必須為0或WC_ERR_INVALID_CHARS,否則函數都將失敗返回並設定錯誤碼ERROR_INVALID_FLAGS,你可以調用GetLastError獲得。

lpWideCharStr: 待轉換的寬字元串。

cchWideChar: 待轉換寬字元串的長度,-1表示轉換到字串結尾。

lpMultiByteStr: 接收轉換後輸出新串的緩衝區。

cbMultiByte: 輸出緩衝區大小,如果為0,lpMultiByteStr將被忽略,函數將返回所需緩衝區大小而不使用lpMultiByteStr。

lpDefaultChar: 指向字元的指標, 在指定編碼裡找不到相應字元時使用此字元作為預設字元代替。 如果為NULL則使用系統預設字元。對於要求此參數為NULL的dwFlags而使用此參數,函數將失敗返回並設定錯誤碼ERROR_INVALID_PARAMETER。

lpUsedDefaultChar:開關變數的指標,用以表明是否使用過預設字元。對於要求此參數為NULL的dwFlags而使用此參數,函數將失敗返回並設定錯誤碼ERROR_INVALID_PARAMETER。lpDefaultChar和lpUsedDefaultChar都設為NULL,函數會更快一些。

傳回值: 

如果函數成功,且cbMultiByte非0,返回寫入lpMultiByteStr的位元組數(包括字串結尾的null);cbMultiByte為0,則返迴轉換所需位元組數。函數失敗,返回0。

注意:

函數WideCharToMultiByte使用不當,會給影響程式的安全。調用此函數會很容易導致記憶體流失,因為lpWideCharStr指向的輸入緩衝區大小是寬字元數,而lpMultiByteStr指向的輸出緩衝區大小是位元組數。為了避免記憶體流失,應確保為輸出緩衝區指定合適的大小。我的方法是先使cbMultiByte為0調用WideCharToMultiByte一次以獲得所需緩衝區大小,為緩衝區分配空間,然後再次調用WideCharToMultiByte填充緩衝區,詳見下面的代碼。另外,從Unicode UTF16向非Unicode字元集轉換可能會導致資料丟失,因為該字元集可能無法找到表示特定Unicode資料的字元。

wchar_t* pwszUnicode = "Holle, word! 你好,中國!";
int iSize;
char* pszMultiByte;
iSize = WideCharToMultiByte(CP_ACP, 0, pwszUnicode, -1, NULL, 0, NULL, NULL);
pszMultiByte = (char*)malloc((iSize+1)/**sizeof(char)*/);
WideCharToMultiByte(CP_ACP, 0, pwszUnicode, -1, pszMultiByte, iSize, NULL, NULL);

第二個是多位元組字元到寬字元轉換函式,函數原型如下:
              int MultiByteToWideChar(
                            UINT CodePage,
                            DWORD dwFlags,
                            LPCSTR lpMultiByteStr,
                            int cbMultiByte,
                            LPWSTR lpWideCharStr,
                            int cchWideChar
              );

此函數把多位元組字串轉換成寬字元串(Unicode),待轉換的字串並不一定是多位元組的。

此函數的參數,傳回值及注意事項參見上面函數WideCharToMultiByte的說明,這裡只對dwFlags做簡單解釋。

dwFlags: 指定是否轉換成預製字元或合成的寬字元,對控制字元是否使用像形文字,以及怎樣處理無效字元。

   MB_PRECOMPOSED 總是使用預製字元,即有單個預製字元時,就不會使用分解的基字元和不佔空間字元。此為函數的預設選項,不能和MB_COMPOSITE合用
   MB_COMPOSITE 總是使用分解字元,即總是使用基字元+不佔空間字元的方式
   MB_ERR_INVALID_CHARS 設定此選項,函數遇到非法字元就失敗並返回錯誤碼ERROR_NO_UNICODE_TRANSLATION,否則丟棄非法字元
   MB_USEGLYPHCHARS 使用像形字元代替控制字元

對於下列字碼頁,dwFlags必須為0,否則函數返回錯誤碼ERROR_INVALID_FLAGS。
    50220 50221 50222 50225 50227 50229 52936 54936 57002到57011 65000(UTF7) 42(Symbol)
對於UTF8,dwFlags必須為0或MB_ERR_INVALID_CHARS,否則函數都將失敗並返回錯誤碼ERROR_INVALID_FLAGS。

以下函數我沒用過,只簡要說明之。

int GetTextCharset( HDC hdc );

此函數擷取當前選進的裝置描述表的字元集,等同於GetTextCharsetInfo(hdc, NULL, 0)。

傳回值: 成功返回字元集標識,失敗返回DEFAULT_CHARSET。

Windows定義的字元集標識有:
              ANSI_CHARSET
              BALTIC_CHARSET
              CHINESEBIG5_CHARSET
              DEFAULT_CHARSET
              EASTEUROPE_CHARSET
              GB2312_CHARSET
              GREEK_CHARSET
              HANGUL_CHARSET
              MAC_CHARSET
              OEM_CHARSET
              RUSSIAN_CHARSET
              SHIFTJIS_CHARSET
              SYMBOL_CHARSET
              TURKISH_CHARSET
              VIETNAMESE_CHARSET

              JOHAB_CHARSET(韓語版)
              ARABIC_CHARSET(中東版)
              HEBREW_CHARSET(中東版)
              THAI_CHARSET(泰國版)

int GetTextCharsetInfo(
               HDC hdc,

 

                LPFONTSIGNATURE lpSig,
                DWORD dwFlags
);

此函數擷取當前選進裝置描述表的字型的字元集資訊。

參數:
  lpSig:指向FONTSIGNATURE結構的指標。如果當前選進裝置的是TureType字型,函數會填充FONTSIGNATURE結構。否則FONTSIGNATURE結構被填充為0,而應使用TranslateCharsetInfo來擷取一般字元集資訊,如果你不需要字型標誌資訊,可將此參數設為NULL,此時相當於調用GetTextCharset。

  FONTSIGNATURE結構包括字碼頁和Unicode子域的資訊,Unicode子域是指定字型的字型輪廓。該結構定義如下:
typedef struct tagFONTSIGNATURE {
              DWORD fsUsb[4];
              DWORD fsCsb[2];
} FONTSIGNATURE, *PFONTSIGNATURE; 

fsUsb 是一個128位的Unicode子集標誌位(Unicode Subset Bitfield),用以標識最多126個Unicode子域。除了兩個最高有效位外,每一位代表一個子域。最高位總是1,表示此位是一個字型標誌,次高位保留,必須位0。Unicode子域根據ISO 10646標準制定。
fsCsb 是一個64位的字碼頁標誌位,用以標識制定的字元集或字碼頁。字碼頁由低32位標識,而高32位用於非Windows字碼頁。

dwFlags:保留,必須為0。
傳回值:成功返回字元集標識,失敗返回DEFAULT_CHARSET。

BOOL TranslateCharsetInfo(
              DWORD* pSrc,
              LPCHARSETINFO lpCs,
              DWORD dwFlags
);

此函數根據指定字元集,字碼頁或字型標識轉換並設定目標結體的值。
參數:
  lpSrc:如果dwFlags是TCI_SRCFONTSIG,此參數是FONTSIGNATURE結構的fsCsb成員地址,否則是一個DWORD值。
  lpCs: 指向要填充的CHARSETINFO結構。

CHARSETINFO結構定義如下:
typedef struct {
              UINT ciCharset; // 字元集標識
              UINT ciACP; // ANSI字碼頁標識
              FONTSIGNATURE fs;
} CHARSETINFO, *PCHARSETINFO;

dwFlags: 指定如何轉換。可以是下列標識之一:
TCI_SRCCHARSET       lpSrc的低字是字元集標識,高字為0
TCI_SRCCODEPAGE    lpSrc的低字是字碼頁標識,高字為0
TCI_SRCFONTSIG         lpSrc是FONTSIGNATURE的字碼頁標誌位部分,即FONTSIGNATURE的fsCsb成員地址
TCI_SRCLOCALE           lpSrc是鍵盤配置的LCID或LANGID,如果是LANGID,其值存在lpSrc的低字

BOOL IsDBCSLeadByte(BYTE TestChar);

此函數使用當前WindowsANSI字碼頁判斷指定位元組是不是一個潛在的雙位元組字元(DBCS)的引導位元組。若使用其他字碼頁,請用IsDBCSLeadByteEx函數。

BOOL IsDBCSLeadByteEx(
              UINT CodePage,
              BYTE TestChar
);

此函數判斷指定位元組是不是一個潛在的雙位元組字元(DBCS)的引導位元組。
CodePage可用的值有:CP_ACP,CP_MACCP,CP_OEMCP,CP_THREAD_ACP。 

BOOL IsTextUnicode(
              CONST VOID* pBuffer,
              int cb,
              LPINT lpi
);

此函數判斷指定緩衝區裡是否可能會有某種格式的Unicode文本。
參數:
lpi: 輸入時指明測試項,輸出時測試位返回各項測試結果:通過測試返回1,測試失敗返回0。如果為NULL,則函數會測試所有可能的項。它可以是以下值的一個或多個:
IS_TEXT_UNICODE_ASCII16 緩衝區文本是Unicode,並且僅有0擴充的ASCII字元
IS_TEXT_UNICODE_REVERSE_ASCII16 同上,只是Unicode文本是位元組翻轉的(與BOM有關)
IS_TEXT_UNICODE_STATISTICS 緩衝區文本可能是Unicode,由於它採用統計分析法,所以並不能確保準確
IS_TEXT_UNICODE_REVERSE_STATISTICS 同上,只是可能的Unicode文本是位元組翻轉的
IS_TEXT_UNICODE_CONTROLS 緩衝區文本含有Unicode表示的一個或多個非列印控制字元,如RETURN, LINEFEED, SPACE, CJK_SPACE, TAB。
IS_TEXT_UNICODE_REVERSE_CONTROLS 同上,只是Unicode字元是位元組翻轉的
IS_TEXT_UNICODE_BUFFER_TOO_SMALL 緩衝區裡的文本太少,不足以作出有意義的分析
IS_TEXT_UNICODE_SIGNATURE 緩衝區文本含有Unicode位元組順序碼(BOM)0XFEFF作為他的第一個字元
IS_TEXT_UNICODE_REVERSE_SIGNATURE 緩衝區文本含有Unicode反向位元組順序碼0XFFFE作為他的第一個字元
IS_TEXT_UNICODE_ILLEGAL_CHARS 緩衝區文本含有Unicode非法字元,如內嵌BOM,UNICODE_NUL,CRLF或0XFFFF
IS_TEXT_UNICODE_ODD_LENGTH 緩衝區字元數為奇數,Unicode字串長度都是偶數
IS_TEXT_UNICODE_NULL_BYTES 緩衝區含有null位元組,表示非ASCII文本
IS_TEXT_UNICODE_UNICODE_MASK IS_TEXT_UNICODE_ASCII16 | IS_TEXT_UNICODE_STATISTICS | IS_TEXT_UNICODE_CONTROLS | IS_TEXT_UNICODE_SIGNATURE
IS_TEXT_UNICODE_REVERSE_MASK IS_TEXT_UNICODE_REVERSE_ASCII16 | IS_TEXT_UNICODE_REVERSE_STATISTICS | IS_TEXT_UNICODE_REVERSE_CONTROLS | IS_TEXT_UNICODE_REVERSE_SIGNATURE.
IS_TEXT_UNICODE_NOT_UNICODE_MASK IS_TEXT_UNICODE_ILLEGAL_CHARS | IS_TEXT_UNICODE_ODD_LENGTH和兩個當前沒有使用的標誌位
IS_TEXT_UNICODE_NOT_ASCII_MASK IS_TEXT_UNICODE_NULL_BYTES 和三個當前沒有使用的標誌位

還有三個Windows不推薦使用的函數:
NlsDllCodePageTranslation,UnicodeToBytes和BytesToUnicode,這裡就不作介紹了。

PS:在VC中編譯定義了_UNICODE的代碼時經常會出現如下串連錯誤:

msvcrtd.lib(crtexew.obj) : error LNK2001: unresolved external symbol _WinMain @16 

Debug/Test.exe : fatal error LNK1120: 1 unresolved externals

解決辦法如下:

在Project->Settings->Link選項下選擇Output, 然後在Entry裡輸入:wWinMainCRTStartup即可。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.