Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
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.срр: реализация фабрики
// для кокласса 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)
{
if(riid == IID_IUnknown)
{
*ppv = (IUnknown*)this;
}
else if(riid == IID_IClassFactory)
{
*ppv = (IdassFactory*) this;
}
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
(IUnknown*)(*ppv)) — >AddRef;
return S OK;
}
//IClassFactory
STDMETHODIMP CoJournaiFactory::Createlnstance(
LPUNKNOWN pUnkOuter, REFIID riid, void** ppv)
{
if(pUnkOuter!= NULL)
{
return СLASS_E_NOAGGREGATION;
}
CoJournal* pJournalObj = NULL;
HRESULT hr;
pJournalObj = new CoJournal;
hr = pJournalObj — > QueryInterface(riid, ppv);
if (FAILED(hr))
delete pJournalObj;
return hr;
}
STDMETHODIMP CoJournalFactory::LockServer(BOOL fLock)
{
if (fLock)
++g_lockCount;
else
– -g_lockCount;
return S OK;
}
Заканчивая разговор о фабрике класса нужно заметить, что для нее не нужно задавать GUID.
Сервер в процессе клиента
Итак, для активации некоторого СОМ объекта необходимо создать фабрику класса для соответствующего класса и получить указатель на интерфейс IClassFactory. Далее, используя этот интерфейс, можно создать любое число экземпляров этого кокласса и получить указатели на любые реализуемые коклассом интерфейсы. Но как создать фабрику класса?
Все, что достаточно знать клиенту о коклассе, это его глобальный
идентификатор (GUID). Зная этот идентификатор, клиент может воспользоваться функцией CoGetClassObject, которая заставит менеджер управления сервисом найти и загрузить нужный сервер (в котором "живет" нужный кокласс), активизировать фабрику класса для этого кокласса и возвратить клиенту указатель на интерфейс IClassFactory.Всю необходимую информацию менеджер получает из реестра системы. Подробнее это будет обсуждаться далее, пока достаточно заметить, что реестр представляет собой специальную базу данных, используя которую, в частности, по глобальному идентификатору кокласса можно узнать тип сервера, в котором этот кокласс "живет" (сервер в процессе клиента, сервер в другом процессе на этой же машине или сервер на удаленной машине), путь к серверу (для серверов на данной машине) или путь к удаленной машине (для сервера на удаленной машине).
Далее работа менеджера зависит от типа сервера.
Пока мы строим сервер в процессе клиента, реализуемый в виде dll. Для этого, при работе в Visual C++, можно создать пустое рабочее пространство проекта Win32 DLL с именем PubInPrосServer. В этом проекте нужно создать (или перенести созданные в другом месте) классы CoBook, CoJournal, CoBookFactory, СоJournalFactory. Там же ДОЛЖНЫ находиться файлы с определениями интерфейсов IPub, IBook, IJournal, файл с GUID для всех интерфейсов и коклассов iid.h и (как советует Э.Трельсен в книге [3]) следующий файл iid.cpp
// iid.cpp: гарантирует автоматический вызов <initguid.h>
// перед "iid.h"
#include <windows.h>
#include <initguid.h>
#include "iid.h"
Теперь нужно создать файл, имя которого совпадает с именем проекта — PublnProcServer.cpp:
#include "CoBookFactory.h"
#include "CoJournalFactory.h"
ULONG g_lockCount = 0;
ULONG g_objCount = 0;
STDAPI DllCanUnloadNow
{
if (g_lockCount == 0 && g_objCount == 0)
return S_OK;
else
return S_FALSE;
}
STDAPI DllGetClassObject(REFCLSID rclsid,
REFIID riid, void** ppv)
{
HRESULT hr;
CoBookFactory* pBookFact = NULL;
CoJournaiFactory* pJournalFact = NULL;
if (rclsid == CLSID_CoBook)
{
pBookFact = new CoBookFactory;
hr = pBookFact —> QueryInterface(riid, ppv);
if (FAILED(hr))
delete pBookFact;
return hr;
}
else if (rclsid == CLSID_CoJournal)
{
pJournalFact = new CoJournaiFactory;
hr = pJournalFact->QueryInterface(riid, ppv);
if (FAILED(hr))
delete pJournalFact;
return hr;
}
else
return СLASS_E_CLASSNOTAVAILABLE;
}
В файле PubInProcServer.cpp определяются и инициализируются нулем две глобальные переменные g_lockCount, g_objCount — соответственно счетчики числа блокировок сервера в памяти и числа активных объектов.