Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
412
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

121

Большая часть этого кода может показаться избыточной и ненужной. Но если внешний компонент сам агрегирован другим компонентом, выполнение описанных выше шагов становится критически важным. В примере из гл. 9 показан компонент, который агрегирует компонент, агрегирующий другой компонент.

«Вот и все, что необходимо сделать для реализации агрегирования», — сказал он, улыбаясь. В действительности, после того, как Вы написали корректный код агрегирования, он работает отлично, и о нем можно забыть. Однако после первой попытки его написать многие начинают называть его не «aggregation», а «aggravation»*.

Законченный пример

Реализуем компонент, который агрегирует некий интерфейс. В данном примере Компонент 1 поддерживает два интерфейса, так же как и в примере с включением. Однако здесь он реализует только IX. Он не будет ни реализовывать IY, ни передавать его вызовы реализации этого интерфейса Компонентом 2. Вместо этого, когда клиент запрашивает у Компонента 1 интерфейс IY, Компонент 1 возвращает указатель на интерфейс IY, реализуемый внутренним Компонентом 2. В листинге 8-3 представлен внешний компонент, а в листинге 8-4 — внутренний. Клиент остался практически неизменным; ему совершенно неважно, используем ли мы агрегирование или включение.

AGGRGATE\CMPNT1

//

// Cmpnt1.cpp - Компонент 1

//

// Интересные части кода выделены полужирным шрифтом

//

#include <iostream.h> #include <objbase.h>

#include "Iface.h" #include "Registry.h"

// Функция Trace

void trace(const char* msg) { cout << "Компонент 1:\t" << msg << endl; }

///////////////////////////////////////////////////////////

//

//Глобальные переменные

//Статические переменные

static HMODULE g_hModule =

NULL;

// Дескриптор модуля DLL

static

long

g_cComponents = 0;

//

Счетчик активных

компонентов

static

long

g_cServerLocks

= 0;

//

Число блокировок

 

// Дружественное имя компонента

const char g_szFriendlyName[] = "Основы COM, Глава 8 Пример 2, Компонент 1";

// Не зависящий от версии ProgID

const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1";

// ProgID

const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt1.1";

///////////////////////////////////////////////////////////

//

// Компонент A

//

class CA : public IX //, public IY

{

public:

// IUnknown

virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);

virtual ULONG

__stdcall AddRef();

virtual ULONG

__stdcall Release();

// Интерфейс IX

 

* Aggravation (англ.) — 1. Ухудшение, усугубление; 2. Раздражение, огорчение. — Прим. перев.

122

virtual void __stdcall Fx() { cout << "Fx" << endl; }

/* Компонент 1 агрегирует интерфейс IY, а не реализует его

// Интерфейс IY

virtual void __stdcall Fy() { m_pIY->Fy(); }

*/

//Конструктор

CA();

//Деструктор

~CA();

//Функция инициализации, вызываемая фабрикой класса для

//создания агрегируемого компонента

HRESULT __stdcall Init();

private:

//Счетчик ссылок long m_cRef;

//Указатель на интерфейс IY агрегированного компонента

//(Нам необязательно сохранять указатель на IY. Однако мы

//можем использовать его в QueryInterface)

IY* m_pIY;

// Указатель на IUnknown внутреннего компонента

IUnknown* m_pUnknownInner;

};

//

// Конструктор

//

CA::CA() : m_cRef(1), m_pUnknownInner(NULL)

{

::InterlockedIncrement(&g_cComponents);

}

//

// Деструктор

//

CA::~CA()

{

::InterlockedDecrement(&g_cComponents); trace("Самоликвидация");

//Предотвращение рекурсивного вызова деструктора следующей

//ниже пары AddRef/Release

m_cRef = 1;

//Учесть pUnknownOuter->Release в методе Init IUnknown* pUnknownOuter = this; pUnknownOuter->AddRef();

//Правильное освобождение указателя; возможен поинтерфейсный

//подсчет ссылок

m_pIY->Release();

// Освободить внутренний компонент if (m_pUnknownInner != NULL)

{

m_pUnknownInner->Release();

}

}

// Инициализировать компонент путем создания внутреннего компонента

