Интернет-журнал "Домашняя лаборатория", 2007 №6 - Усманов
Шрифт:
Интервал:
Закладка:
#include "CoBook.h"
class CoBookFactory: public iciassFactory
{
public:
// Конструктор и деструктор
CoBookFactory ();
virtual ~CoBookFactory();
//IUnknown
STDMETHODIMP Querylnterface(REFIID riid, void** pIFace);
STDMETHODIMP_(ULONG)AddRef();
STDMETHODIMP_(ULONG)Release();
//IClassFactory
STDMETHODIMP LockServer(BOOL fLock);
STDMETHODIMP Createlnstance(LPUNKNOWN pUnkOuter,
REFIID riid, void** ppv);
private:
ULONG m_refCount; // Счетчик числа сылок на объект
};
#endif
Здесь стандартным образом объявлены конструктор, деструктор, три метода интерфейса IUnknown и два метода интерфейса IClassFactory. Семантика всех этих методов уже была изложена ранее. Дополнительно нужно пояснить смысл параметров методов LockServer и Createlnstance.
Параметр fLock принимает значение TRUE — заблокировать сервер, или FALSE — разблокировать сервер. Сервер ведет подсчет всех блокировок, установленных всеми его клиентами, и разрешает выгрузить себя из памяти, если только не осталось активных объектов и общий счет блокировок в памяти равен нулю.
Первый параметр метода CreateInstance используется только при агрегации, которая обсуждалась ранее. Именно, если класс CоBооk проектируется с возможностью его агрегации в другой СОМ класс (класс CоBооk готов предоставить возможность другому классу выдавать интерфейсы класса v за свои), то через параметр pUnkUuter (тип которого определяется в <unknwn.h> как typedef iunknown RPC_FAR * LPUKNOWN) он получает указатель интерфейса IUnknown того объекта, который его собрался агрегировать. Если CоBооk не проектировался с возможностью агрегации (так и есть в нашем случае), то он ожидает получение в этом параметре значения NULL, в противном случае тут будет выдана ошибка СLASS_E_NOAGGREGATION.
Второй параметр метода CreateInstance задает ссылку на идентификатор желаемого интерфейса, а третий возвращает запрошенный интерфейс (если он имеется).
Реализация фабрики класса CoBookFactory для класса CоBооk представлена ниже.
//////////////////////////////////////////////////
// CoBookFactory.срр: реализация класса CoBookFactory —
// фабрики класса для класса CoBook.
//////////////////////////////////////////////////
#include "CoBookFactory.h"
extern ULONG g_lockCount; // Счетчик блокировок сервера в памяти extern ULONG
g_objCount; // Счетчик активных объектов
//////////////////////////////////////////////////
// Конструктор и деструктор
//////////////////////////////////////////////////
CoBookFactory::CoBookFactory()
{
m_refCount = 0;
g_objCount++;
}
CoBookFactory::~CoBookFactory()
{
g_obj Count--;
}
//IUnknown
STDMETHODIMP_(ULONG) CoBookFactory::AddRef()
{
return ++m_refCount;
}
STDMETHODIMP_(ULONG) CoBookFactory::Release()
{
if (--m_refCount == 0)
{
delete this;
return 0;
}
else
return m_refCount;
}
STDMETHODIMP CoBookFactory::Querylnterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
{
*ppv = (IUnknown*)this;
}
else if(riid == IID_IClassFactory)
{
*ppv = (IClassFactory*) this;
{
else
{
*ppv = NULL;
return E NOINTERFACE;
}
((IUnknown*)(*ppv)) — > AddRef();
return S OK;
}
//ICiassFactory
STDMETHODIMP CoBookFactory::Createlnstance(
LPUNKNOWN pUnkOuter, REFIID riid, void** ppv)
{
if(pUnkOuter!= NULL)
{
return СLASS_E_NOAGGREGATION;
}
CoBook* pBookObj = NULL;
HRESULT hr;
pBookObj = new CoBook;
hr = pBookObj —> QueryInterface (riid, ppv);
if (FAILED(hr))
delete pBookObj;
return hr;
}
STDMETHODIMP CoBookFactory::LockServer(BOOL fLock)
{
if (fLock)
++g_lockCount;
else
--g_lockCount;
return S_OK;
}
В конструкторе обнуляется счетчик ссылок на фабрику класса — член класса m ref count (как всегда при создании любого объекта СОМ) и увеличивается на единицу глобальный счетчик числа активных объектов данного сервера (g objCount).
В деструкторе на единицу уменьшается глобальный счетчик активных объектов данного сервера.
Реализация методов интерфейса IUnknown стандартная и уже обсуждалась ранее.
Перейдем теперь к обсуждению реализации методов интерфейса IClassFactory и начнем с метода CreateInstance.
Во-первых, не предполагается агрегация класса CоBооk. В связи с этим выдается ошибка CLASS_E_NOAGGREGATION, если первый параметр не равен NULL.
В следующих строках кода и проявляется связь данной фабрики класса именно с классом CоBооk. Создается экземпляр класса CоBооk и запрашивается указатель на некоторый интерфейс этого класса:
CoBook* pBookObj = NULL;
HRESULT hr;
pBookObj = new CoBook;
hr = pBookObj — > QueryInterface(riid, ppv);
При неудаче получения интерфейса, созданный объект уничтожается.
В методе LockServer глобальный счетчик блокировок сервера в памяти увеличивается или уменьшается на единицу в зависимости от значения параметра fLock.
Совершенно аналогично определяется и реализуется фабрика класса CoJournalFactory для кокласса СоJournal.
//////////////////////////////////////////////////
// СоJournalFactory.h: заголовочный файл для класса
// CoJournaiFactory — фабрики класса для класса CoJournal
//////////////////////////////////////////////////
#ifndef _CoJournalFactory_
#define _CoJournalFactory
#include "CoJournal.h"
class CoJournalFactory: public IClassFactory
{
public:
CoJournalFactory ();
virtual ~CoJournalFactory();
//IUnknown
STDMETHODIMP Querylnterface(REFIID riid, void** pIFace);
STDMETHODIMP_(ULONG)AddRef();
STDMETHODIMP_(ULONG)Release();
//IClassFactory
STDMETHODIMP LockServer(BOOL fLock);
STDMETHODIMP Createlnstance(LPUNKNOWN pUnkOuter,
REFIID riid, void** ppv);
private:
ULONG m_refCount;
};
#endif
И теперь реализация фабрики класса СоJournalFactory для класса CoJournal.
//////////////////////////////////////////////////
// СоJournalFactory.срр: реализация фабрики класса СоJournalFactory
// для кокласса CoJournal
//////////////////////////////////////////////////
#include "СоJournalFactory.h"
extern ULONG g_lockCount;
extern ULONG g_objCount;
//////////////////////////////////////////////////
// Конструктор и деструктор
//////////////////////////////////////////////////
CoJournalFactory::СоJournalFactory ()
{
m_refCount = 0;
g_objCount++;
}
CoJournalFactory::~CoJournalFactory()
{
g_obj Count-;
}
//IUnknown
STDMETHODIMP_(ULONG) CoJournalFactory::AddRef() {
return ++m_refCount;
}
STDMETHODIMP_(ULONG) CoJournalFactory::Release()
{
if (-m_refCount == 0)
{
delete this;
return 0;
}
else
return m refCount;
}
STDMETHODIMP CoJournalFactory::Querylnterface(REFIID riid, void** ppv)
{