一:为什么会有这个?
目前,计算机语言有很多(大哥,为什么不能就那么一样呢?),如C++、Java,此外还有JavaScript、VBScript等脚本语言,它们自立门派,各自维护自己的数据类型。
C++是一种强类型语言,即C++中的某个变量,在使用时类型已经确定,C++中的变量都会被翻译成准确的内存地址和大小,如果类型不确定是不可能处理的。当使用C++这样强类型的语言来读取数据库或者与其他语言之间来交换数据时,它很有可能不知道获取到的数据的具体类型,这个时候必须借助于变体类型读取数据。VARIANT数据类型就具有跨语言的特性,同时它可以表示(存储)任意类型的数据。
二:VARIANT的定义
在我的windows C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include下OAIdl.h有这个东东的定义:
typedef /* [wire_marshal] */ struct tagVARIANT VARIANT; 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; } ; typedef VARIANT *LPVARIANT; typedef VARIANT VARIANTARG; typedef VARIANT *LPVARIANTARG;
看,就是这个东西。太难看了,下面是一个文件简化的让人看的:
struct tagVARIANT { union { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { LONG lVal; BYTE bVal; SHORT iVal; FLOAT fltVal; DOUBLE dblVal; VARIANT_BOOL boolVal; DATE date; BSTR bstrVal; SAFEARRAY *parray; VARIANT *pvarVal; }; }; };
VARIANT数据结构包含两个域(如果不考虑保留的域)。vt域描述了第二个域的数据类型。为了使多种类型能够在第二个域中出现,定义了一个联合结构。所以,第二个域的名称随着vt域中输入值的不同而改变。下面是同一个文件的里面的东东,这个东西是vt域可以赋哪些值及这些值代表什么变量类型:
/* VARIANT STRUCTURE * * VARTYPE vt; * WORD wReserved1; * WORD wReserved2; * WORD wReserved3; * union { * LONGLONG VT_I8 * LONG VT_I4 * BYTE VT_UI1 * SHORT VT_I2 * FLOAT VT_R4 * DOUBLE VT_R8 * VARIANT_BOOL VT_BOOL * SCODE VT_ERROR * CY VT_CY * DATE VT_DATE * BSTR VT_BSTR * IUnknown * VT_UNKNOWN * IDispatch * VT_DISPATCH * SAFEARRAY * VT_ARRAY * BYTE * VT_BYREF|VT_UI1 * SHORT * VT_BYREF|VT_I2 * LONG * VT_BYREF|VT_I4 * LONGLONG * VT_BYREF|VT_I8 * FLOAT * VT_BYREF|VT_R4 * DOUBLE * VT_BYREF|VT_R8 * VARIANT_BOOL * VT_BYREF|VT_BOOL * SCODE * VT_BYREF|VT_ERROR * CY * VT_BYREF|VT_CY * DATE * VT_BYREF|VT_DATE * BSTR * VT_BYREF|VT_BSTR * IUnknown ** VT_BYREF|VT_UNKNOWN * IDispatch ** VT_BYREF|VT_DISPATCH * SAFEARRAY ** VT_BYREF|VT_ARRAY * VARIANT * VT_BYREF|VT_VARIANT * PVOID VT_BYREF (Generic ByRef) * CHAR VT_I1 * USHORT VT_UI2 * ULONG VT_UI4 * ULONGLONG VT_UI8 * INT VT_INT * UINT VT_UINT * DECIMAL * VT_BYREF|VT_DECIMAL * CHAR * VT_BYREF|VT_I1 * USHORT * VT_BYREF|VT_UI2 * ULONG * VT_BYREF|VT_UI4 * ULONGLONG * VT_BYREF|VT_UI8 * INT * VT_BYREF|VT_INT * UINT * VT_BYREF|VT_UINT * } */
三:使用例子
看一个小例子就知道怎么用了:
#include <iostream> #include <OAIdl.h> using namespace std; int main(void) { VARIANT var; cout<<sizeof(VARIANT)<<endl; var.vt = VT_BOOL; //bool var.boolVal = true; cout<<var.boolVal<<endl; var.vt = VT_I4; //long var.lVal = 100; cout<<var.lVal<<endl; var.vt = VT_R8; //double var.dblVal = 3.23; cout<<var.dblVal<<endl; cin.get(); }
从中可以看到使用时,你要先指定这个variant是个什么玩意儿,然后给那个玩意儿赋值,输出的时候也要输出那个玩意儿的值,乖点总没错。输出:
四:还有一点
在使用VARIANT的时候,经常会用到一些它给定的宏,这些宏可以很方便地对VARIANT指定类型及赋值,在我的 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Include 下的oleauto.h里面就有:
// Declare variant access functions. #if __STDC__ || defined(NONAMELESSUNION) #define V_UNION(X, Y) ((X)->n1.n2.n3.Y) #define V_VT(X) ((X)->n1.n2.vt) #define V_RECORDINFO(X) ((X)->n1.n2.n3.brecVal.pRecInfo) #define V_RECORD(X) ((X)->n1.n2.n3.brecVal.pvRecord) #else #define V_UNION(X, Y) ((X)->Y) #define V_VT(X) ((X)->vt) #define V_RECORDINFO(X) ((X)->pRecInfo) #define V_RECORD(X) ((X)->pvRecord) #endif /* Variant access macros */ #define V_ISBYREF(X) (V_VT(X)&VT_BYREF) #define V_ISARRAY(X) (V_VT(X)&VT_ARRAY) #define V_ISVECTOR(X) (V_VT(X)&VT_VECTOR) #define V_NONE(X) V_I2(X) #define V_UI1(X) V_UNION(X, bVal) #define V_UI1REF(X) V_UNION(X, pbVal) #define V_I2(X) V_UNION(X, iVal) #define V_I2REF(X) V_UNION(X, piVal) #define V_I4(X) V_UNION(X, lVal) #define V_I4REF(X) V_UNION(X, plVal) #define V_I8(X) V_UNION(X, llVal) #define V_I8REF(X) V_UNION(X, pllVal) #define V_R4(X) V_UNION(X, fltVal) #define V_R4REF(X) V_UNION(X, pfltVal) #define V_R8(X) V_UNION(X, dblVal) #define V_R8REF(X) V_UNION(X, pdblVal) #define V_I1(X) V_UNION(X, cVal) #define V_I1REF(X) V_UNION(X, pcVal) #define V_UI2(X) V_UNION(X, uiVal) #define V_UI2REF(X) V_UNION(X, puiVal) #define V_UI4(X) V_UNION(X, ulVal) #define V_UI4REF(X) V_UNION(X, pulVal) #define V_UI8(X) V_UNION(X, ullVal) #define V_UI8REF(X) V_UNION(X, pullVal) #define V_INT(X) V_UNION(X, intVal) #define V_INTREF(X) V_UNION(X, pintVal) #define V_UINT(X) V_UNION(X, uintVal) #define V_UINTREF(X) V_UNION(X, puintVal) #ifdef _WIN64 #define V_INT_PTR(X) V_UNION(X, llVal) #define V_UINT_PTR(X) V_UNION(X, ullVal) #define V_INT_PTRREF(X) V_UNION(X, pllVal) #define V_UINT_PTRREF(X) V_UNION(X, pullVal) #else #define V_INT_PTR(X) V_UNION(X, lVal) #define V_UINT_PTR(X) V_UNION(X, ulVal) #define V_INT_PTRREF(X) V_UNION(X, plVal) #define V_UINT_PTRREF(X) V_UNION(X, pulVal) #endif #define V_CY(X) V_UNION(X, cyVal) #define V_CYREF(X) V_UNION(X, pcyVal) #define V_DATE(X) V_UNION(X, date) #define V_DATEREF(X) V_UNION(X, pdate) #define V_BSTR(X) V_UNION(X, bstrVal) #define V_BSTRREF(X) V_UNION(X, pbstrVal) #define V_DISPATCH(X) V_UNION(X, pdispVal) #define V_DISPATCHREF(X) V_UNION(X, ppdispVal) #define V_ERROR(X) V_UNION(X, scode) #define V_ERRORREF(X) V_UNION(X, pscode) #define V_BOOL(X) V_UNION(X, boolVal) #define V_BOOLREF(X) V_UNION(X, pboolVal) #define V_UNKNOWN(X) V_UNION(X, punkVal) #define V_UNKNOWNREF(X) V_UNION(X, ppunkVal) #define V_VARIANTREF(X) V_UNION(X, pvarVal) #define V_ARRAY(X) V_UNION(X, parray) #define V_ARRAYREF(X) V_UNION(X, pparray) #define V_BYREF(X) V_UNION(X, byref) #define V_DECIMAL(X) V_UNION(X, decVal) #define V_DECIMALREF(X) V_UNION(X, pdecVal) #ifndef RC_INVOKED #include <poppack.h> #endif // RC_INVOKED #endif // __OLEAUTO_H__
同样的目录wtypes.h下也有:
typedef unsigned short VARTYPE; /* * VARENUM usage key, * * * [V] - may appear in a VARIANT * * [T] - may appear in a TYPEDESC * * [P] - may appear in an OLE property set * * [S] - may appear in a Safe Array * * * VT_EMPTY [V] [P] nothing * VT_NULL [V] [P] SQL style Null * VT_I2 [V][T][P][S] 2 byte signed int * VT_I4 [V][T][P][S] 4 byte signed int * VT_R4 [V][T][P][S] 4 byte real * VT_R8 [V][T][P][S] 8 byte real * VT_CY [V][T][P][S] currency * VT_DATE [V][T][P][S] date * VT_BSTR [V][T][P][S] OLE Automation string * VT_DISPATCH [V][T] [S] IDispatch * * VT_ERROR [V][T][P][S] SCODE * VT_BOOL [V][T][P][S] True=-1, False=0 * VT_VARIANT [V][T][P][S] VARIANT * * VT_UNKNOWN [V][T] [S] IUnknown * * VT_DECIMAL [V][T] [S] 16 byte fixed point * VT_RECORD [V] [P][S] user defined type * VT_I1 [V][T][P][s] signed char * VT_UI1 [V][T][P][S] unsigned char * VT_UI2 [V][T][P][S] unsigned short * VT_UI4 [V][T][P][S] unsigned long * VT_I8 [T][P] signed 64-bit int * VT_UI8 [T][P] unsigned 64-bit int * VT_INT [V][T][P][S] signed machine int * VT_UINT [V][T] [S] unsigned machine int * VT_INT_PTR [T] signed machine register size width * VT_UINT_PTR [T] unsigned machine register size width * VT_VOID [T] C style void * VT_HRESULT [T] Standard return type * VT_PTR [T] pointer type * VT_SAFEARRAY [T] (use VT_ARRAY in VARIANT) * VT_CARRAY [T] C style array * VT_USERDEFINED [T] user defined type * VT_LPSTR [T][P] null terminated string * VT_LPWSTR [T][P] wide null terminated string * VT_FILETIME [P] FILETIME * VT_BLOB [P] Length prefixed bytes * VT_STREAM [P] Name of the stream follows * VT_STORAGE [P] Name of the storage follows * VT_STREAMED_OBJECT [P] Stream contains an object * VT_STORED_OBJECT [P] Storage contains an object * VT_VERSIONED_STREAM [P] Stream with a GUID version * VT_BLOB_OBJECT [P] Blob contains an object * VT_CF [P] Clipboard format * VT_CLSID [P] A Class ID * VT_VECTOR [P] simple counted array * VT_ARRAY [V] SAFEARRAY* * VT_BYREF [V] void* for local use * VT_BSTR_BLOB Reserved for system use */ 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 } ;
在调试的时候看到了这种难看的就按 Alt+G进入源文件看看是干啥的。
下面是我看到的源码:
1 DISPAPI KETAPITextBox::Copy( VARIANT *RHS ) 2 { 3 ASSERT(m_spShape); 4 VERIFY_IN_POINTER(RHS); 5 6 HRESULT hr = m_spShape->Copy(); 7 V_VT(RHS) = VT_BOOL; 8 V_BOOL(RHS) = SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE; 9 10 return hr; 11 }
从第7行看,V_VT(RHS) = VT_BOOL; 这句话就是把RHS指向的VARIANT的vt值赋成VT的bool类型,其实也就是 RHS->vt = VARIANT的bool 这个意思了,现在这个variant表示bool啦,懂了!