您的位置:首页 > 其它

MultiByteToWideChar和WideCharToMultiByte用法详解

2012-11-21 22:14 477 查看
本文转自:/article/2820505.html

//========================================================================

//TITLE:

// MultiByteToWideChar和WideCharToMultiByte用法详解

//AUTHOR:

// norains

//DATE:

// 第一版:Monday 25-December -2006

// 增补版:Wednesday 27-December -2006

// 修订版:Wednesday 14-March-2007 (修正之前的错误例子)

//Environment:

// EVC4.0 + Standard SDK

//========================================================================

1.使用方法详解

在本文开始之处,先简要地说一下何为短字符和宽字符.

所谓的短字符,就是用8bit来表示的字符,典型的应用是ASCII码.而宽字符,顾名思义,就是用16bit表示的字符,典型的有UNICODE.关于windows下的ASCII和UNICODE的更多信息,可以参考这两本经典著作:《windows 程序设计》,《windows 核心编程》.这两本书关于这两种字符都有比较详细的解说.

宽字符转换为多个短字符是一个难点,不过我们只要掌握到其中的要领,便可如鱼得水.

好吧,那就让我们开始吧.

这个是我们需要转化的多字节字符串:

char sText[20] = {"多字节字符串!OK!"};


我们需要知道转化后的宽字符需要多少个数组空间.虽然在这个里程里面,我们可以直接定义一个20*2宽字符的数组,并且事实上将运行得非常轻松愉快.但假如多字节字符串更多,达到上千个乃至上万个,我们将会发现其中浪费的内存将会越来越多.所以以多字节字符的个数的两倍作为宽字符数组下标的声明绝对不是一个好主意.

所幸,我们能够确知所需要的数组空间.

我们只需要将MultiByteToWideChar()的第四个形参设为-1,即可返回所需的短字符数组空间的个数:

DWORD dwNum = MultiByteToWideChar (CP_ACP, 0, sText, -1, NULL, 0);


接下来,我们只需要分配响应的数组空间:

wchar_t *pwText;
pwText = new wchar_t[dwNum];
if(!pwText)
{
delete []pwText;
}


接着,我们就可以着手进行转换了.在这里以转换成ASCII码做为例子:

MultiByteToWideChar (CP_ACP, 0, psText, -1, sText, dwSize);


【参数说明】

int MultiByteToWideChar(

  UINT CodePage,

  DWORD dwFlags,

  LPCSTR lpMultiByteStr,

  int cchMultiByte,

  LPWSTR lpWideCharStr,

  int cchWideChar

  );

第一个:指定执行转换的字符集,CP_ACP:ANSI字符集;

CP_UTF8:使用UTF-8转换 ;(还有其他,见百度百科)

第二个:一组未标记用以指出是否未转换成预作或宽字符(若组合形式存在),是否使用象形文字替代控制字符,以及如何处理无效字符。(不懂)

第三个:指向将被转换字符串的字符

第四个:指定由参数lpMultiByteStr指向的字符串中字节的个数。如果第三个参数指定的字符串以空字符终止,

可以设置为-1(如果字符串不是以空字符中止,设置为-1可能失败,可能成功),此参数设置为0函数将失败。

第五个:指向接收被转换字符串的缓冲区

最后一个:指定由参数第五个参数指向的缓冲区的字节数。若此值为零,函数返回缓冲区所必需的宽字符数,

在这种情况下,第五个参数中的缓冲区不被使用。

【返回值】

如果函数运行成功,并且cchWideChar不为零,返回值是由lpWideCharStr指向的缓冲区中写入的宽字符数;

如果函数运行成功,并且cchWideChar为零,返回值是接收到待转换字符串的缓冲区所需求的宽字符数大小。

如果函数运行失败,返回值为零。若想获得更多错误信息,请调用GetLastError函数。它可以返回下面所列错误代码

最后,使用完毕当然要记得释放占用的内存:

delete []psText;


同理,宽字符转为多字节字符的代码如下:

wchar_t wText[20] = {L"宽字符转换实例!OK!"};
DWORD dwNum = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
char *psText;
psText = new char[dwNum];
if(!psText)
{
delete []psText;
}
WideCharToMultiByte (CP_OEMCP,NULL,lpcwszStr,-1,psText,dwNum,NULL,FALSE);
delete []psText;

【WideCharToMultiByte参数说明】

int WideCharToMultiByte(

  UINT CodePage, //指定执行转换的代码页

  DWORD dwFlags,

  LPCWSTR lpWideCharStr, //指定的宽字节字符串的缓冲区

  int cchWideChar, //指定由参数lpWideCharStr指向的缓冲区的字符个数

  LPSTR lpMultiByteStr, //指向接收被转换字符串的缓冲区

  int cchMultiByte, //指定由参数lpMultiByteStr指向的缓冲区最大值

  LPCSTR lpDefaultChar,

  LPBOOL pfUsedDefaultChar

  );

