Сущность технологии СОМ. Библиотека программиста | страница 128



. Спецификация СОМ имеет немного больше ограничений при описании результатов запросов QueryInterface именно на IUnknown. Объект не только должен отвечать «да» на запрос, он должен также возвращать в ответ на каждый запрос в точности одно и то же значение указателя. Это означает, что в следующем коде оба утверждения всегда должны быть верны:


void AssertSameObject(IUnknown *pUnk)

{

IUnknown *pUnk1 = 0,

*pUnk2 = 0;

HRESULT hr1 = pUnk->QueryInterface(IID_IUnknown, (void **)&pUnk1);

HRESULT hr2 = pUnk->QueryInterface(IID_IUnknown, (void **)&pUnk2);

// QueryInterface(IUnknown) must always succeed

// QueryInterface(IUnknown) должно всегда быть успешным

assert(SUCCEEDED(hr1) && SUCCEEDED(hr2));

// two requests for IUnknown must always yield the

// same pointer values

// два запроса на IUnknown должны всегда выдавать

// те же самые значения указателя

assert(pUnk1 == pUnk2);

pUnk1->Release();

pUnk2->Release();

}


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


bool IsSameObject(IUnknown *pUnk1, IUnknown *pUnk2)

{ assert(pUnk1 && pUnk2);

bool bResult = true;

if (pUnk1 != pUnk2)

{

HRESULT hr1, hr2; IUnknown *p1 = 0, *p2 = 0;

hr1 = pUnk1->QueryInterface(IID_IUnknown, (void **)&p1);

assert(SUCCEEDED(hr1));

hr2 = pUnk2->QueryInterface(IID_IUnknown, (void **)&p2);

assert(SUCCEEDED(hr2));

// compare the two pointer values, as these

// represent the identity of the object

// сравниваем значения двух указателей,

// так как они идентифицируют объект

bResult = (р1 == р2); p1->Release();

p2->Release();

}

return bResult;

}


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

Вооружившись знанием правил IUnknown, полезно исследовать реализацию объекта и убедиться в том, что она придерживается всех этих правил. Следующая реализация выставляет каждый из четырех интерфейсов средств транспорта и IUnknown:


class CarBoatPlane : public ICar, public IBoat, public IPlane

{

public:

// IUnknown methods – методы IUnknown

STDMETHODIMP QueryInterface(REFIID, void**);

STDMETHODIMP_(ULONG) AddRef(void);

STDMETHODIMP_(ULONG) Release(void);

// IVehicle methods – методы IVehicle

STDMETHODIMP GetMaxSpeed(long *pMax);

// ICar methods – методы

ICar STDMETHODIMP Brake(void);

// IBoat methods – методы