简介
MultiByteToWideChar和WideCharToMultiByte这两个函数是Windows程序设计中用于字符串编码转换的函数。本文对MSDN中这两个函数的说明进行了翻译,水平有限,会有不少错误之处,欢迎指正!
MultiByteToWideChar
MultiByteToWideChar函数将其他类型的字符串转换为宽字符串(Unicode UTF-16)。被转换的字符串类型可以是多字节字符串以外的其他类型。
警告:不正确地使用MultiByteToWideChar函数将引发应用程序的安全问题。由于参数lpMultiByteStr所指向的输入字符串缓冲区的大小以字节为单位表示的,而参数lpWideCharStr所指向的输出字符串缓冲区大小以字符个数为单位,因而调用该函数容易因其缓冲区溢出错误。更多详细信息,请查看Security Considerations: International Features。
注意:不同的计算机系统所使用的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 [in]
编码转换过程中所使用的字符编码,该参数可以是系统中包含的任何字符编码。完整的字符编码列表请参见Code Page Identifiers。您的程序也可以指定下表中的一个值。
值 | 含义 |
---|---|
CP_ACP | 当前系统默认的Windows ANSI字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。 |
CP_MACCP | 当前系统的Macintosh字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。注意:由于现代的Macintosh计算机已经使用Unicode编码,因而该值仅适用于旧程序中。 |
CP_OEMCP | 当前系统的OEM字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。 |
CP_SYMBOL | Windows 2000及以上:Symbol code page (42). |
CP_THREAD_ACP | Windows 2000及以上:当前线程所使用的Windows ANSI字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。 |
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 [in]
用于指定转换类型的标记,可以设置为下表中不同值的组合。其中,MB_PRECOMPOSED为默认值。MB_PRECOMPOSED和MB_COMPOSITE是互斥关系,不能同时使用。MB_USEGLYPHCHARS和MB_ERR_INVALID_CHARS可以同其他值一同指定。
值 | 含义 |
---|---|
MB_COMPOSITE | 总是使用可分解字符。也就是说,组成可分解字符的基本字符以及其他组合字符用单独的码位表示。例如Ä可以表示为A + ¨:LATIN CAPITAL LETTER A (U+0041) + COMBINING DIAERESIS (U+0308)。需要注意的是该值不能与MB_PRECOMPOSED一起使用。 |
MB_ERR_INVALID_CHARS | 当遇到无效字符时转换失败。需要注意的是:如果未设定该值,Windows Vista及之后的系统在执行函数时将不会丢弃无效码位。而在Windows 2000 SP4以上和Windows XP中如果未设定该值将自动丢弃无效码位。调用函数GetLastError返回ERROR_NO_UNICODE_TRANSLATION。 |
MB_PRECOMPOSED | 该值为默认值,并且不能和MB_COMPOSITE一起使用,表示总是使用预组字符。也就是说,由基本字符和组合字符合成的字符拥有自己独立的码位。例如Ä直接用单独的Unicode码位LATIN CAPITAL LETTER A WITH DIAERESIS (U+00C4)表示,而不是使用LATIN CAPITAL LETTER A (U+0041) + COMBINING DIAERESIS (U+0308)的组合来表示。 |
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 [in]
指向被转换字符串的指针。
cbMultiByte [in]
被转换字符串的长度,以字节为单位。当字符串以NULL结尾时,该值可以设为-1。需要注意的是,当该值为0时,函数将执行失败。
当该参数被设为-1时,该函数将处理包含结尾NULL字符在内的整个字符串,同时返回包含结尾NULL字符在内的整个字符串的长度。
如果该值被设定为正整数,该函数仅处理整数所指定的字节内的字符。如果给定的长度内不包含结尾的NULL字符,则转换后的Unicode字符串也不以NULL结尾。
lpWideCharStr [out, optional]
指向接收转换后的字符串的指针。
cchWideChar [in]
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编码。
备注
函数转化后的字符串默认为预组字符形式,如果字符的预组编码不存在,函数将试着转化为非预组形式,即基本字符加组合字符的形式。
由于在大多数字符编码中,字符一般被编码为预组形式,因而MB_PRECOMPOSED标志对函数转换的影响并不大。如果想获取更为精确、标准的字符串编码,请在调用MultiByteToWideChar函数后继续调用NormalizeString函数。需要注意的是,对于传递给NormalizeString的NORM_FORM参数,指定为NormalizationC等价于MB_PRECOMPOSED,指定为NormalizationD等价于MB_COMPOSITE。
为了避免缓冲区溢出错误,在使用该函数进行编码转换之前,请先调用一次该函数并将cchWideChar参数设为0以获取转换后的字符串的长度。如果设置了MB_COMPOSITE标志,转换后的每一个字符的长度可能相当于三个字符或更长。
传递给参数lpMultiByteStr和lpWideCharStr的指针不能相同,否则函数会执行失败,同时调用GetLastError函数后返回ERROR_INVALID_PARAMETER。
如果参数cbMultiByte指定的长度不包含被转换字符串末尾的NULL,该函数转换后的字符串也不以NULL结尾。如果需要转换后的字符串以NULL结尾,请将参数cbMultiByte指定为-1或者其表示的字符串长度包含结尾的NULL。
如果参数dwFlags被设置为MB_ERR_INVALID_CHARS并且在转换时遇到无效字符,转换将失败。无效字符是指下列字符中的一种:
- 一个字符不是被转换字符的默认字符,当MB_ERR_INVALID_CHARS未设置时会被转换为默认字符
- 对于双字节字符,一个字符只包含头字节而没有尾字节
从Windows Vista系统开始,该函数对于UTF-8和UTF-16完全遵守Unicode 4.1规范,而在早期的操作系统中该函数将对编码错误的字符进行转换。因此如果基于早期操作系统编写的代码中如果包含了对无效数据的转换,在新的系统中转换将发生错误。
Windows XP:为了防止UTF-8的非最短形式编码导致的安全问题,MultiByteToWideChar函数移除了这些字符。
Windows 8及以上:MultiByteToWideChar函数在头文件Stringapiset.h中声明,在Windows 8之前,他声明在Winnls.h中。
环境要求
环境 | 最低配置 |
---|---|
桌面 | Windows 2000 Professional |
服务器 | Windows 2000 Server |
手机 | Windows Phone 8 |
头文件 | Stringapiset.h (include Windows.h) |
静态链接库 | Kernel32.lib |
动态链接库 | Kernel32.dll |
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 [in]
编码转换过程中所使用的字符编码,该参数可以是系统中包含的任何字符编码。完整的字符编码列表请参见Code Page Identifiers。您的程序也可以指定下表中的一个值。
值 | 含义 |
---|---|
CP_ACP | 当前系统默认的Windows ANSI字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。 |
CP_MACCP | 当前系统的Macintosh字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。注意:由于现代的Macintosh计算机已经使用Unicode编码,因而该值仅适用于旧程序中。 |
CP_OEMCP | 当前系统的OEM字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。 |
CP_SYMBOL | Windows 2000及以上:Symbol code page (42). |
CP_THREAD_ACP | Windows 2000及以上:当前线程所使用的Windows ANSI字符编码。该值在不同的计算机中可能不同,即使这些计算机位于同一网络中。在同一台计算机上,该值也可能被更改从而导致存储数据发生不可恢复的错误。该值不适用于数据的永久性保存,仅适合临时性存储使用,永久性保存数据请使用UTF-16或UTF-8编码。 |
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 [in]
用于指定转换类型的标记,可以设置为下表中不同值的组合。当该参数没有设为任何值时,函数执行速度将变快。应用程序应指定WC_NO_BEST_FIT_CHARS、WC_COMPOSITECHECK和WC_DEFAULTCHAR标志以检索所有可能的转换结果。如果没有指定这三个值,将会丢失部分结果。
值 | 含义 |
---|---|
WC_COMPOSITECHECK | 将可分解字符转换为预组字符。**注意:**Windows系统一般采用预组字符,因而WC_COMPOSITECHECK标志并不是必须的。 |
WC_ERR_INVALID_CHARS | Windows Vista及以上:当该值被设置时,遇到无效字符将停止转换。若该值未设置,将丢弃无效字符,同时调用GetLastError 函数返回ERROR_NO_UNICODE_TRANSLATION。需要注意的时,仅当字符编码被指定为CP_UTF8或54936时才能使用该值(Windows Vista及以上)。 |
WC_NO_BEST_FIT_CHARS | 如果字符从Unicode编码转换为多字节编码,然后再转换回Unicode编码后与原来的字符不相同,则函数使用lpDefaultChar参数中的相应字符。该值可以与其他标志一起使用。对于需要验证的字符串,例如文件,资源和用户名,应用程序应始终使用WC_NO_BEST_FIT_CHARS标志。该标志防止该函数将字符转换到看似相似但实际含义却不相同的字符。在某些情况下,这些字符的含义差别可能很大。例如,在某些字符集中∞(无穷大)符号可能转换为8。 |
您可以将WC_COMPOSITECHECK标志与一下任意标志相结合。其中,WC_SEPCHARS是默认的,即没有指定以下任一标志时,默认提供WC_SEPCHARS标志。这些标志用于告诉函数在某些字符没有预组形式的编码时如何进行转换。更多详细信息,请查看备注中WC_COMPOSITECHECK及相关标志小节。
- WC_DEFAULTCHAR:用默认字符替换转换中出现异常的字符。
- WC_DISCARDNS:转换过程中忽略组合字符。
- WC_SEPCHARS:默认值,转换过程中生成独立的字符。
对于以下字符编码,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。
lpWideCharStr [in]
指向待转换的Unicode字符串的指针。
cchWideChar [in]
lpWideCharStr指针所指向的字符串的字符个数。如果字符串以NULL结尾,则可以将该参数设为-1。如果cchWideChar设置为0,则函数执行失败。如果该参数为-1,则函数处理整个输入字符串,包括结尾的空字符。因此,生成的字符串包含结尾的空字符,函数返回包含空字符的字符串长度。如果该参数设为正整数,则函数将精确处理指定的字符数。如果提供的大小不包括结尾的空字符,则生成的字符串不是以空字符结尾,并且返回的长度不包括空字符。
lpMultiByteStr [out, optional]
指向接收转换字符串的缓冲区。
cbMultiByte [in]
lpMultiByteStr指针指向的缓冲区大小(以字节为单位)。如果此参数设置为0,则该函数返回lpMultiByteStr所需的缓冲区大小,并且使lpMultiByteStr参数无效。
lpDefaultChar [in, optional]
如果字符无法在指定的字符编码中表示,则使用该指针指向的字符。如果需要函数使用系统提供的默认值,则应将此参数设为NULL。应用程序可以调用GetCPInfo或GetCPInfoEx函数获取系统默认字符。
如果CodePage参数设为CP_UTF7或CP_UTF8,此参数必须设置为NULL。否则,该函数将失败,并显示ERROR_INVALID_PARAMETER。
对于CodePage的CP_UTF7和CP_UTF8设置,此参数必须设置为NULL。 否则,函数将执行失败,调用GetLastError函数显示ERROR_INVALID_PARAMETER。
lpUsedDefaultChar [out, optional]
指向一个标志的指针,该标志表明函数是否在转换中使用了默认字符。如果源字符串中的一个或多个字符不能在指定的字符编码中表示,则该标志设置为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字符。
备注
参数lpMultiByteStr与lpWideCharStr不能相同,否则函数将执行失败,调用GetLastError返回ERROR_INVALID_PARAMETER。
如果参数cchWideChar指定的长度不包含结尾的空字符,则WideCharToMultiByte函数不会自动为转换后的字符串结尾添加空字符。如果要使转换后的字符串包含结尾的空字符,应该将该参数指定为-1或者其指定的长度包含源字符串中的空字符。
如果cbMultiByte小于cchWideChar,则函数将cbMultiByte指定的字符数写入lpMultiByteStr指向的缓冲区。但是,如果CodePage设置为CP_SYMBOL,并且cbMultiByte小于cchWideChar,则该函数不会向lpMultiByteStr写入任何字符。
当lpDefaultChar和lpUsedDefaultChar都设置为NULL时,WideCharToMultiByte函数运行更快。下表显示了这两个参数的四种可能组合所产生的效果。
lpDefaultChar | lpUsedDefaultChar | Result |
---|---|---|
NULL | NULL | 没有默认检查。此种方式下函数运行最快。 |
Non-null character | NULL | 使用指定的默认字符,但不设置lpUsedDefaultChar。 |
NULL | Non-null character | 使用系统默认字符,并在需要时设置lpUsedDefaultChar。 |
Non-null character | Non-null character | 使用指定的默认字符,并在必要时设置lpUsedDefaultChar。 |
从Windows Vista系统开始,该函数完全遵守UTF-8和UTF-16的Unicode 4.1规范,而在早期的操作系统中该函数将对编码错误的字符进行转换。因此如果基于早期操作系统编写的代码中如果包含了对无效数据的转换,在新的系统中转换将发生错误。
Windows 8及以上:MultiByteToWideChar函数在头文件Stringapiset.h中声明,在Windows 8之前,他声明在Winnls.h中。
WC_COMPOSITECHECK and related flags
Unicode规范允许同一字符串有多种表示方式。例如,字符Ä可以表示为单个Unicode码位(U + 00C4),或者分解为大写字母“A”和组合字符“¨”(U + 0041 U + 0308)。但是,大多数代码页只提供组合字符。
WC_COMPOSITECHECK标志使WideCharToMultiByte函数尝试在转换之前先将可分解字符转换为预组字符。测试分解的Unicode字符,并尝试在将它们转换为请求的代码页之前进行撰写。 该标志仅适用于转换为单字节(SBCS)或双字节(DBCS)字符编码(字符编码<50000,不包括代码页42)的情况。如果您的应用程序需要将可分解的Unicode字符转换为单字节或双字节字符编码,则此标志可能很有用。 然而,并不是所有的字符都可以这样转换,将数据存储为Unicode编码更为可靠。
当程序使用WC_COMPOSITECHECK标志时,某些字符组合在转换后会导致不完整或留下多余的组合字符。 例如,A +¨+¨组合成Ä+¨。使用WC_DISCARDNS标志会导致该函数丢弃附加的¨字符。使用WC_DEFAULTCHAR标志,该函数使用默认的替换字符(通常为“?”)。使用WC_SEPCHARS标志使该函数尝试将每个附加的组合字符转换为目标字符编码中的字符,通常该标志也会导致函数使用替换字符(“?”)。 但是,对于字符集1258(越南)和20269,组合字符存在并可以使用。对于这些字符集的转换并不完美。某些字符组合在1258字符编码中不能正确地转换,同时WC_COMPOSITECHECK会破坏字符编码20269中的数据。应用程序以Unicode编码保存数据更为可靠。
环境要求
环境 | 最低配置 |
---|---|
桌面 | Windows 2000 Professional |
服务器 | Windows 2000 Server |
手机 | Windows Phone 8 |
头文件 | Stringapiset.h (include Windows.h) |
静态链接库 | Kernel32.lib |
动态链接库 | Kernel32.dll |