эти API-функции, рассмотрим метод, принимающий VARIANT в качестве [in]-параметра:

HRESULT UseIt([in] VARIANT var);

Следующий фрагмент кода демонстрирует, как передать в этот метод целое число:

VARIANT var;

VariantInit(&var);

// initialize VARIANT

// инициализируем VARIANT

V_VT(&var) = VT_I4;

// set discriminator

// устанавливаем дискриминатор

V_I4(&var) = 100;

// set union

// устанавливаем объединение

HRESULT hr = pItf->UseIt(var);

// use VARIANT

// используем VARIANT

VariantClear(&var);

// free any resources in VARIANT

// освобождаем все ресурсы VARIANT

Отметим, что этот фрагмент кода использует макросы стандартного аксессора (accessor) для доступа к элементам данных VARIANT. Две следующие строки

V_VT(&var) = VT_I4;

V_I4(&var) = 100;

эквивалентны коду, который обращается к самим элементам данных:

var.vt = VT_I4;

var.lVal = 100;

Первый вариант предпочтительнее, так как он может компилироваться на С-трансляторах, которые не поддерживают неименованных объединений.

Ниже приведен пример того, как с помощью приведенной выше технологии реализация метода использует параметр VARIANT в качестве строки:

STDMETHODIMP MyClass::UseIt( /*[in] */ VARIANT var)

{

// declare and init a second VARIANT

// объявляем и инициализируем второй VARIANT

VARIANT var2;

VariantInit(&var2);

// convert var to a BSTR and store it in var2

// преобразуем переменную в BSTR и заносим ее в var2

HRESULT hr = VariantChangeType(&var2, &var, 0, VT_BSTR);

// use the string

// используем строку

if (SUCCEEDED(hr))

{

ustrcpy(m_szSomeDataMember, SAFEBSTR(V_BSTR(&var2)));

// free any resources held by var2

// освобождаем все ресурсы, поддерживаемые var2

VariantClear(&var2);

}

return hr;

}

Отметим, что API-процедура VariantChangeType способна осуществлять сложное преобразование любого переданного клиентом типа из VARIANT в нужный тип (в данном случае BSTR).

Один из последних типов данных, который вызывает дискуссию, – это интерфейс СОМ. Интерфейсы СОМ могут быть переданы в качестве параметров метода одним из двух способов. Если тип интерфейсного указателя известен на этапе проектирования, то тип интерфейса может быть объявлен статически:

HRESULT GetObject([out] IDog **ppDog);

Если же тип на этапе проектирования неизвестен, то разработчик интерфейса может дать пользователю возможность задать тип на этапе выполнения. Для поддержки динамически типизируемых интерфейсов в IDL имеется атрибут [iid_is]:

HRESULT GetObject([in] REFIID riid, [out, iid_is(riid)] IUnknown **ppUnk);

Хотя эта форма будет работать вполне хорошо, следующий вариант предпочтительнее из-за его подобия с QueryInterface:

HRESULT GetObject([in] REFIID riid, [out, iid_is(riid)] void **ppv);

Атрибут [iid_is] можно использовать как с параметрами [in], так и [out] для типов IUnknown * или void *. Для того чтобы использовать параметр интерфейса с динамически типизируемым типом, необходимо просто установить IID указателя требуемого типа:

IDog *pDog = 0; HRESULT hr = pItf->GetObject(IID_IDog, (void**)&pDog);

Соответствующая реализация для инициализации этого параметра просто использовала бы метод QueryInterface для нужного объекта:

STDMETHODIMP Class::GetObject(REFIID riid, void **ppv)

{

extern IUnknown * g_pUnkTheDog;

return g_pUnkTheDog->QueryInterface(riid, ppv);

}

Для уменьшения количества дополнительных вызовов методов между клиентом и объектом указатели интерфейса с динамически типизируемым типом должны всегда использоваться вместо указателей интерфейса со статически типизируемым типом IUnknown.

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату