VS中遇到的 UNICODE和ANSI 编码问题

以前编码问题总能让自己凑或蒙过去,最近要做一个项目服务器端用python写,客户端用c++,工程编译的字符集使用UNICODE。之间通过socket进行通信,通信过程中编码转换问题把我搞得晕头转向,逼着我将编码问题好好研究一番。


 
 

首先先谈谈VC中的编码问题,首先编码我们大致可以分为两类:文件编码和内存编码。文件编码即源代码文件的编码,gbk,UTF-8等。内存编码即源代码编译成为二进制文件的时候采用的编码。


比如,在VC 2008中我们写下如下的代码:


char* a = “a中”;


让我们分别来看一下文件编码和内存编码的区别。


用UntraEdit打开该cpp文件,进入十六进制模式:我们可以看到”a中”对应的编码为:0×61 0xD6 0xD0,0×61是ASCII码中的a,0xD6 0xD0是GBK里”中”的编码。说明,在中文windows环境下,VC创建的文件编码默认是GBK的。那么我们将文件修改为UTF-8的编码格式,重新用UE以十六进制模式进入。我们看到”a中”的编码变为了0×61 0xE4 0xB8 0xAD,0×61仍然是a的编码,而中的编码变成了,0xE4 0xB8 0xAD。


从上面的试验我们还可以知道,GBK中中文为2个字节,UTF-8是3个字节。


 
 

下面我们研究一下内存编码,内存编码在VC中只有3个选项:Not Set,Use Multi-Byte Character Set和Use Unicode Character Set。这个属性的修改可以在工程的属性栏中找到:

 

 

 
 

让我们继续观察上面的例子。来查看一下什么是内存编码。我们在程序中设置断点,调试程序来观察在程序运行过程中,三种工程属性下,char* a所指向的那篇内存空间的值是什么,是不是如我们所认为的那样:


工程属性
 Not Set
 Use Multi-Byte Character Set
 Use Unicode Character Set
 
内存
 0×61 0xd6 0xd0
 0×61 0xd6 0xd0
 0×61 0xd6 0xd0
 

 
 

如上表所示,无论工程属性如何设置,”中”在内存中都是gbk编码。这样的程序拿到非中文的操作系统中执行是会出现乱码的,那么怎么才能将其用UNICODE进行编码呢?我们需要用到wchar_t这个类型,wchar_t是一种宽字类型,宽字类型的变量使用方法如下wchar_t* a = L”a中”;即在”a中”前面加上L。


现在,调试一下可以看到,a在内存中的值为0×61 0×00 0×2d 0×4e。wchar_t类型的变量会将用两个字节存储英文变量,即在原有ASCII的基础上补上两个0.而后面的0×2d 0×4e就是”中”的编码。


这样,变量a就在多种语言平台上都可以正确显示了。那么,工程属性中的三种字符集选项有什么作用呢?


让我们引用MSDN中的原文:


Generic-text


data type name
 SBCS (_UNICODE,


_MBCS not


defined)
 _MBCS


defined
 _UNICODE


defined
 
_TCHAR
 char
 char
 wchar_t
 
_tfinddata_t
 _finddata_t
 _finddata_t
 _wfinddata_t
 
_tfinddata64_t
 __finddata64_t
 __finddata64_t
 __wfinddata64_t
 
_tfinddatai64_t
 _finddatai64_t
 _finddatai64_t
 _wfinddatai64_t
 
_TINT
 int
 int
 wint_t
 
_TSCHAR
 signed char
 signed char
 wchar_t
 
_TUCHAR
 unsigned char
 unsigned char
 wchar_t
 
_TXCHAR
 char
 unsigned char
 wchar_t
 
_T or _TEXT
 No effect (removed by preprocessor)
 No effect (removed by preprocessor)
 L (converts following character or string to its Unicode counterpart)
 

 
 

SBCS、_MBCS和_UNICODE是三个宏,会分别在设置了Not Set、Use Multi-Byte Character Set、Use Unicode Character Set的时候定义。为了程序的可移植性,我们通常不会直接使用wchar_t和L,而是使用TCHAR和T()。这样,在工程属性设置不同的情况下,TCHAR和T()会被解释为不同的内容。


同样,我们以前测试字符串长度的函数strlen也不要直接使用,为了可移植性,我们通常使用_tcslen或者_tcsclen。


 
 

TCHAR.H routine
 _UNICODE & _MBCS not defined
 _MBCS defined
 _UNICODE defined
 
_tcslen
 strlen
 strlen
 wcslen
 
_tcsclen
 strlen
 _mbslen
 wcslen
 
_tcsclen_l
 strlen_l
 _mbslen_l
 wcslen_l
 

 
 

那么现在的问题是,我想要把数据经过网络传输,现在是否可以直接传输wchar_t*的变量呢,答案是不行的,因为wchar_t*的字符串的英文字符表示中存在00,中文英文都用两个byte。这样既浪费空间又可能会导致网络的错误。因此我们需要先将其转换成char*的那种类型,即,英文用一个byte,中文用两个byte。怎么转换呢?要使用MultiByteToWideChar和WideCharToMultiByte来互相进行转换。转换完了之后再通过网络传输。


 
 

 
 

好了,现在数据到了Python端,想想看,现在Python端收到的是什么编码?对,中文是gbk的编码。然后我们为了在python端实现国际化,要将gbk转化成unicode。方法很简单,首先先用


s = struct.unpack(’s’,mysocket.recv(2))来接收一个中文字,然后调用s.decode(”gbk”)来将编码转化成为unicode编码。这样,编码问题就完全解决了~

 

VC++.NET中字符串之间的转换
2007-09-28 20:51
一、BSTR、LPSTR和LPWSTR

  在Visual C++.NET的所有编程方式中,我们常常要用到这样的一些基本字符串类型,如BSTR、LPSTR和LPWSTR等。之所以出现类似上述的这些数据类型,是因为不同编程语言之间的数据交换以及对ANSI、Unicode和多字节字符集(MBCS)的支持。

  那么什么是BSTR、LPSTR以及LPWSTR呢?

  BSTR(Basic STRing,Basic字符串)是一个OLECHAR*类型的Unicode字符串。它被描述成一个与自动化相兼容的类型。由于操作系统提供相应的 API函数(如SysAllocString)来管理它以及一些默认的调度代码,因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。图1描述了BSTR的结构,其中DWORD值是字符串中实际所占用的字节数,且它的值是字符串中Unicode字符的两倍。

  LPSTR和LPWSTR是Win32和VC++所使用的一种字符串数据类型。LPSTR被定义成是一个指向以NULL(‘/0’)结尾的8位ANSI 字符数组指针,而LPWSTR是一个指向以NULL结尾的16位双字节字符数组指针。在VC++中,还有类似的字符串类型,如LPTSTR、 LPCTSTR等,它们的含义如图2所示。

  例如,LPCTSTR是指“long pointer to a constant generic string”,表示“一个指向一般字符串常量的长指针类型”,与C/C++的const char*相映射,而LPTSTR映射为 char*。

  一般地,还有下列类型定义:

#ifdef UNICODE
 typedef LPWSTR LPTSTR;
 typedef LPCWSTR LPCTSTR;
#else
 typedef LPSTR LPTSTR;
 typedef LPCSTR LPCTSTR;
#endif

  二、CString、CStringA 和 CStringW

  Visual C++.NET中将CStringT作为ATL和MFC的共享的“一般”字符串类,它有CString、CStringA和CStringW三种形式,分别操作不同字符类型的字符串。这些字符类型是TCHAR、char和wchar_t。TCHAR在Unicode平台中等同于WCHAR(16位 Unicode字符),在ANSI中等价于char。wchar_t通常定义为unsigned short。由于CString在MFC应用程序中经常用到,这里不再重复。

  三、VARIANT、COleVariant 和_variant_t

  在OLE、ActiveX和COM中,VARIANT数据类型提供了一种非常有效的机制,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。下面让我们来看看OAIDL.H文件中VARIANT定义的一个简化版:

