Дональд Бокс - Сущность технологии СОМ. Библиотека программиста
- Название:Сущность технологии СОМ. Библиотека программиста
- Автор:
- Жанр:
- Издательство:Питер
- Год:2001
- Город:СПб
- ISBN:5-318-00058-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Дональд Бокс - Сущность технологии СОМ. Библиотека программиста краткое содержание
В этой книге СОМ исследуется с точки зрения разработчика C++. Написанная ведущим специалистом по модели компонентных объектов СОМ, она раскрывает сущность СОМ, помогая разработчикам правильно понять не только методы модели программирования СОМ, но и ее основу. Понимание мотивов создания СОМ и ее аспектов, касающихся распределенных систем, чрезвычайно важно для тех разработчиков, которые желают пойти дальше простейших приложений СОМ и стать по-настоящему эффективными СОМ-программистами. Показывая, почему СОМ для распределенных систем (Distributed СОМ) работает именно так, а не иначе, Дон Бокс дает вам возможность применять эту модель творчески и эффективно для ежедневных задач программирования.
Сущность технологии СОМ. Библиотека программиста - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
HRESULT Advise([in] IUnknown * pUnkSink, [out] DWORD * pdwCookie);
// stop holding/using the pointer associated with dwCookle
// прекращаем хранение/использование указателя, связанного с dwCookie
HRESULT Unadvise([in] DWORD dwCookie);
// get information about currently held pointers
// получаем информацию об имеющихся в данный момент указателях
HRESULT EnumConnections([out] IEnumConnections ** ppEnum);
}
Как показано на рис. 7.9, объекты представляют отдельную реализацию этого интерфейса каждому типу интерфейса, который может быть использован объектом в качестве интерфейса обратного вызова. Ввиду того, что IConnectionPoint не выставлен как часть единицы идентификации объекта, он не может быть обнаружен посредством QueryInterface. Вместо этого в СОМ предусмотрен второй интерфейс, который выставлен как часть единицы идентификации объекта, которая позволяет клиентам запрашивать реализацию IConnectionPoint, соответствующую отдельному типу интерфейса обратного вызова:
[object,uuid(B196B284-BAB4-101A-B69C-00AA00341D07)]
interface IConnectionPointContainer : IUnknown {
// get all possible IConnectionPoint implementations
// получаем все возможные реализации IConnectionPoint
HRESULT EnumConnectionPoints([out] IEnumConnectionPoints ** ppEnum);
// get the IConnectionPoint implementation for riid
// получаем реализацию IConnectionPoint для riid
HRESULT FindConnectionPoint([in] REFIID riid, [out] IConnectionPoint ** ppCP);
}

Как показано на рис. 7.9, каждая реализация IConnectionPoint выставляется из отдельной СОМ-единицы идентификации.
С учетом вышеупомянутых определений интерфейса клиент мог бы связать свою реализацию IShutdownNotify с объектом следующим образом:
HRESULT HookupShutdownCallback(IUnknown *pUnkObject,
IShutdownNotify *pShutdownNotify,
DWORD &rdwCookie)
{
IConnectionPointContainer *pcpc = 0;
HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc);
if (SUCCEEDED(hr)) {
IConnectionPoint *pcp = 0;
hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp);
if (SUCCEEDED(hr)) {
hr = pcp->Advise(pShutdownNotify, &rdwCookie);
pcp->Release();
}
pcpc->Release();
}
}
Соответствующий код для разрыва связи выглядит так:
HRESULT TeardownShutdownCallback(IUnknown *pUnkObject, DWORD dwCookie)
{
IConnectionPointContainer *pcpc = 0;
HRESULT hr = pUnkObject->QueryInterface(IID_IConnectionPointContainer, (void**)&pcpc);
if (SUCCEEDED(hr)) {
IConnectionPoint *pcp = 0;
hr =pcpc->FindConnectionPoint(IID_IShutdownNotify,&pcp);
if (SUCCEEDED(hr)) {
hr = pcp->Unadvise(dwCookie);
pcp->Release();
}
pcpc->Release();
}
}
Отметим, что в обоих примерах клиент использует метод IConnectionPointContainer::FindConnectionPoint для вызова из объекта его IShutdownNotify-реализации IConnectionPoint. Если объект отклоняет вызов FindConnectionPoint, это говорит о том, что он не понимает семантику интерфейса IShutdownNotify. Это оберегает пользователя от прикрепления произвольных интерфейсов обратного вызова к объекту без полного согласия на это разработчика объекта.
Как и в случае с IUnknown, реализации IConnectionPointContainer и IConnectionPoint в значительной степени типичны. Объекту C++ требуется отдельная единица идентификации СОМ для каждого типа экспортируемого интерфейса, который он предполагает поддерживать. Одна из методик реализации ConnectionPoint состоит в использовании того варианта методики вложения класса/композиции, которая учитывает различия в отношениях тождественности:
class Surfboard : public ISurfboard,
public IHazardousDevice,
public ISharkBait,
public IConnectionPointContainer {
LONG m_cRef; // СОM reference count
// счетчик ссылок СОМ
// Surfboards don't support multiple outbound interfaces
// of a given type, so it simply declares single pointers
// of each possible type of callback interface
// Surfboard не поддерживает несколько экспортируемых
// интерфейсов заданного типа, поэтому он просто
// объявляет одиночные указатели каждого возможного
// типа интерфейса обратного вызова
IShutdownNotify *m_pShutdownNotify;
ISurfboardUser *m_pSurfer;
// to deal with identity relationship of IConnectionPoint,
// define an IShutdownNotify-specific nested class + member
// для работы с отношением тождественности
// IConnectionPoint, определяем специфический для
// IShutdownNotify вложенный класс+член
class XCPShutdownNotify : public IConnectionPoint {
Surfboard *This(void);
// use fixed offset
// испопьзуем постоянное смещение
// IUnknown methods...
// методы IUnknown...
// IConnectionPoint methods...
// методы IConnectionPoint...
} m_xcpShutdownNotify;
// define an ISurfboardUser-specific nested class + member
// определяем специфический для IShutdownNotify вложенный класс+член
class XCPSurfboardUser : public IConnectionPoint {
Surfboard *This(void);
// use fixed offset
// используем постоянное смещение
// IUnknown methods...
// методы IUnknown...
// IConnectionPoint methods...
// методы IConnectionPoint...
} m_xcpSurfboardUser;
// IUnknown methods...
// методы IUnknown...
// ISurfboard methods...
// методы ISurfboard...
// IHazardousDevice methods...
// методы IHazardousDevice...
// ISharkBait methods...
// методы ISharkBait...
// IConnectionPointContainer methods...
// методы IConnectionPointContainer...
};
Следует указать, что экземпляры класса Surfboard будут иметь две отдельные реализации IConnectionPoint, одна из которых используется для присоединения интерфейсов обратного вызова IShutdownNotify, а вторая – для присоединения интерфейсов ISurfboardUser. Эти две реализации разделены на отдельные классы C++, что позволяет каждой реализации IConnectionPoint иметь свои собственные уникальные реализации IUnknown и IConnectionPoint. В частности, может иметься три отдельных реализации QueryInterface со своими собственными наборами интерфейсных указателей, которые могут быть выделены для создания трех отдельных СОМ-копий.
Из приведенного выше определения класса следует такая QueryInterface-peaлизация основного класса Surfboard:
STDMETHODIMP Surfboard::QueryInterface(REFIID riid, void**ppv)
{
if (riid == IID_IUnknown || riid == IID_ISurfboard)
*ppv = static_cast(this);
else if (riid == IID_IHazardousDevice)
*ppv = static_cast< IHazardousDevice *>(this);
else if (riid == IID_ISharkBait)
*ppv = static_cast(this);
else if (riid == IID_IConnectionPointContainer)
*ppv = static_cast(this);
else
return (*ppv = 0), E_NOINTERFACE;
((IUnknown*)*ppv)->AddRef();
return S_OK;
}
Отметим, что доступ к интерфейсу IConnectionPoint не может быть осуществлен через эту главную реализацию QueryInterface. Каждый из методов QueryInterface вложенного класса будет выглядеть примерно так:
STDMETHODIMP Surfboard::XCPShutdownNotify::QueryInterface(REFIID riid, void**ppv)
{
if (riid == IID_IUnknown || riid == IID_IConnectionPoint)
*ppv = static_cast(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)
Читать дальшеИнтервал:
Закладка: