реализацию QueryInterface. Каждый из методов QueryInterface вложенного класса будет выглядеть примерно так:

STDMETHODIMP Surfboard::XCPShutdownNotify::QueryInterface(REFIID riid, void**ppv)

{

if (riid == IID_IUnknown || riid == IID_IConnectionPoint)

*ppv = static_cast<IConnectionPoint *>(this);

else

return (*ppv = 0), E_NOINTERFACE;

((IUnknown*)*ppv)->AddRef();

return S_OK;

}

Эту же реализацию можно было бы применить и к классу XCPSurfboardUser. Между объектом Surfboard и двумя подобъектами, которые реализуют интерфейс IConnectionPoint не существует идентичности.

Для того чтобы объект Surfboard не уничтожил себя раньше времени, подобъекты администратора соединений просто делегируют вызовы своих методов AddRef и Release в содержащий их объект surfboard:

STDMETHODIMP_(ULONG) Surfboard::XCPShutdownNotify::AddRef(void)

{

return This()->AddRef();

/* AddRef containing object */

/* AddRef объекта-контейнера */

}

STDMETHODIMP_(ULONG) Surfboard::XCPShutdownNotify::Release(void)

{

return This()->Release();

/* Release containing object */

/* Release объекта-контейнера */

}

В приведенных выше методах предполагается, что метод This возвращает указатель на объект- контейнер Surfboard, используя вычисление некоторого постоянного смещения.

Клиенты находят интерфейсы объекта IConnectionPoint посредством вызова метода объекта FindConnectionPoint, который для класса Surfboard мог бы выглядеть примерно так:

STDMETHODIMP Surfboard::FindConnectionPoint(REFIID riid, IConnectionPoint **ppcp)

{

if (riid == IID_IShutdownNotify)

*ppcp = IID_IShutdownNotify;

else if (riid == IID_ISurfboardUser)

*ppcp = &m_xcpSurfboardUser;

else

return (*ppcp = 0), CONNECT_E_NOCONNECTION;

(*ppcp)->AddRef();

return S_OK;

}

Отметим, что объект выдает интерфейсные указатели IConnectionPoint только при запросе тех интерфейсов, на которые он сможет сделать обратный запрос. Необходимо указать также на поразительное сходство с большинством реализации QueryInterface. Основное различие состоит в том, что QueryInterface имеет дело с импортируемыми (inbound) интерфейсами, в то время как FindConnectionPoint – с экспортируемыми (outbound) интерфейсами.

Поскольку метод IConnectionPoint::Advise принимает только интерфейс IUnknown, статически типизированный как интерфейсный указатель обратного вызова[1], то реализации Advise должны использовать QueryInterface для того, чтобы привязать указатель обратного вызова к соответствующему типу интерфейса:

STDMETHODIMP Surfboard::XCPShutdownNotify::Advise(IUnknown *pUnk, DWORD *pdwCookie)

{

assert (pdwCookie && pUnk);

*pdwCookie = 0;

if (This()->m_pShutdownNotify) // already have one

// уже имеем один

return CONNECT_E_ADVISELIMIT;

// QueryInterface for correct callback type

// QueryInterface для корректирования типа обратного вызова

HRESULT hr = pUnk->QueryInterface(IID_IShutdownNotify,

(void**)&(This()->m_pShutdownNotify));

if (hr == E_NOINTERFACE)

hr = CONNECT_E_NOCONNECTION;

if (SUCCEEDED(hr)) // make up a meaningful cookie

// готовим значимый маркер

*pdwCookie = DWORD(This()->m_pShutdownNotify);

return hr;

}

Напомним, что QueryInterface неявно вызывает AddRef, что означает следующее: объект Surfboard теперь хранит ссылку обратного вызова, причем она остается легальной за пределами области действия метода Advise. Отметим также, что если объект обратного вызова не реализует соответствующий интерфейс, то результирующий HRESULT преобразуется в CONNECT_E_NOCONNECTION. Если же сбой QueryInterface последовал по какой-либо иной причине, то HRESULT от QueryInterface передается вызывающей программе[2].

Основанный на приведенной выше реализации Advise соответствующий метод Unadvise имеет следующий вид:

STDMETHODIMP Surfboard::XCPShutdownNotify::Unadvise(DWORD dwCookie)

{

// ensure that the cookie corresponds to a valid connection

// убеждаемся, что маркер соответствует допустимому соединению

if (DWORD (This()->m_pShutdownNotify) != dwCookie)

return CONNECT_E_NOCONNECTION;

// release the connection

// освобождаем соединение

This()->m_pShutdownNotify->Release();

This()->m_pShutdownNotify = 0;

return S_OK;

}

В интерфейсе IConnectionPoint имеется три дополнительных вспомогательных метода, два из которых реализуются тривиально:

STDMETHODIMP Surfboard::XCPShutdownNotify::GetConnectionInterface( IID *piid)

{

assert (piid);

// return IID of the interface managed by this subobject

// возвращаем IID интерфейса, управляемого этим подобъектом

*piid = IID_IShutdownNofify;

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

0

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

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