7、只有当WideCharToMultiByte函数遇到一个宽字节字符,而该字符在uCodePage参数标识的代码页中并没有它的表示法时,WideCharToMultiByte函数才使用这两个

参数。如果宽字节字符不能被转换,该函数便使用lpDefaultChar参数指向的字符。如果该参数是NULL(这是大多数情况下的参数值),那么该函数使用系统的默认

字符。该默认字符通常是个问号。这对于文件名来说是危险的,因为问号是个通配符。

8、pfUsedDefaultChar参数指向一个布尔变量,如果Unicode字符串中至少有一个字符不能转换成等价多字节字符,那么函数就将该变量置为TRUE。如果所有字符均

被成功地转换,那么该函数就将该变量置为FALSE。当函数返回以便检查宽字节字符串是否被成功地转换后,可以测试该变量。

【返回值】

如果函数运行成功,并且cchMultiByte不为零,返回值是由 lpMultiByteStr指向的缓冲区中写入的字节数;

如果函数运行成功,并且cchMultiByte为零,返回值是接收到待转换字符串的缓冲区所必需的字节数。

如果函数运行失败,返回值为零。

如果之前我们已经分配好空间,并且由于字符串较短,可以不理会浪费的空间,仅仅只是想简单地将短字符和宽字符相互转换,那有没有什么简便的方法呢?

WIN32 API里没有符合这种要求的函数,但我们可以自己进行封装:

//-------------------------------------------------------------------------------------

//Description:

// This function maps a character string to a wide-character (Unicode) string

//

//Parameters:

// lpcszStr: [in] Pointer to the character string to be converted

// lpwszStr: [out] Pointer to a buffer that receives the translated string.

// dwSize: [in] Size of the buffer

//

//Return Values:

// TRUE: Succeed

// FALSE: Failed

//

//Example:

// MByteToWChar(szA,szW,sizeof(szW)/sizeof(szW[0]));

//---------------------------------------------------------------------------------------

BOOL MByteToWChar(LPCSTR lpcszStr, LPWSTR lpwszStr, DWORD dwSize)
{
// Get the required size of the buffer that receives the Unicode
// string.
DWORD dwMinSize;
dwMinSize = MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, NULL, 0);

if(dwSize < dwMinSize)
{
return FALSE;
}

// Convert headers from ASCII to Unicode.
MultiByteToWideChar (CP_ACP, 0, lpcszStr, -1, lpwszStr, dwMinSize);
return TRUE;
}


//-------------------------------------------------------------------------------------

//Description:

// This function maps a wide-character string to a new character string

//

//Parameters:

// lpcwszStr: [in] Pointer to the character string to be converted

// lpszStr: [out] Pointer to a buffer that receives the translated string.

// dwSize: [in] Size of the buffer

//

//Return Values:

// TRUE: Succeed

// FALSE: Failed

//

//Example:

// MByteToWChar(szW,szA,sizeof(szA)/sizeof(szA[0]));

//---------------------------------------------------------------------------------------

BOOL WCharToMByte(LPCWSTR lpcwszStr, LPSTR lpszStr, DWORD dwSize)
{
DWORD dwMinSize;
dwMinSize = WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,NULL,0,NULL,FALSE);
if(dwSize < dwMinSize)
{
return FALSE;
}
WideCharToMultiByte(CP_OEMCP,NULL,lpcwszStr,-1,lpszStr,dwSize,NULL,FALSE);
return TRUE;
}


使用方法也很简单,示例如下:

wchar_t wText[10] = {L"函数示例"};
char sText[20]= {0};
WCharToMByte(wText,sText,sizeof(sText)/sizeof(sText[0]));
MByteToWChar(sText,wText,sizeof(wText)/sizeof(wText[0]));


这两个函数的缺点在于无法动态分配内存,在转换很长的字符串时可能会浪费较多内存空间;优点是,在不考虑浪费空间的情况下转换较短字符串非常方便.

2.MultiByteToWideChar()函数乱码的问题

有的朋友可能已经发现,在标准的WinCE4.2或WinCE5.0 SDK模拟器下,这个函数都无法正常工作,其转换之后的字符全是乱码.及时更改MultiByteToWideChar()参数也依然如此.

不过这个不是代码问题,其结症在于所定制的操作系统.如果我们定制的操作系统默认语言不是中文,也会出现这种情况.由于标准的SDK默认语言为英文,所以肯定会出现这个问题.而这个问题的解决,不能在简单地更改控制面板的"区域选项"的"默认语言",而是要在系统定制的时候,选择默认语言为"中文".

系统定制时选择默认语言的位置于:

Platform -> Setting... -> locale -> default language ,选择"中文",然后编译即可.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: