VARIANT结构体主要是使用在COM(组件对象模型)中用于传递参数使用,它的存在主要是为了保持一个在COM参数传递方法的统一性,它几乎包含了所有普通常用类型的数据类型的传递,如整型,浮点型,布尔型等等,以及相应类型的指针类型,如整型指针。它的使用也比较方便。先来看看这个结构体它的结构:

typedef struct tagVARIANT {
   union {
     struct __tagVARIANT {
       VARTYPE vt;
       WORD    wReserved1;
       WORD    wReserved2;
       WORD    wReserved3;
       union {
         LONGLONG            llVal;
         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            *punkVal;
         IDispatch           *pdispVal;
         SAFEARRAY           *parray;
         BYTE                *pbVal;
         SHORT               *piVal;
         LONG                *plVal;
         LONGLONG            *pllVal;
         FLOAT               *pfltVal;
         DOUBLE              *pdblVal;
         VARIANT_BOOL        *pboolVal;
         _VARIANT_BOOL       *pbool;
         SCODE               *pscode;
         CY                  *pcyVal;
         DATE                *pdate;
         BSTR                *pbstrVal;
         IUnknown            **ppunkVal;
         IDispatch           **ppdispVal;
         SAFEARRAY           **pparray;
         VARIANT             *pvarVal;
         PVOID               byref;
         CHAR                cVal;
         USHORT              uiVal;
         ULONG               ulVal;
         ULONGLONG           ullVal;
         INT                 intVal;
         UINT                uintVal;
         DECIMAL             *pdecVal;
         CHAR                *pcVal;
         USHORT              *puiVal;
         ULONG               *pulVal;
         ULONGLONG           *pullVal;
         INT                 *pintVal;
         UINT                *puintVal;
         struct __tagBRECORD {
           PVOID       pvRecord;
           IRecordInfo *pRecInfo;
         } __VARIANT_NAME_4;
       } __VARIANT_NAME_3;
     } __VARIANT_NAME_2;
     DECIMAL             decVal;
   } __VARIANT_NAME_1;
 } VARIANT, *LPVARIANT, VARIANTARG, *LPVARIANTARG;

这个结构体呢,有5个成员,分别是VARTYPE vt ,WORD wReserved1,WORD wReserved2,WORD wReserved3,和最后一个共用体。其中vt用以指明最后一个共用体中哪一个成员有效,wReserved1,wReserved2,wReserved3,这三个我们使用的时候不用管,系统保留,最后一个共用体根据vt的提示,对相应的成员进行值的存储。我们从两个不同的角度来理解,首先是使用VARIANT来存储参数,首先是声明一个这个结构体的对象,然后对对象的vt进行赋值,它可接受的值是一个枚举值,也就说只能在枚举这个范围内取值,比如我要用VARIANT传递一个整数,现在我对vt的赋值为VT_INT,这样就说明了我要使用这个结构体中共用体的整型变量,接着对INT变量进行赋值,赋我们要传递的值。这样就完成VARIANT的传递。现在我们从另外一个角度来理解VARIANT,刚才是我们对VARIANT对象进行赋值传递,现在我们是这个VARIANT对象的接收者,我们从参数中获得这个对象之后,我们首先检查这个结构体的vt成员,看它哪个类型的变量有效,比如就这个例子而言,检查到vt的值是VT_INT,因此,我直接去获取这个结构体中VT_INT所对应的变量,获取它的值。这样,我们从传递到使用两个角度来理解了VARIANT结构体,概括起来说,就是vt指明了我要传递的变量的类型,结构体中共用体的成员用来存储vt指明的类型的值。

下面来看看具体VARIANT结构体是如何使用赋值的,首先是第一种方法:

volume加权限 vt权限开启_volume加权限

