Сущность технологии COM


Приведение типов и IUnknown - часть 2


Если же объект в действительности не совместим с ICat или с IDog, то данная функция просто проигнорирует пропущенный аспект объекта (или оба аспекта сразу). Ниже показан семантически эквивалентный вариант с использованием QueryInterface:

void TryToSnoreAndIgnore(/* [in] */ IUnknown *pUnk) { HRESULT hr; IPug *pPug = 0; hr = pUnk->QueryInterface(IID_IPug, (void**)&pPug); if (SUCCEEDED(hr)) { // the object is Pug-compatible // объект совместим с Pug pPug->Snore(); pPug->Release(); // R2 }

ICat *pCat = 0; hr = pUnk->QueryInterface(IID_ICat, (void**)&pCat); if (SUCCEEDED(hr)) { // the object is Cat-compatible // объект совместим с Cat pCat->IgnoreMaster(); pCat->Release(); // R2 } }

Хотя имеются очевидные различия в синтаксисе, единственная существенная разница между двумя приведенными фрагментами кода состоит в том, что вариант, основанный на QueryInterface, подчиняется правилам подсчета ссылок СОМ.

Есть несколько тонкостей, связанных с QueryInterface и его употреблением. Метод QueryInterface может возвращать указатели только на тот же самый СОМ-объект, для которого он вызван. Глава 4 посвящена объяснению каждого нюанса этого оператора. Полезно, однако, отметить уже сейчас, что клиент не должен трактовать AddRef и Release как операции с объектом. Вместо этого следует рассматривать их как операции с указателем интерфейса. Это означает, что нижеследующий код ошибочен:

void BadCOMCode(/*[in]*/ IUnknown *pUnk) { ICat *pCat = 0; IPug *pPug = 0; HRESULT hr; hr = pUnk->QueryInterface(IID_ICat, (void**)&pCat); if (FAILED(hr)) goto cleanup; hr = pUnk->QueryInterface(IID_IPug, (void**)&pPug); if (FAILED(hr)) goto cleanup; pPug->Bark(); pCat->IgnoreMaster(); cleanup: if (pCat) pUnk->Release(); // pCat got AddRefed in QI // pCat получил AddRef в QI if (pPug) pUnk->Release(); // pDog got AddRefed in QI // pDog получил AddRef в QI }

Несмотря на то что все три указателя: pCat, pPug и pUnk — указывают на тот же самый объект, клиент не имеет права компенсировать AddRef, который происходит для pCat и pPug при вызове QueryInterface, вызовами Release для pUnk.


Начало  Назад  Вперед



Книжный магазин