Файл: Технология COM (АНАЛИЗ ТЕХНОЛОГИИ COM).pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 23.04.2023

Просмотров: 249

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Файл IDL содержит в себе три основных элемента:

  • Интерфейс. Клиенты применяют его для взаимодействия с сервером.
  • CoClass. Класс, реализующий данный интерфейс.
  • Библиотека типов. Это откомпилированный файл IDL, который используется для получения информации об интерфейсе.
    1. Определение пользовательского интерфейса. В рассматриваемом при­мере [6] файл MySrv.idl содержит определение интерфейса с помощью языка IDL. Опе­ратор import применяется для взятия определений интерфейсов из файла oaidl.idl. Он подобен директиве #include языка C+—+. В квадратных скобках перечисляются атрибуты, которые относятся к описанию интерфейса, идущего ниже. Атрибут object сообщает компилятору IDL, что эта информация является определением скорее интер­фейса COM, чем интерфейса RPC. Идентификатор GUID, определенный с помощью атрибута uuid, - уникальный идентификатор интерфейса. Директива importlib напо­минает директиву import, но импортирует бинарные (откомпилированные) библиотеки типов. Всем библиотекам типов требуется директивой importlib импортировать библио­теку базовых типов, определенную в файле Stdole32.tlb.

С помощью программы guidgen.exe необходимо создать три идентификатора и за­менить ими имеющиеся в файле MySrv.idl [6]. Копировать готовые идентификаторы необходимо в формате реестра (Registry Format).

Файл idl компилируется с помощью программы midl.exe. При компиляции генери­руются следующие файлы:

  • прокси-файл интерфейса (interface proxy file) mysrv_p.c, в котором содержится программный код передачи интерфейса IMyInterface между процессами, опреде­ленный в файле IDL из примера [6];
  • файл заголовка mysrv.h, содержащий интерфейс и определения типов C++. Он также объявляет символьные константы для идентификаторов интер­фейса ID и класса компонентов CLSID. Из примера это IID_IMyInterface и CLSID_MyComponent;
  • файл mysrv_i.c, содержащий определения GUID для идентификаторов IID, CLSID и LIBID, объявленных в файле заголовка;
  • бинарная версия файла IDL.
    1. Реализация интерфейсов. Файл MyComponent.h из примера [6] содер­жит реализацию интерфейса IUnknown и пользовательского. Заголовочный файл windows.h включен для использования некоторых функций WinAPI. Также включен файл mysrv.h, сгенерированный компилятором IDL. Этот файл содержит определение интерфейса. Класс CMyComponent наследуется от интерфейса и реализует его.

Поле refCount служит для подсчета ссылок на объект класса CMyComponent и ини­циализируется в конструкторе значением 0. Макросы STDMETHOD и STDMETHOD_ применяются для объявления функций с описанием соглашения о вызовах функций и типом возвращаемого значения. Макрос STDMETHOD описывает возвращаемое значение как HRESULT. Макрос STDMETHOD_ определяет возвращаемое значение в первом параметре. Для функций AddRef и Release он применяется, так как эти функ­ции возвращают значение счетчика ссылок, а не HRESULT. В зависимости от плат­формы макросы могут быть определены по-разному, поэтому описание функций без использования макросов было бы некорректным.


С помощью метода QueryInterface клиент запрашивает конкретный интерфейс. Ме­тод проверяет наличие такого интерфейса в компоненте и, если он найден, присваивает в указатель, переданный в метод. Сравнивается передаваемый параметр riid с иденти­фикатором интерфейсов IUnknown и MyInterface. Также метод QueryInterface вызы­вает функцию AddRef для увеличения количества ссылок на объект. Функции AddRef и Release используют функции WinAPI InterlockedIncrement и InterlockedDecrement для получения монопольного доступа к переменной refCount при обеспечении без­опасности многопоточности (thread-friendly). Если бы применялся простой инкремент refCount+—+, то конкурирующие потоки могли бы создать проблемы при использовании функций AddRef и Release [2].

Метод HelloWorld является единственным в пользовательском интерфейсе, который вызывает диалоговое окно с надписью «Hello World!».

3.5. Фабрика классов для интерфейса. Создание объекта COM и получение указателя интерфейса происходят через фабрику класса данного компонента. При этом происходят следующие действия:

  • ищется бинарный файл, содержащий сервер COM;
  • файл загружается в память;
  • создается экземпляр компонента и передается указатель интерфейса IUnknown, реализованный в этом компоненте.

Обычно для создания экземпляра сервера COM клиент вызывает WinAPI функцию CoCreateInstance, которая имеет такую сигнатуру:

WINOLEAPI CoCreatelnstance(REFCLSID rclsid

, LPUNKNOWN pUnkOuter , DWORD dwClsContext , REFIID riid , LPVOID* ppv);

Параметр rclsid - это идентификатор CLSID требуемого компонента. Параметр riid - идентификатор требуемого интерфейса. В параметр ppv присваивается указа­тель интерфейса.

