当前位置: 代码迷 >> 综合 >> VARIANT和CComVariant
  详细解决方案

VARIANT和CComVariant

热度:69   发布时间:2023-10-31 05:53:14.0

VARIANT

1.定义

VARIANT,变体数据类型,在文件OAIDL.IDL中定义

VARIANT数据结构包含两个域(如果不考虑保留的域)。

vt域描述了第二个域的数据类型。

为了使多种类型能够在第二个域中出现,我们定义了一个联合结构。

所以,第二个域的名称随着vt域中输入值的不同而改变。

简单来说VARIANT主要由一个变量类型vt(枚举值)和一个联合体(变量内容)组成。

struct tagVARIANT {union {struct __tagVARIANT {VARTYPE vt;WORD     wReserved1;WORD     wReserved2;WORD     wReserved3;union {ULONGLONG      ullVal;        /* VT_UI8                */LONGLONG       llVal;         /* VT_I8                 */LONG           lVal;          /* VT_I4                 */BYTE           bVal;          /* VT_UI1                */SHORT          iVal;          /* VT_I2                 */FLOAT          fltVal;        /* VT_R4                 */DOUBLE         dblVal;        /* VT_R8                 */VARIANT_BOOL   boolVal;       /* VT_BOOL               */_VARIANT_BOOL bool;          /* (obsolete)            */SCODE          scode;         /* VT_ERROR              */CY             cyVal;         /* VT_CY                 */DATE           date;          /* VT_DATE               */BSTR           bstrVal;       /* VT_BSTR               */IUnknown *     punkVal;       /* VT_UNKNOWN            */IDispatch *    pdispVal;      /* VT_DISPATCH           */SAFEARRAY *    parray;        /* VT_ARRAY              */BYTE *         pbVal;         /* VT_BYREF|VT_UI1       */SHORT *        piVal;         /* VT_BYREF|VT_I2        */LONG *         plVal;         /* VT_BYREF|VT_I4        */LONGLONG *     pllVal;        /* VT_BYREF|VT_I8        */FLOAT *        pfltVal;       /* VT_BYREF|VT_R4        */DOUBLE *       pdblVal;       /* VT_BYREF|VT_R8        */VARIANT_BOOL *pboolVal;      /* VT_BYREF|VT_BOOL      */_VARIANT_BOOL *pbool;        /* (obsolete)            */SCODE *        pscode;        /* VT_BYREF|VT_ERROR     */CY *           pcyVal;        /* VT_BYREF|VT_CY        */DATE *         pdate;         /* VT_BYREF|VT_DATE      */BSTR *         pbstrVal;      /* VT_BYREF|VT_BSTR      */IUnknown **    ppunkVal;      /* VT_BYREF|VT_UNKNOWN   */IDispatch **   ppdispVal;     /* VT_BYREF|VT_DISPATCH */SAFEARRAY **   pparray;       /* VT_BYREF|VT_ARRAY     */VARIANT *      pvarVal;       /* VT_BYREF|VT_VARIANT   */PVOID          byref;         /* Generic ByRef         */CHAR           cVal;          /* VT_I1                 */USHORT         uiVal;         /* VT_UI2                */ULONG          ulVal;         /* VT_UI4                */INT            intVal;        /* VT_INT                */UINT           uintVal;       /* VT_UINT               */DECIMAL *      pdecVal;       /* VT_BYREF|VT_DECIMAL   */CHAR *         pcVal;         /* VT_BYREF|VT_I1        */USHORT *       puiVal;        /* VT_BYREF|VT_UI2       */ULONG *        pulVal;        /* VT_BYREF|VT_UI4       */ULONGLONG *    pullVal;       /* VT_BYREF|VT_UI8       */INT *          pintVal;       /* VT_BYREF|VT_INT       */UINT *         puintVal;      /* VT_BYREF|VT_UINT      */struct __tagBRECORD {PVOID          pvRecord;IRecordInfo * pRecInfo;} __VARIANT_NAME_4;          /* VT_RECORD             */} __VARIANT_NAME_3;} __VARIANT_NAME_2;DECIMAL decVal;} __VARIANT_NAME_1;
};

2.实例

long lValue = 999;
VARIANT vParam;
vParam.vt = VT_I4;//指定数据类型,常量VT_I4表明在第二个域中将出现一个long型的数据
vParam.lVal = lValue;//一个long型数据存入VARIANT类型时,其第二个域使用的名称是lVal

3.作用

