BSTR与VARIANT

一、BSTR
概述
  它被描述成一个与自动化相兼容的类型,由于操作系统提供相应的API函数(如SysAllocString)来管理它以及一些默认的调度代码。因此BSTR实际上就是一个COM字符串,但它却在自动化技术以外的多种场合下得到广泛使用。

为什么需要BSTR

  COM是一种跨编程语言的平台,需要提供语言无关的数据类型。多数编程语言有自己的字符串表示。
  ●C++ 字符串是以0结束的ASCII或Unicode字符数组。
  ●Visual Basic字符串是一个ASCII字符数组加上表示长度的前缀。
  ●Java字符串是以0结束的Unicode字符数组。
  需要定义一种通用的字符串类型,可以很容易的匹配到不同编程语言。 在C++中,就是BSTR

什么是BSTR

  BSTR是“Basic STRing”的简称,微软在COM/OLE中定义的标准字符串数据类型。
  对于C++,Windows头文件wtypes.h中定义如下:
  typedef wchar_t WCHAR;
  typedef WCHAR OLECHAR;
  typedef OLECHAR __RPC_FAR *BSTR;;
  使用以Null结尾的简单字符串在COM component间传递不太方便。因此, 标准BSTR是一个有长度前缀和null结束符的OLECHAR数组。BSTR的前4字节是一个表示字符串长度的前缀。BSTR长度域的值是字符串的字节数,并且不包括0结束符。
  由于是Unicode串,所以字符数是字节数的一半。这种方式的优点是允许程序员在BSTR串中间嵌入NULL字符。但是,BSTR的前四个字节表示长度,而OLECHAR数组的前四字节表示前两个字符。这种情况下,对于C++程序,如何实现BSTR和OLECHAR的交换?答案是COM提供了两个BSTR分配用的API:SysAllocString / SysReallocString。函数返回的指针指向BSTR的第一个字符,而不是BSTR在内存的第一个字节。

什么时候使用BSTR

实际使用中BSTR并非第一选择,只有在你不得不用的时候在考虑吧!

   使用BSTR一般有以下几种情况:
  ●COM interface接口定义,并且不希望额外提供custom marshaling库(MDIL生成或开发人员自己订制),必须使用BSTR传递字符串。使用C/C++类型的字符串在COM DLL传递字符串,表面上可以使用,但违背了COM的基本规则,并且给以后的扩展留下了隐患。例如,把一个In-process COM Object(简单说COM DLL)改成out-of-process object(COM EXE)。理论上,客户端的代码应该不做任何改变。但如果是用了C/C++字符串,又希望只使用系统的automation mashaller(Oleaut32.dll),就会出错。
  ●如果可以提供custom marshaling,也推荐使用BSTR。
  ●客户要求接口必须使用BSTR,和客户讨论后,不能修改。
  ●使用的外部库的接口使用BSTR
   不使用的情况:
  ● 不推荐在IDL结构体中定义BSTR成员,会给结构体的复制和释放带来麻烦。最好直接使用限定最大长度的TCHAR数组。如果确实需要传递变长字符串,BSTR应该被定义成独立的参数或者使用独立的get/set接口。
  ● 尽可能缩小的BSTR及相关类型的作用域范围。类的成员变量和函数参数不使用BSTR。局部变量要尽快释放类的内部不使用BSTR。代码处理逻辑中只在接口直接相关部分使用BSTR。接收到一个BSTR时,尽量立刻变成C/C++的字符串副本进行处理。在需要传递BSTR参数前产生BSTR,用过立即释放。


二、VARIANT

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

struct   tagVARIANT
{
     union  
         {
         struct   __tagVARIANT
             {
            VARTYPE vt ;
            WORD wReserved1 ;
            WORD wReserved2 ;
            WORD wReserved3 ;
             union  
                 {
                LONG lVal ;
                BYTE bVal ;
                SHORT iVal ;
                FLOAT fltVal ;
                DOUBLE dblVal ;
                VARIANT_BOOL boolVal ;
                _VARIANT_BOOL  bool ;
                SCODE scode ;
                CY cyVal ;
                DATE date ;
                BSTR bstrVal ;
                 IUnknown  __RPC_FAR  * punkVal ;
                 IDispatch  __RPC_FAR  * pdispVal ;
                SAFEARRAY __RPC_FAR  * parray ;
                BYTE __RPC_FAR  * pbVal ;
                SHORT __RPC_FAR  * piVal ;
                LONG __RPC_FAR  * plVal ;
                FLOAT __RPC_FAR  * pfltVal ;
                DOUBLE __RPC_FAR  * pdblVal ;
                VARIANT_BOOL __RPC_FAR  * pboolVal ;
                _VARIANT_BOOL __RPC_FAR  * pbool ;
                SCODE __RPC_FAR  * pscode ;
                CY __RPC_FAR  * pcyVal ;
                DATE __RPC_FAR  * pdate ;
                BSTR __RPC_FAR  * pbstrVal ;
                 IUnknown  __RPC_FAR  * __RPC_FAR  * ppunkVal ;
                 IDispatch  __RPC_FAR  * __RPC_FAR  * ppdispVal ;
                SAFEARRAY __RPC_FAR  * __RPC_FAR  * pparray ;
                VARIANT __RPC_FAR  * pvarVal ;
                PVOID byref ;
                CHAR cVal ;
                USHORT uiVal ;
                ULONG ulVal ;
                INT intVal ;
                UINT uintVal ;
                DECIMAL __RPC_FAR  * pdecVal ;
                CHAR __RPC_FAR  * pcVal ;
                USHORT __RPC_FAR  * puiVal ;
                ULONG __RPC_FAR  * pulVal ;
                INT __RPC_FAR  * pintVal ;
                UINT __RPC_FAR  * puintVal ;
                 struct   __tagBRECORD
                     {
                    PVOID pvRecord ;
                     IRecordInfo  __RPC_FAR  * pRecInfo ;
                     }  __VARIANT_NAME_4 ;
                 }  __VARIANT_NAME_3 ;
             }  __VARIANT_NAME_2 ;
        DECIMAL decVal ;
         }  __VARIANT_NAME_1 ;
};


对于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_tVARIANT的封装类,其赋值可以使用强制类型转换,其构造函数会自动处理这些数据类型。
例如: 

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 ;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值