struct tagVARIANT {
 VARTYPE vt;
 union {
  short iVal; // VT_I2.
  long lVal; // VT_I4.
  float fltVal; // VT_R4.
  double dblVal; // VT_R8.
  DATE date; // VT_DATE.
  BSTR bstrVal; // VT_BSTR.
  …
  short * piVal; // VT_BYREF|VT_I2.
  long * plVal; // VT_BYREF|VT_I4.
  float * pfltVal; // VT_BYREF|VT_R4.
  double * pdblVal; // VT_BYREF|VT_R8.
  DATE * pdate; // VT_BYREF|VT_DATE.
  BSTR * pbstrVal; // VT_BYREF|VT_BSTR.
 };
};

  显然,VARIANT类型是一个C结构,它包含了一个类型成员vt、一些保留字节以及一个大的union类型。例如,如果vt为VT_I2,那么我们可以从iVal中读出VARIANT的值。同样,当给一个VARIANT变量赋值时,也要先指明其类型。例如:

VARIANT va;
:: VariantInit(&va); // 初始化
int a = 2002;
va.vt = VT_I4; // 指明long数据类型
va.lVal = a; // 赋值

  为了方便处理VARIANT类型的变量,Windows还提供了这样一些非常有用的函数:

  VariantInit —— 将变量初始化为VT_EMPTY;

  VariantClear —— 消除并初始化VARIANT;

  VariantChangeType —— 改变VARIANT的类型;

  VariantCopy —— 释放与目标VARIANT相连的内存并复制源VARIANT。

  COleVariant类是对VARIANT结构的封装。它的构造函数具有极为强大大的功能,当对象构造时首先调用VariantInit进行初始化,然后根据参数中的标准类型调用相应的构造函数,并使用VariantCopy进行转换赋值操作,当VARIANT对象不在有效范围时,它的析构函数就会被自动调用,由于析构函数调用了VariantClear,因而相应的内存就会被自动清除。除此之外,COleVariant的赋值操作符在与VARIANT类型转换中为我们提供极大的方便。例如下面的代码:

COleVariant v1("This is a test"); // 直接构造
COleVariant v2 = "This is a test";
// 结果是VT_BSTR类型,值为"This is a test"
COleVariant v3((long)2002);
COleVariant v4 = (long)2002;
// 结果是VT_I4类型,值为2002

  _variant_t是一个用于COM的VARIANT类,它的功能与COleVariant相似。不过在Visual C++.NET的MFC应用程序中使用时需要在代码文件前面添加下列两句:

  #include "comutil.h"

  #pragma comment( lib, "comsupp.lib" )
四、CComBSTR和_bstr_t

  CComBSTR是对BSTR数据类型封装的一个ATL类,它的操作比较方便。例如:

CComBSTR bstr1;
bstr1 = "Bye"; // 直接赋值
OLECHAR* str = OLESTR("ta ta"); // 长度为5的宽字符
CComBSTR bstr2(wcslen(str)); // 定义长度为5
wcscpy(bstr2.m_str, str); // 将宽字符串复制到BSTR中
CComBSTR bstr3(5, OLESTR("Hello World"));
CComBSTR bstr4(5, "Hello World");
CComBSTR bstr5(OLESTR("Hey there"));
CComBSTR bstr6("Hey there");
CComBSTR bstr7(bstr6);
// 构造时复制,内容为"Hey there"

  _bstr_t是是C++对BSTR的封装,它的构造和析构函数分别调用SysAllocString和SysFreeString函数,其他操作是借用BSTR API函数。与_variant_t相似,使用时也要添加comutil.h和comsupp.lib。

  五、BSTR、char*和CString转换

  (1) char*转换成CString

  若将char*转换成CString,除了直接赋值外,还可使用CString::Format进行。例如:

char chArray[] = "This is a test";
char * p = "This is a test";

  或

LPSTR p = "This is a test";

  或在已定义Unicode应的用程序中

