Материал: Методические указания к практическим занятиям по дисциплине «Основы построения защищенных компьютерных сетей». Деревянко В.Н

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

}

STDMETHODIMP_(ULONG) CoCarClassFactory::Release () { if(--m_refCount == 0)

{

delete this; return 0;

}

return m_refCount;

}

//Фабрики класса не реализуют интерфейсы кокласса, который они создают!

STDMETHODIMP CoCarClassFactory::QueryInterface(REFIID riid, void** ppv)

{

//Какой интерфейс желаете?

if(riid == IID_IUnknown)

{

*ppv = (lUnknown*)this;

}

else if(riid == IID_IClassFactory)

{

*ppv = (IClassFactory*)this;

}

else

{

*ppv = NULL; return E_NOINTERFACE;

}

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

}

Теперь реализуем IClassFactory:: CreateInstance(). В этом методе создадим объект СоСаr и запросим нужный интерфейс. Вернем HRESULT, который клиент сможет проанализировать. Если в методе CreateInstance() что-то не сработает, выделенную под кокласс память надо освободить:

// Создаем СоСаr!

39

STDMETHODIMP CoCarClassFactory:: CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void** ppv)

{

// В этом объекте класса агрегация не поддерживается if(pUnkOuter != NULL)

return CLASS_E_NOAGGREGATION; СоСаr* pCarObj = NULL;

HRESULT hr;

//Создаем автомобиль pCarObj = new CoCar;

//Запрашиваем интерфейс

hr = pCarObj -> QueryInterface(riid, ppv);

// Проблема? Освобождаем занятую память if (FAILED(hr))

delete pCarObj;

return hr;

}

Реализуем IClassFactory: :LockServer()

для работы со счетчиком блокировок. В конструкторе и деструкторе объекта класса добавьте соответствующий код для этого счетчика. Для обращения к глобальным переменным, определенным в CarInProcServer.cpp, используйте ключевое, слово extern в файле СРР вашего объекта класса:

//Завершаем построение фабрики класса extern ULONG g_lockCount;

extern ULONG g_objCount;

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

CoCarClassFactory::CoCarClassFactory()

{

m_refCount = 0; g_objCount++;

}

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

CoCarClassFactory::~CoCarClassFactory() { g_objCount--; }

40

// Блокировки сервера

STDMETHODIMP CoCarClassFactory::LockServer(BOOL fLock)

{

if (fLock)

++g_lockCount;

else

--g_lockCount;

return S_OK;

}

Кроме того, убедитесь, что вы вставили нужные файлы в исходный код фабрики класса (существует обращение к CоСаr в CreateInstance(), поэтому требуется заголовочный файл CоСаr). Далее разработаем минимальный полный набор экспортируемых функций сервера.

3. Реализация хранилища компонентов DLL

Реализуйте в файле CarlnProcServer.cpp метод

DllGetClassObject():

//Этот экспортируемый метод делает фабрики класса видимыми для

//менеджера управления сервисом (Service Control Manager)

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void** ppv) { /*

1.Проверьте, совпадают ли CLSID и СоСаr, если нет — верните код ошибки

2.Создайте объект CoCarClassFactory

3.Запросите параметр REFIID у нового объекта класса

4.Установите HRESULT для клиента

*/

}

Последняя экспортируемая функция DLL — это

DllCanUnloadNow():

// Метод определяет, можно ли выгрузить DLL из памяти

STDAPI DllCanUnloadNow()

{

//Если g_objCount и g_lockCount оба равны нулю, возвращаем S_OK,

//в противном случае — S_FALSE

}

41

Ниже приводится возможный код для каждой из экспортируемых функций:

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

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;

CoCarClassFactory *pCFact = NULL;

//Знаем, как в этом сервере создавать машины if(rclsid != CLSID_CoCar)

return CLASS_E_CLASSNOTAVAILABLE;

//Запрашивается CoCarClassFactory

pCFact = new CoCarClassFactory;

// Получаем интерфейс из CoCarClassFactory hr = pCFact -> QueryInterface(riid, ppv) ; if(FAILED(hr))

delete pCFact; return hr;

}

Создайте и вставьте в проект файл carinprocserver.def, чтобы сделать эти две функции видимыми окружающему миру. Имя в операторе library должно совпадать с именем проекта, который вы компонуете:

LIBRARY "CARINPROCSERVER" EXPORTS

DllGetClassObject @l PRIVATE DllCanUnloadNow @2 PRIVATE

42

4. Внесение информации в реестр

Чтобы завершить наш DLL-сервер, нужно создать еще REG-файл для внесения минимальной и полной информации о сервере в реестр системы. Создайте ProgID для вашего кокласса с подключом CLSID. Введите его прямо под HKCR. Затем введите CLSID для вашего кокласса с подключом InprocServer32, указывающим на физический путь к DLL.

Вот пример файла carinprocserver.reg:

REGEDIT

HKEY_CLASSES_ROOT\CarInProcServer.CoCar\CLSID = {7AD2D539-EE35-lld2-B8DE- 0020781238D4}

HKEY_CLASSES_ROOT\CLSID\{7AD2D539-EE35-lld2-B8DE-0020781238D4} = CarlnProcServer.CoCar

HKEY_CLASSES_ROOT\CLSID\{7AD2D539-EE35-lld2-B8DE-0020781238D4} \InprocServer32 = E:\ATL\Labs\Chapter03\CarInProcServer \Debug\CarInProcServer.dll

После того как сформируете REG-файл, просто щелкните по нему дважды в Проводнике Windows, чтобы записать информацию в реестр. Используйте regedit.exe для проверки правильности занесения информации.

Итак, создан СОМ-сервер на обычном C++ и без всяких библиотек. Позже построим клиент СОМ на C++, обращающийся к этому серверу.

Контрольные вопросы

1.Для чего служит фабрика класса?

2.Какая информация записывается в реестр системы о распределённых COM-программах?

43

Источник: https://studfile.net/preview/16565401/