VARIANT类型,可以跨语言(VB, C#, Java, C++)来表示任意一种类型。和BSTR一样,它也是微软约定好的一种协议。遵循这种协议,我们的变量可以正确地被支持COM的语言所认识。

4.API

VariantInit(VARIANTARG* pvarg)

初始化一个VARIANT(VARIANTARG是VARIANT别名)变量,它将变量初始化为VT_EMPTY

VariantClear(VARIANTARG * pvarg)

清理一个VARIANT对象。当调用完VariantClear后,变量的vt将会被设置为VT_EMPTY。

VariantCopy(VARIANTARG *pvargDest, const VARIANTARG *pvargSrc)

将pvargSrc中的内容拷贝到pvargDest中。如果pvargDest事先有内容,那么则使用VariantClear来释放它。

VARIANT a, b;
VariantInit(&a);
VariantInit(&b);
VariantCopy(&a, &b); // 释放a中的内容,然后a<-b
VariantClear(&a);
VariantClear(&b);

CComVariant

1.定义

类(class),在ATL中定义,是直接继承于VARIANT类的,所以它可以直接使用VARIANT成员。

头文件 :atlcomcli.h

析构函数:调用Clear()方法,也就是调用VariantClear()。

构造函数:

第一类是没有参数的构造函数,简单地调用了VariantInit。

第二类是传入值变量的构造函数,例如传入BYTE, short等,vt将分别设置为VT_UI1, VT_I2,且设置到对应的成员中。

第三类转调了自身的operator=

可以将CComVariant看为“智能VARIANT”,我们只需要给它传入适当的值,它自己来处理VARIANT的生命周期,并且它符合我们绝大部分需求

2.实现

(1) 构造

默认构造函数:CComVariant()

BYTE构造函数:CComVariant(BYTE  nSrc)

short构造函数:CComVariant(short  nSrc)

long 构造函数:CComVariant(long nSrc, VARTYPE=VT_I4)

bool 构造函数:CComVariant(bool  nSrc)

 这个函数有点特别,如果是true,那么boolVal会被赋值为ATL_VARIANT_TRUE,否则,    会被赋值为ATL_VARIANT_FALSE

IDispatch* 构造函数: CComVariant(IDispatch *)

IUnknown*构造函数: CComVariant(IUnknown *)

VARIANT构造函数: CComVariant(const VARIANT *var)

本身构造函数:         CComVariant(const CComVariant & varSrc)

在使用CComVariant(const VARIANT *var)的时候,要注意一定要先初始化var参数,否则会导致 CComVariant被创建为 VT_ERROR

 比如下面的代码, 导致 CComVariant被创建为 VT_ERROR     

    void  fuck(){VARIANT  vt;CComVariant  ccv(&vt);}

跟BSTR相关的构造函数:

CComVariant(const CComBSTR & bstrSrc)

CComVariant(LPCOLESTR  lpszSrc)

CComVariant(LPCSTR       lpszSrc)

这三个构造函数,如果不能顺利的构建BSTR内存,那么也会将CComVariant构建为VT_ERROR.

上面三个构造函数,只有第一个能够正确的处理含有NULL的字符串,下面的两个将被NULL给截断,原因就是BSTR的构建过程中,会将NULL当做结束符。 

(2)赋值

赋值跟构造函数类似,也是很多类似的赋值函数。

(3)Clear函数

如果要释放CComVariant,那么需要调用Clear函数,但是在CComVariant的析构函数中,Clear会被自动的调用,所以一般不需要自己去手动调用Clear函数。

(4)Copy函数

Copy将CComVariant的内容,拷贝到一个VARIANT

VARIANT  vt;long i=5;CComVariant cvt(i);cvt.Copy(&vt);

(5)  Detach函数

如果想把CComVariant的实例内容的管理权交给VARIANT管理时,使用Detach函数。这个时候,CComVariant将不再自动管理内容。         

在一个方法里面,如果要用Detach设置一个VARIANT的输出参数时候,记得一定要初始化VARIANT参数,因为在Detach的时候,CComVariant会去销毁清除指定的VARIANT,这个时候,如果VARIANT没有被初始化,那么就很可能会抛出异常。

 void getVariant(VARIANT * poutVar){VariantInit(poutVar);//记得一定要初始化VARIANT参数//或者poutVar->vt=VT_EMPTY;//假定ccvar是一个被正确初始化和赋值的CComVariantccvar->Detach(poutVar);}

(6) Attach函数

Attach可以让一个CComVariant获得VARIANT的所以权,全面接管所有权。
 

VARIANT  vt;vt.vt=VT_BSTR;vt.bstrVal=::SysAllocString("Hello  VARIANT");CComVariant  ccv;ccv.Attach(&vt);

这样,CComVariant就接管了 bstr,而 vt不再拥有bstr了,可以不管vt了。

最后,给一个COM方法传递VARIANT,以及从一个方法获得VARIANT
 

//设置void  SetVar(VARIANT * var){CComVariant     ccc;ccc=var;//这里利用的是 VARIANT赋值函数}//获得void  GetVar(VARIANT *  var){VariantInit(var);CComVariant  ccc;ccc.Copy(var);//或者ccc.Detach(var);}

CComVariant::Attach 将 VARIANT 附加到 CComVariant 对象。
CComVariant::ChangeType 将 对象 CComVariant 转换为新类型。
CComVariant::Clear 清除 CComVariant 对象。
CComVariant::Copy 将 VARIANT 复制到 CComVariant 对象。
CComVariant::CopyTo 复制 对象 CComVariant 的内容。
CComVariant::Detach 从 对象 VARIANT 分离基础 CComVariant 。
CComVariant::GetSize 返回对象内容的大小(以字节 CComVariant 数为单位)。
CComVariant::ReadFromStream 从流中加载 VARIANT
CComVariant::SetByRef 初始化 对象 CComVariant ,将 vt 成员设置为 VT_BYREF 。
CComVariant::WriteToStream 将基础 VARIANT 保存到流。