TCHAR * p = _T("This is a test");

  或

LPTSTR p = _T("This is a test");
CString theString = chArray;
theString.Format(_T("%s"), chArray);
theString = p;

  (2) CString转换成char*

  若将CString类转换成char*(LPSTR)类型,常常使用下列三种方法:

  方法一,使用强制转换。例如:

CString theString( "This is a test" );
LPTSTR lpsz =(LPTSTR)(LPCTSTR)theString;

  方法二,使用strcpy。例如:

CString theString( "This is a test" );
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
_tcscpy(lpsz, theString);

  需要说明的是,strcpy(或可移值Unicode/MBCS的_tcscpy)的第二个参数是 const wchar_t* (Unicode)或const char* (ANSI),系统编译器将会自动对其进行转换。

  方法三,使用CString::GetBuffer。例如:

CString s(_T("This is a test "));
LPTSTR p = s.GetBuffer();
// 在这里添加使用p的代码
if(p != NULL) *p = _T('/0');
s.ReleaseBuffer();
// 使用完后及时释放,以便能使用其它的CString成员函数

  (3) BSTR转换成char*

  方法一,使用ConvertBSTRToString。例如:

#include
#pragma comment(lib, "comsupp.lib")
int _tmain(int argc, _TCHAR* argv[]){
BSTR bstrText = ::SysAllocString(L"Test");
char* lpszText2 = _com_util::ConvertBSTRToString(bstrText);
SysFreeString(bstrText); // 用完释放
delete[] lpszText2;
return 0;
}

  方法二,使用_bstr_t的赋值运算符重载。例如:

_bstr_t b = bstrText;
char* lpszText2 = b;

  (4) char*转换成BSTR

  方法一,使用SysAllocString等API函数。例如:

BSTR bstrText = ::SysAllocString(L"Test");
BSTR bstrText = ::SysAllocStringLen(L"Test",4);
BSTR bstrText = ::SysAllocStringByteLen("Test",4);

  方法二,使用COleVariant或_variant_t。例如:

//COleVariant strVar("This is a test");
_variant_t strVar("This is a test");
BSTR bstrText = strVar.bstrVal;

  方法三,使用_bstr_t,这是一种最简单的方法。例如:

BSTR bstrText = _bstr_t("This is a test");

  方法四,使用CComBSTR。例如:

BSTR bstrText = CComBSTR("This is a test");

  或

CComBSTR bstr("This is a test");
BSTR bstrText = bstr.m_str;

  方法五,使用ConvertStringToBSTR。例如:

char* lpszText = "Test";
BSTR bstrText = _com_util::ConvertStringToBSTR(lpszText);

  (5) CString转换成BSTR

  通常是通过使用CStringT::AllocSysString来实现。例如:

CString str("This is a test");
BSTR bstrText = str.AllocSysString();

SysFreeString(bstrText); // 用完释放

  (6) BSTR转换成CString

  一般可按下列方法进行:

BSTR bstrText = ::SysAllocString(L"Test");
CStringA str;
str.Empty();
str = bstrText;

  或

CStringA str(bstrText);

  (7) ANSI、Unicode和宽字符之间的转换

  方法一,使用MultiByteToWideChar将ANSI字符转换成Unicode字符,使用WideCharToMultiByte将Unicode字符转换成ANSI字符。

  方法二,使用“_T”将ANSI转换成“一般”类型字符串,使用“L”将ANSI转换成Unicode,而在托管C++环境中还可使用S将ANSI字符串转换成String*对象。例如:

TCHAR tstr[] = _T("this is a test");
wchar_t wszStr[] = L"This is a test";
String* str = S”This is a test”;

  方法三,使用ATL 7.0的转换宏和类。ATL7.0在原有3.0基础上完善和增加了许多字符串转换宏以及提供相应的类,它具有如图3所示的统一形式:

  其中,第一个C表示“类”,以便于ATL 3.0宏相区别,第二个C表示常量,2表示“to”,EX表示要开辟一定大小的缓冲。SourceType和DestinationType可以是A、 T、W和OLE,其含义分别是ANSI、Unicode、“一般”类型和OLE字符串。例如,CA2CT就是将ANSI转换成一般类型的字符串常量。下面是一些示例代码:

