На этом шаге мы рассмотрим структуру, описывающую тип данных VARIANT.
Тип данных VARIANT определен в файле OAIDL.IDL так:
struct tagVARIANT { union { struct __tagVARIANT { VARTYPE vt; WORD wReserved1; WORD wReserved2; WORD wReserved3; union { 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 */ 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 */ 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; };
Структура данных VARIANT содержит два поля (если пренебречь зарезервированными). Поле vt описывает тип данных во втором поле. Объединение позволяет во втором поле размещать данные различных типов. Поэтому имя второго поля изменяется в зависимости от значения поля vt. Константы, которыми задается значение поля vt, указаны в комментарии на соответствующей строке объявления объединения.
Таким образом, использовать структуры данных VARIANT и VARIANTARG нужно в два приема. Взгляните на такой код:
long lValue = 555;
VARIANT vParam;
VParam.vt = VT_I4;
vParam.lVal = lValue;
В первой строке содержатся сведения о типе данных. В константе VT_I4 объявлено, что во втором элементе находится переменная типа long. Из определения типа VARIANT видно, что при сохранении значения типа long в структуре данных VARIANTARG второму полю должно быть присвоено имя lVal.
Использование VARIANT для передачи параметров означает, что языки с нестрогим контролем типов, например VBScript, могут обращаться к методам, реализованным на языках со строгим контролем типов, таких как C++. В методе Invoke() стоит предусмотреть проверку корректности типа значения, инкапсулированного в параметре VARIANT. Если тип верен, то параметр извлекается и передается в метод. В противном случае Invoke() попытается привести значение к правильному типу с помощью API-функции VariantChangeType().
На следующем шаге мы рассмотрим библиотеки типов.