VS新版本打开旧项目,即当升级一个vcproject文件时,可能会涉及从“多字节字符集”(可能是utf-8)到unicode字符集的转换。
所以总结一下,代码端如何适应转换。
unicode字符集下,微软引入了一个宽字符集的概念(多讨厌)
所以,有些winapi就是以宽字符集来传参的。
第一类问题:
- messagebox()函数
所以字符串常量前,加一个L,即L“原来的字符串”;
L的意思是小端序。当为unicode时,长度要么1要么2(汉字),所以,再加上小端序,不会有歧义了。
第二类问题:
- strcpy()函数要求多字符集
事实此时的CSting已经入乡随俗了用了宽字符集,而直接强制转换就会出现让你头大的提示,
居然const char * 和 CString不等价了。
1 | char SendBuf[512] = {0}; |
办法一:用新的缓冲区放置,并且必须再转换一下。1
2char SendBuf[512] = {0};
strcpy(SendBuf,( const char *)strEdit.GetBuffer());
办法二:复杂,此时要做的是把“变质的”CString给救回来。1
2
3
4
5char SendBuf[512] = {0};
wchar_t temp[512];
MultiByteToWideChar(CP_ACP, NULL, (LPCCH)strEdit.GetBuffer(), 512, temp, 512);
strcpy(SendBuf,(const char *)temp);
m_Conn.Send(SendBuf,strlen(SendBuf));
第三类问题
- atoi转int:
把atoi换成_ttoi即可,这是神器,在啥字符集下,都可编译。
第四类问题
- CString->std::string 举例如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17CString strMfc=“test“;
std::string strStl;
#ifdef _UNICODE
USES_CONVERSION
strStl=W2A(strMfc.LockBuffer());
strMfc.UnlockBuffer();
#else
strStl = strMfc.GetBuffer(0);
strMfc.ReleaseBuffer();
#endif
有时,CString可以做为桥梁,把乱码的UTF-8字符串转成string打印正确。思路是先用下面的函数转换乱码,再把返回的CString转string.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49CString UTF8toUnicode(const char* utf8Str, UINT length)
{
CString unicodeStr;
unicodeStr = _T("");
if (!utf8Str)
return unicodeStr;
if (length == 0)
return unicodeStr;
//转换
WCHAR chr = 0;
for (UINT i = 0; i<length;)
{
if ((0x80 & utf8Str[i]) == 0) // ASCII
{
chr = utf8Str[i];
i++;
}
else if ((0xE0 & utf8Str[i]) == 0xC0) // 110xxxxx 10xxxxxx
{
chr = (utf8Str[i + 0] & 0x3F) << 6;
chr |= (utf8Str[i + 1] & 0x3F);
i += 2;
}
else if ((0xF0 & utf8Str[i]) == 0xE0) // 1110xxxx 10xxxxxx 10xxxxxx
{
chr = (utf8Str[i + 0] & 0x1F) << 12;
chr |= (utf8Str[i + 1] & 0x3F) << 6;
chr |= (utf8Str[i + 2] & 0x3F);
i += 3;
}
else // 不是UTF-8字符串
{
return unicodeStr;
}
unicodeStr.AppendChar(chr);
}
return unicodeStr;
}
CString UTF8toUnicode(const char* utf8Str)
{
UINT theLength = strlen(utf8Str);
return UTF8toUnicode(utf8Str, theLength);
}
第五类问题
- BSTR -> std::string 举例如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15BSTR bstrTest = ::SysAllocString(L”Test”);
_bstr_t bstr_t(bstrTest);
std::strStl = bstr_t;
SysFreeString(bstrTest );
std::string -> BSTR 举例如下
std::string name = "nisb";
_bstr_t bstr_t(name.c_str());
BSTR ret_val = bstr_t.GetBSTR();
转来一篇原理编码的原理:
1:使用CString,要包含文件afx.h,比如在Win32 Console Application中Alt+F7选择Use MFC in a Static Liberary,然后再添加#include
2:WCHAR ch = L’中’;与CHAR ch = ’中’;的区别是第一种使用UNICODE编码,第二种方式一般不经常用到,比如:1
2
3
4
5
6
7WCHAR strA [ 2 ] = { L'中' , 0 } ;//打开VC的Options菜单,选中Debug选项卡中的Display unicode strings后,可以看到strA的值。
WCHAR strB [ 2 ] = { '中' , 0 } ;
CString strC ;
strC+ = ( ( char * ) strB ) [ 1 ] ;
strC+ = ( ( char * ) strB ) [ 0 ] ;//strC==”中”
3:CString的AllocSysString ( )成员函数;可以方便的把一个字符串转换成UNICODE形式。记得使用完该UNICODE字符串后要调用::SysFreeString()函数释放字符串。
4: CString::AllocSysString ( )或者::SysAllocString得到的字符串并不是普通的UNICODE字符串,它之前的四个字节会存放申请的字符串的长度:1
2
3CString strD = ”asdf”;
BSTR strD = strC.AllocSysString( ) ;
long i =* ( ( long * ) strD – 1 ) ; // i == 8;一个UNICDE字符的长度是2字节,所以strD的长度为8个字节。
4:UTF-8码转换为一般的字符串:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include " Windows.h "
int main(void)
{
char str [ 256 ] = {( char )0xE4, ( char ) 0xBD, ( char ) 0xA0, ( char ) 0xE5 ,
( char)0xA5 ,(char)0xBD, (char)0x61, (char)0x62 ,(char)0x63,(char)0} ; //一段UTF-8编码
WCHAR* strA;
int i= MultiByteToWideChar ( CP_UTF8 , 0 ,(char*) str ,-1 ,NULL,0);
strA = new WCHAR[i];
MultiByteToWideChar ( CP_UTF8 , 0 ,( char * ) str, -1, strA , i );
i= WideCharToMultiByte(CP_ACP,0,strA,-1,NULL,0,NULL,NULL);
char *strB=new char[i];
WideCharToMultiByte (CP_ACP,0,strA,-1,strB,i,NULL,NULL);
//strB即为所求
delete []strA;
delete []strB;
return 0;
}
5:在转换方面_bstr_t是最最灵活的,他提供了UNICODE到一般字符串的直接转换:1
2
3
4
5
6
7
8#include <comdef.h>
_bstr_t strA;
char *strB="中国人";
strA=strB;
WCHAR *strC=strA;
long i =* ( ( long * ) strC - 1 ) ;// i 亦是字符串的字节长度
char *strD=strA;
return 0;
宽窄字串转换!
两种方法:1、CString 2、_bstr_t1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include "comutil.h"
//注意在Project-》Setting-》Link中加入comsupp.lib,从而使_bstr_t可用
void CAaaDlg::OnButton1()
{
// TODO: Add extra cleanup here
_bstr_t a(L"sdfsafds");
a+="zzz";
char * b = (char *)a;//获得内部BSTR的char*指针,勿做修改和释放
WCHAR *c=(WCHAR *)a;//获得内部BSTR的WCHARr*指针,勿做修改和释放
CString p = L"asdfsa";
p+="ppp";
WCHAR *y =p.AllocSysString(); //获得WCHAR*指针,使用完请释放,否则有内存泄漏。
char *z = p.GetBuffer(p.GetLength()+1);//内部Buffer指针,z不要释放
::SysFreeString(y);
}