MultiByteToWideChar
MultiByteToWideChar函数将其他类型的字符串转换为宽字符串(Unicode UTF-16)。被转换的字符串类型可以是多字节字符串以外的其他类型。
不正确地使用MultiByteToWideChar函数将引发应用程序的安全问题。由于参数lpMultiByteStr所指向的输入字符串缓冲区的大小以字节为单位表示的,而参数lpWideCharStr所指向的输出字符串缓冲区大小以字符个数为单位,因而调用该函数容易因其缓冲区溢出错误。
不同的计算机系统所使用的ANSI字符编码可能并不相同,并且用户可以对系统使用的ANSI字符编码进行更改从而导致数据错误。为了保证数据的一致性,应用程序应统一使用Unicode编码,例如UTF-8(字符编码65001)或UTF-16。在某些情况下用户可能无法使用Unicode对数据进行编码,此时如果数据传输协议支持则应用程序应该标记数据所使用的编码名称。HTML、XML和HTTP文件支持标记编码格式,普通的文本文件则不支持编码标记。
函数的声明定义:
int MultiByteToWideChar(
_In_ UINT CodePage,
_In_ DWORD dwFlags,
_In_ LPCSTR lpMultiByteStr,
_In_ int cbMultiByte,
_Out_opt_ LPWSTR lpWideCharStr,
_In_ int cchWideChar
);
参数列表:
参数 | 类型描述 |
---|---|
CodePage | 指定要转换成的字符集代码页,可以是任何已经安装或系统自带的字符集,也可以使用如下所示代码页之一。 CP_ACP: 当前系统默认的Windows ANSI字符编码。 CP_MACCP: 当前系统的Macintosh字符编码 CP_OEMCP: 当前系统的OEM字符编码 CP_SYMBOL: Windows 2000及以上:Symbol code page (42) CP_THREAD_ACP: Windows 2000及以上:当前线程所使用的Windows ANSI字符编码 CP_UTF7: Windows 98/Me, Windows NT 4.0及以上:UTF-7。仅当使用7-bit传输技术时指定该值,一般情况下首选UTF-8 CP_UTF8: Windows 98/Me, Windows NT 4.0及以上:UTF-8 |
dwFlags | 用于指定转换类型的标记,可以设置为下表中不同值的组合。其中,MB_PRECOMPOSED为默认值。MB_PRECOMPOSED和MB_COMPOSITE是互斥关系,不能同时使用。MB_USEGLYPHCHARS和MB_ERR_INVALID_CHARS可以同其他值一同指定。 MB_COMPOSITE: 总是使用可分解字符。组成可分解字符的基本字符以及其他组合字符用单独的码位表示 MB_ERR_INVALID_CHARS: 当遇到无效字符时转换失败 MB_PRECOMPOSED:该值为默认值,并且不能和MB_COMPOSITE一起使用,表示总是使用预组字符 MB_USEGLYPHCHARS: 使用象形字符替代控制字符 对于以下字符编码,dwFlags必须设为0。否则函数将执行失败并返回ERROR_INVALID_FLAGS。 50220、50221、50222、50225、50227、50229、57002 through 57011、65000(UTF-7)、 42(Symbol) 注意:对于UTF-8或字符编码54936(GB18030,Windows Vista及以上),dwFlags应设为0或MB_ERR_INVALID_CHARS,否则函数将返回ERROR_INVALID_FLAGS。 |
lpMultiByteStr | 指向被转换字符串的指针。 |
cbMultiByte | 被转换字符串的长度,以字节为单位。当字符串以NULL结尾时,该值可以设为-1。 需要注意的是,当该值为0时,函数将执行失败。 当该参数被设为-1时,该函数将处理包含结尾NULL字符在内的整个字符串,同时返回包含结尾NULL字符在内的整个字符串的长度。如果该值被设定为正整数,该函数仅处理整数所指定的字节内的字符。如果给定的长度内不包含结尾的NULL字符,则转换后的Unicode字符串也不以NULL结尾。 |
lpWideCharStr | 指向接收转换后的字符串的指针。 |
cchWideChar | lpWideCharStr指针所指向的缓冲区所能容纳的字符数。如果该值被设为0,函数将返回存放转换后的字符串(包含结尾NULL字符在内)所需要的的缓冲区大小,即缓冲区所应容纳的字符数量。当该值设为0时,lpWideCharStr参数将不起作用。 |
返回值 | 如果参数cchWideChar不为0且函数执行成功时,返回值为写入参数lpWideCharStr所指向的缓冲区的字符数量。如果参数cchWideChar为0且函数执行成功时,返回值为转换后的字符串的字符数量(包含结尾NULL字符在内)。无效字符将被转换为U+FFFD。 如果执行失败,函数将返回0。如果想获取有关错误的详细信息,请调用GetLastError函数,该函数会返回以下错误值。 ERROR_INSUFFICIENT_BUFFER:lpWideCharStr参数提供的缓冲区不足以容纳转换后的字符,或者lpWideCharStr参数为NULL导致函数无法存放转换后的字符串。 ERROR_INVALID_FLAGS:传递给参数dwFlags的值无效。 ERROR_INVALID_PARAMETER:传递给函数的参数中包含无效参数。 ERROR_NO_UNICODE_TRANSLATION:传递给函数的字符串中包含无效Unicode编码。 |
代码示例:
DWORD UTF8ToUnicodeOper:: transCode(byte *utf8Buf,byte *unicodeBuf,DWORD len)
{
char *lpUTF8Buf=(char*)utf8Buf;
WCHAR *lpUnicodeBuf=(WCHAR*)unicodeBuf;
DWORD nRetLen = 0;
if(!lpUTF8Buf)
return 0;
nRetLen = ::MultiByteToWideChar(CP_UTF8,NULL,lpUTF8Buf,len,NULL,0);
if(nRetLen>1024*10)
{
setLastErrInfo("一行超过10K");
LOG4CPLUS_ERROR(logger,m_lastErrInfo);
return -1;
}
memset(lpUnicodeBuf,0,nRetLen);
nRetLen = ::MultiByteToWideChar(CP_UTF8,NULL,lpUTF8Buf,len,lpUnicodeBuf,nRetLen);
if(!nRetLen)
{
DWORD e = GetLastError();
setLastErrInfo("转码失败,错误原因:"+e);
LOG4CPLUS_ERROR(logger,m_lastErrInfo);
return -1;
}
lpUnicodeBuf[nRetLen] = '\0';
return 2*nRetLen;
}
WideCharToMultiByte
将宽字符串(UTF-16)转化为其他字符编码类型的字符串。
警告:不正确地使用WideCharToMultiByte函数将引发应用程序的安全问题。由于参数lpWideCharStr所指向的输入字符串缓冲区大小以字符个数为单位表示的,而参数lpMultiByteStr所指向的输出字符串缓冲区的大小以字节为单位,因而调用该函数容易因其缓冲区溢出错误。为了防止缓冲区溢出,您的程序应该指定足够的缓冲区大小以容纳转换后的数据类型。
从UTF-16编码转换为非Unicode编码时有可能发生数据丢失,因为某些字符编码可能无法完整地表示Unicode编码中的每一个字符。更多详细信息,请查看Security Considerations: International Features。
注意:不同的计算机系统所使用的ANSI字符编码可能并不相同,并且用户可以对系统使用的ANSI字符编码进行更改从而导致数据错误。为了保证数据的一致性,应用程序应统一使用Unicode编码,例如UTF-8(字符编码65001)或UTF-16。在某些情况下用户可能无法使用Unicode对数据进行编码,此时如果数据传输协议支持则应用程序应该标记数据所使用的编码名称。HTML、XML和HTTP文件支持标记编码格式,普通的文本文件则不支持编码标记。
函数的声明定义:
int WideCharToMultiByte(
_In_ UINT CodePage,
_In_ DWORD dwFlags,
_In_ LPCWSTR lpWideCharStr,
_In_ int cchWideChar,
_Out_opt_ LPSTR lpMultiByteStr,
_In_ int cbMultiByte,
_In_opt_ LPCSTR lpDefaultChar,
_Out_opt_ LPBOOL lpUsedDefaultChar
);
参数列表:
参数 | 类型描述 |
---|---|
CodePage | 指定要转换成的字符集代码页,可以是任何已经安装或系统自带的字符集,也可以使用如下所示代码页之一。 CP_ACP: 当前系统默认的Windows ANSI字符编码。 CP_MACCP: 当前系统的Macintosh字符编码 CP_OEMCP: 当前系统的OEM字符编码 CP_SYMBOL: Windows 2000及以上:Symbol code page (42) CP_THREAD_ACP: Windows 2000及以上:当前线程所使用的Windows ANSI字符编码 CP_UTF7: Windows 98/Me, Windows NT 4.0及以上:UTF-7。仅当使用7-bit传输技术时指定该值,一般情况下首选UTF-8。当参数CodePage设置为该值时,lpDefaultChar参数与lpUsedDefaultChar参数必须设为NULL。 CP_UTF8: Windows 98/Me, Windows NT 4.0及以上:UTF-8。当参数CodePage设置为该值时,lpDefaultChar参数与lpUsedDefaultChar参数必须设为NULL。 |
dwFlags | 用于指定转换类型的标记,可以设置为下表中不同值的组合。当该参数没有设为任何值时,函数执行速度将变快。应用程序应指定WC_NO_BEST_FIT_CHARS、WC_COMPOSITECHECK和WC_DEFAULTCHAR标志以检索所有可能的转换结果。如果没有指定这三个值,将会丢失部分结果。 WC_COMPOSITECHECK: 将可分解字符转换为预组字符。 WC_ERR_INVALID_CHARS: 当该值被设置时,遇到无效字符将停止转换。 WC_NO_BEST_FIT_CHARS: 如果字符从Unicode编码转换为多字节编码,然后再转换回Unicode编码后与原来的字符不相同,则函数使用lpDefaultChar参数中的相应字符。该值可以与其他标志一起使用。 您可以将WC_COMPOSITECHECK标志与一下任意标志相结合。其中,WC_SEPCHARS是默认的,即没有指定以下任一标志时,默认提供WC_SEPCHARS。这些标志用于告诉函数在某些字符没有预组形式的编码时如何进行转换。 |
lpWideCharStr | 指向待转换的Unicode字符串的指针。 |
cchWideChar | lpWideCharStr指针所指向的字符串的字符个数。如果字符串以NULL结尾,则可以将该参数设为-1。如果cchWideChar设置为0,则函数执行失败。如果该参数为-1,则函数处理整个输入字符串,包括结尾的空字符。因此,生成的字符串包含结尾的空字符,函数返回包含空字符的字符串长度。如果该参数设为正整数,则函数将精确处理指定的字符数。如果提供的大小不包括结尾的空字符,则生成的字符串不是以空字符结尾,并且返回的长度不包括空字符。 |
lpMultiByteStr | 指向接收转换字符串的缓冲区。 |
cbMultiByte | lpMultiByteStr指针指向的缓冲区大小(以字节为单位)。如果此参数设置为0,则该函数返回lpMultiByteStr所需的缓冲区大小,并且使lpMultiByteStr参数无效。 |
lpDefaultChar | 如果字符无法在指定的字符编码中表示,则使用该指针指向的字符。如果需要函数使用系统提供的默认值,则应将此参数设为NULL。应用程序可以调用GetCPInfo或GetCPInfoEx函数获取系统默认字符。 如果CodePage参数设为CP_UTF7或CP_UTF8,此参数必须设置为NULL。否则,该函数将失败,并显示ERROR_INVALID_PARAMETER。 对于CodePage的CP_UTF7和CP_UTF8设置,此参数必须设置为NULL。 否则,函数将执行失败,调用GetLastError函数显示ERROR_INVALID_PARAMETER。 |
lpUsedDefaultChar | 指向一个标志的指针,该标志表明函数是否在转换中使用了默认字符。如果源字符串中的一个或多个字符不能在指定的字符编码中表示,则该标志设置为TRUE。否则,该标志设置为FALSE。该参数可以设置为NULL。 对于CodePage的CP_UTF7和CP_UTF8设置,此参数必须设置为NULL。 否则,函数将执行失败,调用GetLastError函数显示ERROR_INVALID_PARAMETER。 |
返回值 | 如果成功,返回由lpMultiByteStr指向的缓冲区的字节数。 如果参数cbMultiByte为0,并且函数执行成功,则返回值是lpMultiByteStr所指向的缓冲区的大小(以字节为单位)。如果输入字节/字符序列无效,则返回U + FFFD的UTF编码。 如果函数执行失败则返回0。如果要获取有关错误的详细信息,可以调用GetLastError,它可以返回以下错误代码之一: ERROR_INSUFFICIENT_BUFFER:所提供的缓冲区大小不够,或者其被设置为NULL。 ERROR_INVALID_FLAGS:为参数dwFlags提供的值无效。 ERROR_INVALID_PARAMETER:包含无效参数。 ERROR_NO_UNICODE_TRANSLATION:待转换字符串包含无效Unicode字符。 |
代码示例:
DWORD UnicodeToUTF8Oper:: transCode(byte *unicodeBuf,byte *utf8Buf,DWORD len)
{
char *lpUTF8Buf=(char*)utf8Buf;
wchar_t *lpUnicodeBuf=(wchar_t*)unicodeBuf;
DWORD nRetLen = 0;
DWORD nUTF8StrLen = 0;
if(!lpUnicodeBuf)
return 0;
len=len/sizeof(wchar_t);
nRetLen = ::WideCharToMultiByte(CP_UTF8,0,lpUnicodeBuf,len,NULL,0,NULL,NULL);
if(nRetLen>1024*10)
{
setLastErrInfo("一行超过10K");
LOG4CPLUS_ERROR(logger,m_lastErrInfo);
return -1;
}
memset(lpUTF8Buf,0,nRetLen);
nRetLen = ::WideCharToMultiByte(CP_UTF8,0,lpUnicodeBuf,len,lpUTF8Buf,nRetLen,NULL,NULL);
if(!nRetLen)
{
DWORD e = GetLastError();
setLastErrInfo("转码失败,错误原因:"+e);
LOG4CPLUS_ERROR(logger,m_lastErrInfo);
return -1;
}
return nRetLen;
}
代码地址
见github(代码、设计文档及测试文件):https://github.com/CheerForU/TransCodeTool