HRESULT __stdcall CA::Init()

{

// Получить указатель на внешний IUnknown

123

//Поскольку этот компонент агрегируется, внешний IUnknown -

//это то же самое, что и указатель this

IUnknown* pUnknownOuter = this;

trace("Создать внутренний компонент");

HRESULT hr = ::CoCreateInstance(CLSID_Component2,

pUnknownOuter,

// IUnknown внешнего компонента

CLSCTX_INPROC_SERVER,

IID_IUnknown,

// При агрегировании - IUnknown

(void**)&m_pUnknownInner);

if (FAILED(hr))

{

trace("Не могу создать внутренний компонент"); return E_FAIL;

}

// Следующий вызов будет увеличивать счетчик ссылок внешнего компонента trace("Получить интерфейс IY внутреннего компонента");

hr = m_pUnknownInner->QueryInterface(IID_IY, (void**)&m_pIY); if (FAILED(hr))

{

trace("Внутренний компонент не поддерживает интерфейс IY"); m_pUnknownInner->Release();

return E_FAIL;

}

//Необходимо уменьшить счетчик ссылок внешнего компонента, увеличенный

//предыдущим вызовом. Для этого вызываем Release для указателя,

//переданного CoCreateInstance.

pUnknownOuter->Release(); return S_OK;

}

//

// Реализация IUnknown

//

HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)

{

if (iid == IID_IUnknown)

{

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

}

else if (iid == IID_IX)

{

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

}

else if (iid == IID_IY)

{

trace("Вернуть интерфейс IY внутреннего компонента");

#if 1

// Этот интерфейс можно запросить...

return m_pUnknownInner->QueryInterface(iid,ppv);

#else

//либо можно вернуть сохраненный указатель

*ppv = m_pIY;

//Проходим дальше, чтобы была вызвана AddRef

#endif

}

else

{

*ppv = NULL;

return E_NOINTERFACE;

}

reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK;

}

ULONG __stdcall CA::AddRef()

{

return ::InterlockedIncrement(&m_cRef);

124

}

ULONG __stdcall CA::Release()

{

if (::InterlockedDecrement(&m_cRef) == 0)

{

delete this; return 0;

}

return m_cRef;

}

///////////////////////////////////////////////////////////

//

// Фабрика класса

//

class CFactory : public IClassFactory

{

 

public:

 

// IUnknown

 

virtual HRESULT

__stdcall QueryInterface(const IID& iid, void** ppv);

virtual ULONG

__stdcall AddRef();

virtual ULONG

__stdcall Release();

// Интерфейс IClassFactory

virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid,

void** ppv); virtual HRESULT __stdcall LockServer(BOOL bLock);

// Конструктор

CFactory() : m_cRef(1) {}

// Деструктор

~CFactory() {}

private:

long m_cRef; };

//

// Реализация IUnknown для фабрики класса

//

HRESULT __stdcall CFactory::QueryInterface(REFIID iid, void** ppv)

{

IUnknown* pI;

if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))

{

pI = static_cast<IClassFactory*>(this);

}

else

{

*ppv = NULL;

return E_NOINTERFACE;

}

pI->AddRef(); *ppv = pI; return S_OK;

}

ULONG __stdcall CFactory::AddRef()

{

return ::InterlockedIncrement(&m_cRef);

}

ULONG __stdcall CFactory::Release()

{

if (::InterlockedDecrement(&m_cRef) == 0)

{

delete this;

125

return 0;

}

return m_cRef;

}

//

// Реализация IClassFactory

//

HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid,

void** ppv)

{

//Агрегирование не поддерживается if (pUnknownOuter != NULL)

{

return CLASS_E_NOAGGREGATION;

}

//Создать компонент

CA* pA = new CA; if (pA == NULL)

{

return E_OUTOFMEMORY;

}

// Инициализировать компонент

HRESULT hr = pA->Init(); if (FAILED(hr))

{

// Ошибка инициализации. Удалить компонент. pA->Release();

return hr;

}

// Получить запрошенный интерфейс hr = pA->QueryInterface(iid, ppv); pA->Release();

return hr;

}

// LockServer

HRESULT __stdcall CFactory::LockServer(BOOL bLock)