LPTSTR tstr= CA2TEX<16>("this is a test");
LPCTSTR tcstr= CA2CT("this is a test");
wchar_t wszStr[] = L"This is a test";
char* chstr = CW2A(wszStr);
 


一.               VC常用数据类型列表

二.               常用数据类型转化

2.1数学类型变量与字符串相互转换

2.2 CString及string,char *与其他数据类型的转换和操作

●CString,string,char*的综合比较

●数学类型与CString相互转化

●CString与char*相互转换举例

●CString 与 BSTR 型转换

●VARIANT 型转化成 CString 型

2.3 BSTR、_bstr_t与CComBSTR

2.4 VARIANT 、_variant_t 与 COleVariant

附录CString及字符串转及操作详解

参考书籍:CSDN,<<MFC深入浅出(Second Edit)>>

                              一.VC常用数据类型列表

 Type
 Default Size
 Description
 


 说明:这些基础数据类型对于MFC还是API都是被支持的
 
boolean
 unsigned 8 bit ,
 取值TRUE/FALSE
 
byte
 unsigned 8 bit,
 整数,输出按字符输出
 
char
 unsigned 8 bit,
 字符
 
double
 signed 64 bit
 浮点型
 
float
 signed32 bit
 浮点型
 
handle_t
  Primitive handle type
 
hyper
 signed 64 bit
 整型
 
int
 signed 32 bit
 整型
 
long
 signed 32 bit
 整型
 
short
 signed 16 bit
 整型
 
small
 signed 8 bit
 整型
 
void *
 32-bit
 指向未知类型的指针
 
wchar_t
 unsigned 16 bit
 16位字符,比char可容纳更多的字符
 
  
Win32

API


 说明: 这些Win32API支持的简单数据类型主要是用来定义函数返回值,消息参数,结构成员。这类数据类型大致可以分为五大类:字符型、布尔型、整型、指针型和句柄型(?). 总共大概有100多种不同的类型,
 
BOOL/BOOLEAN
 8bit,TRUE/FALSE
 布尔型
 
BYTE
 unsigned 8 bit
 
BSTR

CComBSTR

_bstr_t
 32 bit
 BSTR是指向字符串的32位指针

是对BSTR的封装

是对BSTR的封装
 
CHAR
 8 bit
 (ANSI)字符类型
 
COLORREF
 32 bit
 RGB颜色值 整型
 
DWORD
 unsigned 32 bit
 整型
 
FLOAT
 float型
 float型
 
HANDLE
  Object句柄
 
HBITMAP
  bitmap句柄
 
HBRUSH
  brush句柄
 
HCURSOR
  cursor句柄
 
HDC
  设备上下文句柄
 
HFILE
  OpenFile打开的File句柄
 
HFONT
  font句柄
 
HHOOK
  hook句柄
 
HKEY
  注册表键句柄
 
HPEN
  pen句柄
 
HWND
  window句柄
 
INT
 --------
 --------
 
LONG
 --------
 ---------
 
LONGLONG
  64位带符号整型
 
LPARAM
 32 bit
 消息参数
 
LPBOOL
  BOOL型指针
 
LPBYTE
  BYTE型指针
 
LPCOLOREF
  COLORREF型指针
 
LPCSTR/LPSTR/PCSTR
  指向8位(ANSI)字符串类型指针
 
LPCWSTR/LPWSTR/PCWSTR
  指向16位Unicode字符串类型
 
LPCTSTR/LPTSTR/PCTSTR
  指向一8位或16位字符串类型指针
 
LPVOID
  指向一个未指定类型的32位指针
 
LPDWORD
  指向一个DWORD型指针
 
其他相似类型: LPHANDLE、LPINT、LPLONG、LPWORD、LPRESULT

PBOOL、PBOOLEAN、PBYTE、PCHAR、PDWORD、PFLOAT、PHANDLE、PINT、PLONG、PSHORT……

说明:(1)在16位系统中 LP为16bit,P为8bit,在32位系统中都是32bit(此时等价)

(2)LPCSTR等 中的C指Const,T表示TCHAR模式即可以工作在ANSI下也可UNICODE
 
SHORT
 usigned
 整型
 
其他UCHAR、UINT、ULONG、ULONGLONG、USHORT为无符号相应类型
 
TBYTE
  WCHAR型或者CHAR型
 
TCHAR
  ANSI与unicode均可
 
VARIANT

_variant_t

COleVariant
  一个结构体参考OAIDL.H

_variant_t是VARIANT的封装类

COleVariant也是VARIANT的封装类
 
  
  
WNDPROC
  指向一个窗口过程的32位指针
 
WCHAR
  16位Unicode字符型
 
WORD
  16位无符号整型
 
WPARAM
  消息参数
 
MFC

独有

数据

类型
 下面两个数据类型是微软基础类库中独有的数据类型
 
POSITION
 标记集合中一个元素的位置的值,被MFC中的集合类所使用
 
LPCRECT
 指向一个RECT结构体常量(不能修改)的32位指针
 
CString
 其实是MFC中的一个类
 
  

说明:

(1)-------表示省略

(2)1Byte=8Bit,

字与机器有关,在8位系统中:字=1字节,16位系统中,1字=2字节,32位中:1字=4字节,

64位中1字=8字节.不要搞混这些概念.

二.常用数据类型转化及操作

2.1 数学类型变量与字符串相互转换(这些函数都在STDLIB.H里)

(1)将数学类型转换为字符串可以用以下一些函数:

举例: _CRTIMP char * __cdecl _itoa(int, char *, int);//这是一个将数字转换为一个字符串类型的函数,最后一个int表示转换的进制

如以下程序:

int iTyep=3;

char *szChar;

itoa(iType,szChar,2);

cout<<szChar;//输出为1010

类似函数列表:

_CRTIMP char * __cdecl _itoa(int, char *, int);//为了完整性,也列在其中

_CRTIMP char * __cdecl _ultoa(unsigned long, char *, int);

_CRTIMP char * __cdecl _ltoa(long, char *, int);

_CRTIMP char * __cdecl _i64toa(__int64, char *, int);

_CRTIMP char * __cdecl _ui64toa(unsigned __int64, char *, int);

_CRTIMP wchar_t * __cdecl _i64tow(__int64, wchar_t *, int);

_CRTIMP wchar_t * __cdecl _ui64tow(unsigned __int64, wchar_t *, int);

_CRTIMP wchar_t * __cdecl _itow (int, wchar_t *, int);//转换为长字符串类型

_CRTIMP wchar_t * __cdecl _ltow (long, wchar_t *, int);

_CRTIMP wchar_t * __cdecl _ultow (unsigned long, wchar_t *, int);

还有很多,请自行研究

(2)将字符串类型转换为数学类型变量可以用以下一些函数:

举例: _CRTIMP int   __cdecl atoi(const char *);//参数一看就很明了

char *szChar=”88”;

int temp(0);

temp=atoi(szChar);

cout<<temp;

类似的函数列表:

_CRTIMP int     __cdecl atoi(const char *);

_CRTIMP double __cdecl atof(const char *);

_CRTIMP long    __cdecl atol(const char *);

_CRTIMP long double __cdecl _atold(const char *);

_CRTIMP __int64 __cdecl _atoi64(const char *);

_CRTIMP double __cdecl strtod(const char *, char **);//

_CRTIMP long    __cdecl strtol(const char *, char **, int);//

_CRTIMP long double __cdecl _strtold(const char *, char **);

_CRTIMP unsigned long __cdecl strtoul(const char *, char **, int);

_CRTIMP double __cdecl wcstod(const wchar_t *, wchar_t **);//长字符串类型转换为数学类型

_CRTIMP long    __cdecl wcstol(const wchar_t *, wchar_t **, int);

_CRTIMP unsigned long __cdecl wcstoul(const wchar_t *, wchar_t **, int);

_CRTIMP int __cdecl _wtoi(const wchar_t *);

_CRTIMP long __cdecl _wtol(const wchar_t *);

_CRTIMP __int64    __cdecl _wtoi64(const wchar_t *);

还有很多,请自行研究

2.2.CString及string,char *与其他数据类型的转换和操作

(1)CString,string,char*的综合比较(这部分CSDN上的作者joise的文章

<< CString,string,char*的综合比较>>写的很详细,请大家在仔细阅读他的文章.

地址: http://blog.csdn.net/joise/

或参考附录:

(2)转换:

●数学类型与CString相互转化

数学类型转化为CString

可用Format函数,举例:

CString s;

int i = 64;

s.Format("%d", i)

CString转换为数学类型:举例CString strValue("1.234");

double dblValue;

dblValue = atof((LPCTSTR)strValue);

●CString与char*相互转换举例

CString strValue(“Hello”);

char *szValue;

szValue=strValue.GetBuffer(szValue);

也可用(LPSTR)(LPCTSTR)对CString//   进行强制转换. 

szValue=(LPSTR)(LPCTSTR)strValue;

反过来可直接赋值:

char *szChar=NULL;

CString strValue;

szChar=new char[10];

memset(szChar,0,10);

strcpy(szChar,”Hello”);

strValue=szChar;

●CString 与 BSTR 型转换

CString 型转化成 BSTR 型

当我们使用 ActiveX 控件编程时,经常需要用到将某个值表示成 BSTR 类型.BSTR 是一种记数字符串,Intel平台上的宽字符串(Unicode),并且可以包含嵌入的 NULL 字符。

可以调用 CString 对象的 AllocSysString 方法将 CString 转化成 BSTR:

CString str;

str = .....; // whatever

BSTR bStr = str.AllocSysString();

BSTR型转换为CString

如果你在 UNICODE 模式下编译代码,你可以简单地写成:

CString convert(BSTR bStr)

{

     if(bStr == NULL)

         return CString(_T(""));

     CString s(bStr); // in UNICODE mode

     return s;

}

如果是 ANSI 模式

CString convert(BSTR b)

{

     CString s;

     if(b == NULL)

        return s; // empty for NULL BSTR

#ifdef UNICODE

     s = b;

#else

     LPSTR p = s.GetBuffer(SysStringLen(b) + 1);

     ::WideCharToMultiByte(CP_ACP,             // ANSI Code Page

                           0,                  // no flags

                           b,                  // source widechar string

                           -1,                 // assume NUL-terminated

                           p,                  // target buffer

                           SysStringLen(b)+1, // target buffer length

                           NULL,               // use system default char

                           NULL);              // don''t care if default used

     s.ReleaseBuffer();

#endif

     return s;

}

●VARIANT 型转化成 CString 型

VARIANT 类型经常用来给 COM 对象传递参数,或者接收从 COM 对象返回的值。你也能自己编写返回 VARIANT 类型的方法,函数返回什么类型 依赖可能(并且常常)方法的输入参数(比如,在自动化操作中,依赖与你调用哪个方法。IDispatch::Invoke 可能返回(通过其一个参数)一个 包含有BYTE、WORD、float、double、date、BSTR 等等 VARIANT 类型的结果,(详见 MSDN 上的 VARIANT 结构的定义)。在下面的例子中,假设 类型是一个BSTR的变体,也就是说在串中的值是通过 bsrtVal 来引用,其优点是在 ANSI 应用中,有一个构造函数会把 LPCWCHAR 引用的值转换为一个 CString(见 BSTR-to-CString 部分)。在 Unicode 模式中,将成为标准的 CString 构造函数,参见对缺省::WideCharToMultiByte 转换的告诫,以及你觉得是否可以接受(大多数情况下,你会满意的)。VARIANT vaData;

vaData = m_com.YourMethodHere();

ASSERT(vaData.vt == VT_BSTR);

CString strData(vaData.bstrVal);

你还可以根据 vt 域的不同来建立更通用的转换例程。为此你可能会考虑:

CString VariantToString(VARIANT * va)

{

     CString s;

     switch(va->vt)

       { /* vt */

        case VT_BSTR:

           return CString(vaData->bstrVal);

        case VT_BSTR | VT_BYREF:

           return CString(*vaData->pbstrVal);

        case VT_I4:

           s.Format(_T("%d"), va->lVal);

           return s;

        case VT_I4 | VT_BYREF:

           s.Format(_T("%d"), *va->plVal);

        case VT_R8:

           s.Format(_T("%f"), va->dblVal);

           return s;

        ... 剩下的类型转换由读者自己完成

        default:

           ASSERT(FALSE); // unknown VARIANT type (this ASSERT is optional)

           return CString("");

       } /* vt */

}

2.3 BSTR、_bstr_t与CComBSTR

CComBSTR、_bstr_t是对BSTR的封装,BSTR是指向字符串的32位指针。

char *转换到BSTR可以这样:

BSTR b=_com_util::ConvertStringToBSTR("数据");///使用前需要加上头文件comutil.h

反之可以使用char *p=_com_util::ConvertBSTRToString(b);

2.4(引)VARIANT 、_variant_t 与 COleVariant

VARIANT的结构可以参考头文件VC98/Include/OAIDL.H中关于结构体tagVARIANT的定义。

对于VARIANT变量的赋值:首先给vt成员赋值,指明数据类型,再对联合结构中相同数据类型的变量赋值,举个例子:

VARIANT va;

int a=2001;

va.vt=VT_I4;///指明整型数据

va.lVal=a; ///赋值

对于不马上赋值的VARIANT,最好先用Void VariantInit(VARIANTARG FAR* pvarg);进行初始化,其本质是将vt设置为VT_EMPTY,下表我们列举vt与常用数据的对应关系:

unsigned char bVal; VT_UI1

short iVal; VT_I2

long lVal; VT_I4

float fltVal; VT_R4

double dblVal; VT_R8

VARIANT_BOOL boolVal; VT_BOOL

SCODE scode; VT_ERROR

CY cyVal; VT_CY

DATE date; VT_DATE

BSTR bstrVal; VT_BSTR

IUnknown FAR* punkVal; VT_UNKNOWN

IDispatch FAR* pdispVal; VT_DISPATCH

SAFEARRAY FAR* parray; VT_ARRAY|*

unsigned char FAR* pbVal; VT_BYREF|VT_UI1

short FAR* piVal; VT_BYREF|VT_I2

long FAR* plVal; VT_BYREF|VT_I4

float FAR* pfltVal; VT_BYREF|VT_R4

double FAR* pdblVal; VT_BYREF|VT_R8

VARIANT_BOOL FAR* pboolVal; VT_BYREF|VT_BOOL

SCODE FAR* pscode; VT_BYREF|VT_ERROR

CY FAR* pcyVal; VT_BYREF|VT_CY

DATE FAR* pdate; VT_BYREF|VT_DATE

BSTR FAR* pbstrVal; VT_BYREF|VT_BSTR

IUnknown FAR* FAR* ppunkVal; VT_BYREF|VT_UNKNOWN

IDispatch FAR* FAR* ppdispVal; VT_BYREF|VT_DISPATCH

SAFEARRAY FAR* FAR* pparray; VT_ARRAY|*

VARIANT FAR* pvarVal; VT_BYREF|VT_VARIANT

void FAR* byref; VT_BYREF

_variant_t是VARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。

例如:

long l=222;

ing i=100;

_variant_t lVal(l);

lVal = (long)i;

COleVariant的使用与_variant_t的方法基本一样,请参考如下例子:

COleVariant v3 = "字符串", v4 = (long)1999;

CString str =(BSTR)v3.pbstrVal;

long i = v4.lVal;

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/lookahead99/archive/2009/12/13/4999189.aspx

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值