Функция CoCreateInstance непосредственно не создает экземпляр компонента, а пе­редает указатель на реализацию интерфейса IClassFactory, которая отвечает за пост­роение объектов классов компонента. При реализации интерфейса IClassFactory опре­деляются функции:

  • HRESULT CreateInstance(IUnknown* unkOuter, REFIID riid, void** ppvObject);
  • HRESULT LockServer(BOOL lock).

Метод Createlnstance создает экземпляр объекта и возвращает указатель на тре­буемый интерфейс. Метод LockServer сохраняет сервер в памяти для последующего быстрого выполнения.

В методе CreateInstance создается экземпляр объекта с помощью оператора new. В самой реализации компонента он удаляется в методе Release при достижении счет­чиком значения 0. Также вызывается метод QueryInterface и запрашивается требуе­мый интерфейс. Если объект не поддерживает требуемый интерфейс, то вызов завер­шается ошибкой, и клиент получает значение типа HRESULT с кодом ошибки. Метод LockServer увеличивает или уменьшает переменную locks, которая отвечает за удер­жание объекта в памяти.


3.6. Создание файла DLL. Для окончательного создания сервера COM нужно добавить несколько дополнительных функций API:

  • DllMain - точка входа DLL, которая вызывается системой, когда поток или про­цесс начинает использование DLL. Это позволяет выполнить любую инициали­зацию и последующую очистку. Данная функция соответствует функции main исполняемых файлов с расширением exe.
  • DllGetClassObject - вызывается с помощью функции CoGetClassObject для воз­врата указателя на интерфейс IClassFactory.
  • DllCanUnloadNow - функция возвращает константу S_OK, если количество фик­саций сервера равно 0, в противном случае возвращает S_FALSE.
  • DllRegisterServer - используется для регистрации сервера COM в операционной системе. В системах Win32 это означает добавление соответствующих записей в системный реестр Windows.
  • DllUnregisterSever - применяется для отмены регистрации сервера COM. В систе­мах Win32 это достигается удалением соответствующих записей из системного реестра Windows.

В файле MySrvDll.cpp из примера [6] экземпляр класса CMyClassFactory определен с помощью синглтона Мейерса [3, 4]. Это единственный экземпляр данного класса, используемый для создания объектов компонента COM.

Функции OpenKey, CreateKey, SetValue и DeleteKey применяются для управ­ления регистрацией и отменой регистрации построенного нами сервера COM. Функция DllGetClassObject проверяет запрашиваемый идентификатор CLSID. Ес­ли он равен CLSID_MyComponent, то она использует глобальный экземпляр CMyClassFactory для запроса требуемого интерфейса (riid) и возврата результата. Функции DllRegisterServer и DllUnregisterServer управляют добавлением или удалением требуемых ключей и их значений в системном реестре. Фукция DllRegisterServer соз­дает ключ системного реестра в разделе HKEYS_CLASSES_ROOT_CLSID. Название этого ключа является идентификатором CLSID компонента, заключенным в скобки. Для него установлено значение имени нашего компонента MyComponent. Внутри но­вого ключа создан подчиненный ему ключ InprocSever32. В нем установлено значение пути к файлу DLL. Ключ ThreadingModel установлен в значение Apartment. Для экс­порта вышеуказанных функций создан текстовый файл MySrvDll.def. В нем определе­ны экспортируемые функции DLL:

LIBRARY "MyComponent"

EXPORTS

DllCanUnloadNow PRIVATE

DllGetClassObject PRIVATE

DllRegisterServer PRIVATE DllUnregisterServer PRIVATE

Функции API, предназначенные для использования в системе COM, экспортируются как PRIVATE.

После сборки проекта необходимо зарегистрировать сервер COM, вызвав команду regsvr32 и передав в качестве параметра имя DLL. Программа Regsvr32.exe загрузит модуль DLL и вызовет функцию DllRegisterServer для создания требуемых записей в системном реестре [1].


3.7. Создание клиентского приложения. Клиентское приложение можно соз­дать как Win32 консольный проект, где в функции main будет происходить обращение к серверу COM:

#include "stdafx.h"

#include <iostream>

#include <windows.h>

#include "..\MyComponent\mysrv.h"

#include

"..\MyComponent\mysrv_i.c"

int _tmain(int argc, _TCHAR* argv[])

{

CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

IMyInterface* my = NULL;

HRESULT hr = CoCreateInstance(CLSID_MyComponent , NULL

, CLSCTX_INPROC_SERVER , IID_IMyInterface , reinterpret_cast<void**>(&my));

if (FAILED(hr))

std::cout << "Com failed"; else {

my->HelloWorld();

my->Release();

}

CoUninitialize(); return 0;

}

Для доступа к интерфейсу IMyInterface нужен файл mysrv.h, сгенерированный ком­пилятором MIDL; для доступа к идентификаторам CLSID и IID - файл mysrv_i.c, также сгенерированный компилятором MIDL. COM инициализируется вызовом функ­ций Coinitialize. Указатель на интерфейс инициализируем с помощью функции CoCreatelnstance. Функцией CoUninitialize COM деинициализируется.

2 АНАЛИЗ ТЕХНОЛОГИИ COM

2.1 Сравнение технологии COM

Сравнение COM с другими похожими технологиями. В первую оче­редь технология COM интересна с точки зрения распределенных вычислений, когда каждая из компонент COM находится на отдельном сервере и они взаимодействуют друг с другом через сеть.

Наиболее известным конкурентом технологии COM является архитектура брокеров объектных запросов Common Object Request Broker Architecture (CORBA), которую развивает Консорциум OMG [8].

Функции CORBA и COM - это функции промежуточного программного обеспече­ния объектной среды. Для того чтобы обеспечить взаимодействие объектов и их инте­грацию в цельную систему, архитектура промежуточного уровня должна реализовать несколько базовых принципов:

  • независимость от физического размещения объекта: компоненты программного обеспечения не обязаны находиться в одном исполняемом файле, выполняться в рамках одного процесса или размещаться на одной аппаратной системе;
  • независимость от платформы: компоненты могут выполняться на различных ап­паратных и операционных платформах, взаимодействуя друг с другом в рамках единой системы;
  • независимость от языка программирования: различия в языках, которые исполь­зуются при создании компонентов, не препятствуют их взаимодействию друг с другом.

CORBA и COM отличаются, однако сходны в том, каким образом в них достигается реализация базовых принципов. Это клиент-серверные технологии, в которых функ­циональность объекта предоставляется клиенту посредством обращения к абстракт­ным интерфейсам. Интерфейс определяет набор методов, которые реализуют функ­ции, присущие данному классу объектов. Интерфейс дает клиенту возможность толь­ко вызывать тот или иной метод, скрывая от него все детали его реализации. В обеих технологиях взаимодействие между клиентским процессом и сервером объекта, т. е. процессом, который порождает и обслуживает экземпляры объекта, использует меха­низм объектного варианта вызова удаленной процедуры (remote procedure call - RPC). Он реализует схему передачи сообщений, в соответствии с которой в распределенном клиент-серверном приложении процедура-клиент передает специальное сообщение с па­раметрами вызова по сети в удаленную серверную процедуру, а результаты ее выпол­нения возвращаются в другом сообщении клиентскому процессу.


Для того чтобы реализовать эту схему, на стороне клиента и на стороне сервера поддерживаются специальные компоненты, носящие название клиентский и серверный суррогаты (client stub и server stub). Для того чтобы вызвать ту или иную функ­цию, клиент обращается к клиентскому суррогату, который упаковывает аргументы в сообщение-запрос и передает их на транспортный уровень соединения. Серверный суррогат распаковывает полученное сообщение и в соответствии с переданными аргу­ментами вызывает нужную функцию или нужный метод объекта, если речь идет об объектном варианте RPC. В СОМ клиентский суррогат называется proxy, а сервер­ный - stub. В CORBA клиентский суррогат не имеет специального названия, а сервер­ный обозначают термином skeleton [8].

Параметры вызова могут формироваться в отличной от серверной языковой и опе­рационной среде, поэтому на клиентский и серверный суррогаты возлагаются функции преобразования аргументов и результатов в универсальное, не зависящее от конкрет­ной архитектуры представление. Тем самым достигается возможность взаимодействия клиента и сервера на различных платформах. Одной из последних технологий для рас­пределенных вычислений является Windows Communication Foundation (WCF) от ком­пании Microsoft. Тотальное принятие стандартных способов реализации распределен­ных вычислений поменяло мир разработки приложений. К примеру, функции, пред­ставляемые в настоящее время, включают в себя безопасность, координацию распреде­ленных транзакций и надежные соединения. Полезные изменения в программировании сервисов должны быть отражены в инструментах, используемых разработчиками. WCF призван предоставить управляемый подход к распределенным вычислениям, широкой функциональной совместимости и прямую поддержку сервисов.

WCF упрощает разработку связанных приложений с помощью новой, ориентирован­ной на сервисы, модели. Он поддерживает множество стилей для разработки распре­деленных приложений, создавая слоистую архитектуру. В основе архитектура каналов WCF дает асинхронную, нетипизированную передачу сообщений. Над этим надстраи­вается архитектура для защищенного, надежного, транзакционного обмена данными, дающего большие возможности передачи и кодировки данных. WCF включает в се­бя возможности сериализации, которая позволяет избежать стыковки и версионирова- ния, и предоставляет интеграцию и функциональную совместимость с существующими распределенными системами .NET, такими как очередь сообщений (MSMQ), COM+, ASP.NET, сетевые сервисы, улучшенные сетевые сервисы (WSE).