Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
// 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
}
В файле PubInProcServer.cpp определяются и инициализируются нулем две глобальные переменные g_lockCount, g_objCount — соответственно счетчики числа блокировок сервера в памяти и числа активных объектов.
Далее дается реализация двух экспортируемых из dll функций — DllGetClassObject и DllCanUnioadNow. Используя первую, менеджер управления сервисом (из СОМ) сможет активизировать фабрику класса запрашиваемого кокласса и получить указатель на интерфейс ICiassFactory соответствующей фабрики класса. Вторая функция используется менеджером на этапе принятия решения об удалении сервера из памяти.
Рассмотрим подробнее реализацию функции DllGetClassObject.
Эта функция получает в качестве аргументов ссылку на GUID нужного кокласса, ссылку на желаемый интерфейс фабрики класса этого кокласса (обычно IID_IClassFactory) и в качестве выходного параметра возвращает указатель на запрашиваемый интерфейс. Возвращаемое функцией значение типа HRESULT говорит об успехе или неудаче операции. В последнем случае можно выяснить причину неудачи. Дня проверки успешности операции можно использовать определенные в СОМ макроопределения SUCCEEDED и FAILED, анализирующие старший бит возвращенного значения типа HRESULT.
Реализация функции DllCanUnioadNow тривиальна.
Обычно dll Сервер Экспортирует еще две функции: DllRegisterServer и DllUnregisterServer. Эти функиции должны обеспечить саморегистрацию сервера в реестре. В данном курсе этот вопрос не рассматривается, и регистрация разрабатываемого сервера будет проведена вручную с помощью редактора реестра.
Далее надо включить в проект стандартный DEF-файл PubInProcServer.def, который перечисляет экспортируемые функции:
LIBRARY "PUBINPROCSERVER"
EXPORTS
DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
Здесь название библиотеки должно совпадать с названием проекта, private используется для того, чтобы компоновщик не поместил имена этих функций в библиотеку импорта, т. к. они будут использоваться только СОМ.
Регистрация сервера в реестре
Теперь сервер готов, но для его использования необходимо внести некоторые данные в реестр системы. Сделаем это, используя редактор реестра — regedit.ехе. Для внесения минимальной информации о сервере внесем в реестр следующие данные:
• CLSID и соответствующие ProgID и путь к серверу
Программный идентификатор (ProgID) используется некоторыми программами как некоторая замена CLSID (требуется только локальная уникальность). Формат для ProgID
имя_сервера. имя_кокласса. Для CoBook это PuInProcServer.CoBook.
Под ключом HKEY_CLASSES_ROOT нужно найти ключ CLSID и под ним создать раздел {49F00760-7238-11d5-98C7-000001223694}. Это CLSID для кокласса CoBook. Для задания соответствующего ProgID следует для данного раздела создать подраздел с именем ProgID и в качестве значения для параметра по умолчанию взять PubInProcServer.CoBook.
Аналогично, под ключом HKEY_CLASSES_ROOT CLSID нужно еще создать раздел {49F00761-7238-11d5-98C7-000001223694}. Это CLSID ДЛЯ кокласса CoJournal. Для задания соответствующего ProgID следует для данного раздела создать подраздел с именем ProgID и в качестве значения для параметра по умолчанию взять PubInProcServer.CoJournal.
Для задания пути к серверу (один сервер для двух коклассов), надо под ключом
НКЕY_CLASSЕS_ROOT CLSID {49F00760-7238-11d5-98С7-000001223694} создать раздел InProcServer32 и в качестве параметра по умолчанию задать полный путь к dll серверу.
Это же повторяется для CLSID кокласса CoJournal.
• ProgID и соответствующий CLSID
Под ключом НКЕY_CLASSЕS_ROOT надо создать разделы PubInProcServer.CoBook и PubInProcServer.CoJournal. Для каждого из построенных разделов создать подразделы CLSID, где в качестве значения параметра по умолчанию задаются CLSID соответствующих коклассов.