Сущность технологии СОМ. Библиотека программиста | страница 72
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.
Атрибуты и свойства
Иногда бывает полезно показать, что объект имеет некие открытые свойства, которые могут быть доступны и/или которые можно модифицировать через СОМ-интерфейс. СОМ IDL позволяет аннотировать методы интерфейса с тем, чтобы данный метод либо модифицировал, либо читал именованный атрибут объекта. Рассмотрим такое определение интерфейса: