发布时间:2012-5-3 10:27
分类名称:COM
从com的设计初衷来讲,要达到跨语言的目的,但是c++啊,java,python,pascal什么的都是有自己的数据类型的,设计这个变体类型 VARIANT就是为了达到这个目的,之所以称之为变体类型是因为它的类型不是固定的,基本上可以表示COM里面的任何基本类型和常见接口指针,从c++ 的本质来讲,VARIANT类型就是一个结构体,该结构体中有一个成员是表示该变量到底是个什么变量,也就是应该把这个表示数据的部分解释成一个什么东 东,实际的数据是存在结构体的一个联合体成员中的。
且看它在C++中的定义:
VARIANT 数据类型在文件OAIDL.IDL中定义如下:
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;
};
其中wReserved1,wReserved2,wReserved3是保留域,暂时可以不看,vt域表示下面的联合体域的数据类型,分别怎么表示可以看联合体中每个成员后面的注释,其实也是一个枚举类型,如下:
enum VARENUM
{ VT_EMPTY = 0,
VT_NULL = 1,
VT_I2 = 2,
VT_I4 = 3,
VT_R4 = 4,
VT_R8 = 5,
VT_CY = 6,
VT_DATE = 7,
VT_BSTR = 8,
VT_DISPATCH = 9,
VT_ERROR = 10,
VT_BOOL = 11,
VT_VARIANT = 12,
VT_UNKNOWN = 13,
VT_DECIMAL = 14,
VT_I1 = 16,
VT_UI1 = 17,
VT_UI2 = 18,
VT_UI4 = 19,
VT_I8 = 20,
VT_UI8 = 21,
VT_INT = 22,
VT_UINT = 23,
VT_VOID = 24,
VT_HRESULT = 25,
VT_PTR = 26,
VT_SAFEARRAY = 27,
VT_CARRAY = 28,
VT_USERDEFINED = 29,
VT_LPSTR = 30,
VT_LPWSTR = 31,
VT_RECORD = 36,
VT_INT_PTR = 37,
VT_UINT_PTR = 38,
VT_FILETIME = 64,
VT_BLOB = 65,
VT_STREAM = 66,
VT_STORAGE = 67,
VT_STREAMED_OBJECT = 68,
VT_STORED_OBJECT = 69,
VT_BLOB_OBJECT = 70,
VT_CF = 71,
VT_CLSID = 72,
VT_VERSIONED_STREAM = 73,
VT_BSTR_BLOB = 0xfff,
VT_VECTOR = 0x1000,
VT_ARRAY = 0x2000,
VT_BYREF = 0x4000,
VT_RESERVED = 0x8000,
VT_ILLEGAL = 0xffff,
VT_ILLEGALMASKED = 0xfff,
VT_TYPEMASK = 0xfff
} ;
使用或定义VARIANT类型的时候就要分两步了,首先赋值类型vt域,然后给联合体域赋值,此时应该注意的是,最好使用正确的数据域,否则代码会晦涩难懂,如下:
VARIANT_BOOL bValue = VARIANT_TRUE;
VARIANT vParam;
vParam.vt = VT_BYREF | VT_BOOL;
vParam.pboolVal = &bValue;
如果觉得这么使用难用的话,可以使用包装类,CComVariant、COleVariant、_variant_t。
Invoke方法中有个参数类型是DISPPARAMS,这个也是一个结构体,定义如下:
typedef struct tagDISPPARAMS
{
/* [size_is] */ VARIANTARG *rgvarg;
/* [size_is] */ DISPID *rgdispidNamedArgs;
UINT cArgs;
UINT cNamedArgs;
}
DISPPARAMS;
cArgs表示rgvarg数组的长度,其中VARIANTARG实际就是VARIANT类型,这里是一个VARIANT类型的数组,rgvarg指向这个数组的第一个元素。