{

if (bLock)

{

::InterlockedIncrement(&g_cServerLocks);

}

else

{

::InterlockedDecrement(&g_cServerLocks);

}

return S_OK;

}

///////////////////////////////////////////////////////////

//

// Экспортируемые функции

//

STDAPI DllCanUnloadNow()

{

if ((g_cComponents == 0) && (g_cServerLocks == 0))

{

return S_OK;

}

else

{

return S_FALSE;

}

}

126

//

// Получение фабрики класса

//

STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)

{

//Можем ли мы создать такой компонент? if (clsid != CLSID_Component1)

{

return CLASS_E_CLASSNOTAVAILABLE;

}

//Создать фабрику класса

CFactory* pFactory = new CFactory;

// В конструкторе нет Addref

if (pFactory == NULL)

 

{

 

return E_OUTOFMEMORY;

 

}

 

// Получить запрошенный интерфейс

HRESULT hr = pFactory->QueryInterface(iid, ppv); pFactory->Release();

return hr;

}

//

// Регистрация сервера

//

STDAPI DllRegisterServer()

{

return RegisterServer(g_hModule, CLSID_Component1, g_szFriendlyName, g_szVerIndProgID, g_szProgID);

}

STDAPI DllUnregisterServer()

{

return UnregisterServer(CLSID_Component1, g_szVerIndProgID, g_szProgID);

}

///////////////////////////////////////////////////////////

//

// Информация о модуле DLL

//

BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, void* lpReserved)

{

if (dwReason == DLL_PROCESS_ATTACH)

{

g_hModule = hModule;

}

return TRUE;

}

Листинг 8-3 Реализация внешнего (агрегирующего) компонента

AGGRGATE\CMPNT2

//

//Cmpnt2.cpp - Компонент 2

//Помните, что изменения в фабрике класса отмечены полужирным шрифтом

//

#include <iostream.h>

127

#include <objbase.h>

#include "Iface.h" #include "Registry.h"

void trace(const char* msg) { cout << "Компонент 2:\t" << msg << endl; }

///////////////////////////////////////////////////////////

//

//Глобальные переменные

//Статические переменные

static HMODULE g_hModule =

NULL;

// Дескриптор

модуля DLL

static

long

g_cComponents = 0;

// Счетчик активных компонентов

static

long

g_cServerLocks

= 0;

// Количество

блокировок

// Дружественное имя компонента const char g_szFriendlyName[]

="Основы COM, Глава 8 Пример 2, Компонент 2";

//Независящий от версии ProgID

const char g_szVerIndProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt2";

// ProgID

const char g_szProgID[] = "InsideCOM.Chap08.Ex2.Cmpnt2.1";

///////////////////////////////////////////////////////////

//

// Неделегирующий интерфейс IUnknown

//

struct INondelegatingUnknown

{

virtual HRESULT __stdcall NondelegatingQueryInterface(const IID&, void**) = 0;

virtual ULONG __stdcall NondelegatingAddRef() = 0; virtual ULONG __stdcall NondelegatingRelease() = 0;

};

///////////////////////////////////////////////////////////

//

// Компонент B

//

class CB : public IY, public INondelegatingUnknown

{

public:

// Делегирующий IUnknown

virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)

{

trace("Делегирующий QueryInterface");

return m_pUnknownOuter->QueryInterface(iid, ppv);

}

virtual ULONG __stdcall AddRef()

{

trace("Делегировать AddRef"); return m_pUnknownOuter->AddRef();

}

virtual ULONG __stdcall Release()

{

trace("Делегировать Release"); return m_pUnknownOuter->Release();

}

// Неделегирующий IUnknown virtual HRESULT __stdcall

NondelegatingQueryInterface(const IID& iid, void** ppv);

virtual

ULONG

__stdcall

NondelegatingAddRef();

virtual

ULONG

__stdcall

NondelegatingRelease();

128

// Интерфейс IY

virtual void __stdcall Fy() { cout << "Fy" << endl; }

// Конструктор

CB(IUnknown* m_pUnknownOuter);

// Деструктор

~CB();

private:

long m_cRef;

IUnknown* m_pUnknownOuter; };

//

// Реализация IUnknown

//

HRESULT __stdcall CB::NondelegatingQueryInterface(const IID& iid, void** ppv)

{

if (iid == IID_IUnknown)

{

// !!! ПРИВЕДЕНИЕ ТИПА ОЧЕНЬ ВАЖНО !!!

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

}

else if (iid == IID_IY)

{

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

}

else

{

*ppv = NULL;

return E_NOINTERFACE;

}

reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK;

}

ULONG __stdcall CB::NondelegatingAddRef()

{

return ::InterlockedIncrement(&m_cRef);

}

ULONG __stdcall CB::NondelegatingRelease()

{

if (::InterlockedDecrement(&m_cRef) == 0)

{

delete this; return 0;

}

return m_cRef;

}

//

// Конструктор

//

CB::CB(IUnknown* pUnknownOuter) : m_cRef(1)

{

::InterlockedIncrement(&g_cComponents);

if (pUnknownOuter == NULL)

{

trace("Не агрегируется; использовать неделегирующий IUnknown"); m_pUnknownOuter = reinterpret_cast<IUnknown*>

(static_cast<INondelegatingUnknown*> (this));

}

else

{

129

trace("Агрегируется; делегировать внешнему IUnknown"); m_pUnknownOuter = pUnknownOuter;

}

}

//

// Деструктор

//

CB::~CB()

{

::InterlockedDecrement(&g_cComponents); trace("Саморазрушение");

}

///////////////////////////////////////////////////////////

//

// Фабрика класса

//

class CFactory : public IClassFactory

{

public:

// IUnknown

virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);

virtual

ULONG

__stdcall

AddRef();

virtual

ULONG

__stdcall

Release();

// Интерфейс IClassFactory

virtual HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter, const IID& iid,

void** ppv); virtual HRESULT __stdcall LockServer(BOOL bLock);

// Конструктор

CFactory() : m_cRef(1) {}

// Деструктор

~CFactory() {}

private:

long m_cRef; };

//

// Реализация IUnknown для фабрики класса

//

HRESULT __stdcall CFactory::QueryInterface(const IID& iid, void** ppv)

{

if ((iid == IID_IUnknown) || (iid == IID_IClassFactory))

{

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

}

else

{

*ppv = NULL;

return E_NOINTERFACE;

}

reinterpret_cast<IUnknown*>(*ppv)->AddRef(); return S_OK;

}

ULONG __stdcall CFactory::AddRef()

{

return ::InterlockedIncrement(&m_cRef);

}

ULONG __stdcall CFactory::Release()

{

if (::InterlockedDecrement(&m_cRef) == 0)

{

delete this;

130

return 0;

}

return m_cRef;

}

//

// Реализация IClassFactory

//

HRESULT __stdcall CFactory::CreateInstance(IUnknown* pUnknownOuter, const IID& iid,

void** ppv)

{

// При агрегировании iid должен быть IID_IUnknown

if ((pUnknownOuter != NULL) && (iid != IID_IUnknown))

{

return CLASS_E_NOAGGREGATION;

}

// Создать компонент

CB* pB = new CB(pUnknownOuter); if (pB == NULL)

{

return E_OUTOFMEMORY;

}

// Получить запрошенный интерфейс

HRESULT hr = pB->NondelegatingQueryInterface(iid, ppv); pB->NondelegatingRelease();

return hr;

}

// LockServer

HRESULT __stdcall CFactory::LockServer(BOOL bLock)

{

if (bLock)

{

::InterlockedIncrement(&g_cServerLocks);

}

else

{

::InterlockedDecrement(&g_cServerLocks);

}

return S_OK;

}

///////////////////////////////////////////////////////////

//

// Экспортируемые функции

//

STDAPI DllCanUnloadNow()

{

if ((g_cComponents == 0) && (g_cServerLocks == 0))

{

return S_OK;

}

else

{

return S_FALSE;

}

}

//

// Получение фабрики класса

//

STDAPI DllGetClassObject(const CLSID& clsid, const IID& iid, void** ppv)

{

// Можем ли мы создать такой компонент? if (clsid != CLSID_Component2)

{

Соседние файлы в предмете Программирование на C++