前言
使用MultiByteToWideChar()和WideCharToMultiByte()函數進行ANSI和UNICODE轉換時,微軟推薦通過執行同一函數兩次,以確保轉換成功,第一次執行獲取保存轉換結果所需內存大小,根據其返回值申請一片內存,第二次才真正執行轉換。
MultiByteToWideChar() :返回值是確保轉換成功的寬字符數,因此申請空間時需要乘以sizeof(wchar_t)。
WideCharToMultiByte () :返回值直接是確保轉換成功所需的字節數,無需執行乘以sizeof操作;
具體實現可見示例代碼。
寬字符到多字節字符轉換函數
int WideCharToMultiByte(
UINT CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int cchWideChar,
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。
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
當指定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數據的字符。
多字節字符到寬字符轉換函數
函數原型如下:
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。
示例代碼
#include "iostream"
#include "windows.h"
using namespace std;
void main()
{
// UINCONDE to ANSI
wchar_t* pwszUnicode = L"Holle, word! 你好,中國! ";
int iSize;
char* pszMultiByte;
iSize = WideCharToMultiByte(CP_ACP, 0, pwszUnicode, -1, NULL, 0, NULL, NULL);
pszMultiByte = (char*)malloc((iSize)/**sizeof(char)*/);
WideCharToMultiByte(CP_ACP, 0, pwszUnicode, -1, pszMultiByte, iSize, NULL, NULL);
cout<<"UINCONDE to ANSI:"<<pszMultiByte<<endl;
// ANSI to UNICODE
locale loc( "chs" ); // 定義“區域設置”爲中文方式
wcout.imbue( loc ); // 載入中文字符輸入方式
char *pByteStr = "hello world! 你好,中國! ";
int iSize1;
wchar_t *pWideStr ;
iSize1 = MultiByteToWideChar(CP_ACP,0,pByteStr,-1,NULL,0);
pWideStr = (wchar_t*)malloc(iSize1*sizeof(wchar_t));
MultiByteToWideChar(CP_ACP,0,pByteStr,-1,pWideStr,iSize1*sizeof(wchar_t));
wcout<<"ANSI to UNICODE:"<<pWideStr<<endl;
system("pause");
}
參考資料
MultiByteToWideChar的與WideCharToMultiByte的參數詳解