首先我们声明一个VARIANT结构体的对象vr1,然后使用VariantInit函数对其进行初始化,它的作用就是对vt赋VT_EMPTY,对别的变量值附空,否则就是一个随机值,这个过程和我们声明一个int变量一样,如果声明的时候不初始化,就是一个随机值。编程过程中,不管是指针还是什么变量,都应该在声明之后对其进行初始化。接着就是我赋VT_INT给vt,这里的V_VT就是代表要对vr1结构体中的vt成员进行幅值,接着对vr1中的INT成员赋值,这里的V_INT就是表示要对INT赋值,因此这里有一个规律,就是V_,它的后面加成员类型就可以对相应的成员赋值,而这里的成员类型有一个对照表,在文章的最后给出,比如,我要对BSTR成员赋值,我就用V_BSTR。这时候,就可以使用vr1了,使用完成之后,我们应该调用VariantClear函数,这个函数的作用就是将vt赋值为VT_EMPTY,以及释放使用这个结构体中的内存中的内容,如果是com对象,该函数是不会进行对象的release操作的,不管怎么样,我们都应该在使用完了VARIANT结构体之后,调用这个函数。

下面是第二种方法,原理和过程和地中方法类似,有一点微小的区别,就是VARIANT结构体的赋值上面来说,有点不同,如下:

volume加权限 vt权限开启_VARIANT_02

接下来是字符串的操作,BSTR,我们不能直接将字符串传递一个VARIANT结构体对象,而是要用到函数SysAllocString,它的返回值就是一个BSTR,由它分配一个字符串,供VARIANT,对于为什么要这么做,可以自己查看MSDN COM的Automation那部分:

volume加权限 vt权限开启_VARIANT_03

完成之后,我们还应该调用SysFreeString来释放由SysAllocString分配的内存。

另外,我们可以在类型与变量的对照表中发现,同一类型,对应了两种不同的变量,如,INT对应了变量有intVal和pintVal,其实这很简单,后者是指针性,如果要使用,说明我们赋值的对象是一个指针,如下:

volume加权限 vt权限开启_赋值_04

最后给出类型与变量的对照表,如果是使用地中方法用V_加类型,就直接使用下表中VT_后的名称就可以了:


Member name

Description

 

VT_EMPTY

Indicates that a value was not specified.

 

VT_NULL

Indicates a null value, similar to a null value in SQL.

 

VT_I2

Indicates a short

 

VT_I4

Indicates a long

 

VT_R4

Indicates a float

 

VT_R8

Indicates a double

 

VT_CY

Indicates a currency value.

 

VT_DATE

Indicates a DATE value.

 

VT_BSTR

Indicates a BSTR string.

 

VT_DISPATCH

Indicates an IDispatch

 

VT_ERROR

Indicates an SCODE.

 

VT_BOOL

Indicates a Boolean value.

 

VT_VARIANT

Indicates a VARIANT far

 

VT_UNKNOWN

Indicates an IUnknown

 

VT_DECIMAL

Indicates a decimal

 

VT_I1

Indicates a char

 

VT_UI1

Indicates a byte.

 

VT_UI2

Indicates an unsignedshort.

 

VT_UI4

Indicates an unsignedlong.

 

VT_I8

Indicates a 64-bit integer.

 

VT_UI8

Indicates an 64-bit unsigned integer.

 

VT_INT

Indicates an integer value.

 

VT_UINT

Indicates an unsigned

 

VT_VOID

Indicates a C style void.

 

VT_HRESULT

Indicates an HRESULT.

 

VT_PTR

Indicates a pointer type.

 

VT_SAFEARRAY

Indicates a SAFEARRAY. Not valid in a VARIANT.

 

VT_CARRAY

Indicates a C style array.

 

VT_USERDEFINED

Indicates a user defined type.

 

VT_LPSTR

Indicates a null-terminated string.

 

VT_LPWSTR

Indicates a wide string terminated by nullNothingnullptra null reference (Nothing in Visual Basic).

 

VT_RECORD

Indicates a user defined type.

 

VT_FILETIME

Indicates a FILETIME value.

 

VT_BLOB

Indicates length prefixed bytes.

 

VT_STREAM

Indicates that the name of a stream follows.

 

VT_STORAGE

Indicates that the name of a storage follows.

 

VT_STREAMED_OBJECT

Indicates that a stream contains an object.

 

VT_STORED_OBJECT

Indicates that a storage contains an object.

 

VT_BLOB_OBJECT

Indicates that a blob contains an object.

 

VT_CF

Indicates the clipboard format.

 

VT_CLSID

Indicates a class ID.

 

VT_VECTOR

Indicates a simple, counted array.

 

VT_ARRAY

Indicates a SAFEARRAY

 

VT_BYREF

Indicates that a value is a reference.