3590
.pdfЕсли требуется только один экземпляр кокласса, то можно использовать метод СоCreateInstance(). Метод СоCreateInstance() находит объект класса и автоматически вызывает CreateInstance() из указателя IСlassFactory. От программиста требуется передать нужные CLSID и IID. При использовании СоCreateInstance() объект каждый раз создаётся и каждый раз удаляется.
1.2.6. Язык определения интерфейса MIDL
MIDL – (Microsoft Interface Definition Language) яв-
ляется расширением существующего IDL для поддержки СОМ.
Описание СОМ-сервера помещается в файл *.idl и обрабатывается компилятором midl.exe. Использование MIDL обеспечивает языковую независимость и прозрачность местонахождения сервера. Файл *.idl создаётся в среде Visual C++ и автоматически компилируется при сборке проекта.
Основные типы данных IDL (см. таблицу) похожи на их аналоги в языке С. Это язык определений. В нём отсутствуют циклы и условные операторы.
31
|
Таблица |
|
Ключевые слова MIDL |
Ключевое |
Описание |
слово |
|
typedef |
Аналогично слову typedef языка С. |
|
|
import |
Вносит существующие IDL-определения в |
|
IDL-файл. Аналогично директиве #include |
|
языка С. Пример: |
|
import “ouidl.idl” // включает ин- |
|
терфейсы автоматизации. |
object |
Определяет, что далее следуют определения, |
|
относящиеся к СОМ. |
interface |
Объявление нового СОМ-интерфейса. |
cpp-quote |
Вставка строки в программу на С\С++, гене- |
|
рируемую компилятором MIDL (это строка - |
|
комментарий). |
uuid |
Универсальный уникальный идентификатор |
|
(то же, что и GUID). |
helpstring |
Вставка строки комментария. |
|
|
enum, |
Создание перечисления, vl_enum означает 32- |
vl_enum |
битные перечисления |
library |
Оператор библиотеки типов с обязательным |
|
атрибутом uuid определяет, какие коклассы |
|
содержатся в сервере (ЕХЕ или DLL - библио- |
|
теке). |
importlib |
Импорт в откомпилированную библиотеку. |
|
Должна, как минимум, импортироваться |
|
стандартная библиотека типов stdole32.tlb. |
32
|
Продолжение таблицы |
Ключевое |
Описание |
слово |
|
[in] |
Атрибут параметра метода, передаваемого от |
|
клиента к серверу (параметр, задаваемый по |
|
умолчанию). |
[out] |
Атрибут параметра метода, передаваемого от |
|
сервера к клиенту. |
|
Клиент освобождает память полученных дан- |
|
ных. Параметр [out] – это всегда указатель. |
[in, out] |
Посылка от клиента к серверу. Клиент отво- |
|
дит и освобождает память, но сервер тоже |
|
может управлять памятью при вызове метода. |
coclass |
Объявление кокласса в библиотеке, uuid – |
|
обязателен. |
default |
Определение интерфейса по умолчанию. Ка- |
|
ждый кокласс должен иметь ровно один ин- |
|
терфейс по умолчанию. Используется для ра- |
|
боты с С\С++. |
Пример определения интерфейсов сервера CarServer средствами IDL.
import “oaidl.idl” |
|
... |
|
// ICreateCar |
// IID |
[object, uuid (...), |
|
helpstring (“Create a car”)] |
|
interface ICreateCar: IUnknown |
|
{ |
|
33
HRESULT SetPetName ([in] BSTR petName);
HRESULT SetMaxSpeed ([in] int maxSp);
};
[uuid (...), //LIBID helpstring (“CoCar Server with TypeLib”)] library CarServer
{
importlib(“stdole32.tlb”); //должна
быть //первой строкой в |
библиотеке |
[uuid (...)] |
//CLSID |
coclass CoCar |
|
{ |
|
[default] interface ICreateCar; interface IStats;
interface IEngine;
};
};
Файлы, генерируемые компилятором MIDL
Имена большинства генерируемых MIDL-файлов основаны на первоначальном имени IDL-файла. Для файла CarServer.idl, например, строятся следующие файлы.
CarServer.h – содержит определение интерфейса с использованием интерфейсных макросов СОМ.
CarServer_i.c – содержит все определения GUID. Для каждого атрибута [uuid] формируется соответствующая константа с префиксом IID_ , CLSID_ или
LIBID_.
CarServer.tlb – двоичный эквивалент текста IDL, который называется библиотекой типов. Важно, что программы и на других языках, кроме С\С++, могут ис-
34
пользовать содержащиеся в них коклассы, интерфейсы и пользовательские типы.
CarServer_p.c и dlldata.c – используются для формирования dll, содержащего заглушки/прокси для удалённого доступа к СОМ-интерфейсам.
Для того чтобы другие языки могли получить информацию о типе сервера, надо ввести информацию о файле *.tlb в системный реестр под ключом
HKEY_CLASSES_ROOT/TypeLib.
1.3.Технология DCOM
1.3.1.Организация обмена между клиентом
исервером (маршалинг)
В модели СОМ одна и та же программа пользователя используется для доступа к СОМ-объекту независимо от его физического расположения. СОМ создает иллюзию, что все вызовы методов интерфейсов происходят внутри процесса. Для этого во время выполнения используется DLL, содержащая объекты «заглушка» и «прокси».
Процедура обмена между клиентом и локальным или удаленным сервером посредством использования заглушек и прокси называется маршалингом. Коды заглушек и прокси генерируются для всех определенных на IDL интерфейсов. Маршалинг осуществляется с помощью механизма удаленного вызова процедур (RPC).
Заглушка-объект – это СОМ-объект, загруженный в процесс сервера, который получает запросы клиента и передает реальному объекту.
Прокси-объект – это СОМ-объект, загруженный в процесс клиента, который отправляет запросы клиента к методам интерфейсов. Это СОМ-объект, поддерживающий
35
стандартные СОМ-интерфейсы. Прокси располагаются внутри процесса клиента и предоставляют клиенту локальные или удаленные интерфейсы.
Следующий посредник на пути между клиентом и сервером – объект канала ORPC (Object RPC). Объект канала поддерживает интерфейс IRpcChannelBuffer. Этот интерфейс разбивает на пакеты запросы клиента и посылает их заглушке, используя вызовы RPC низкого уровня.
Прокси поддерживает интерфейс IRpcProxyBuffer. Этот интерфейс используется для установления или разрыва связи между прокси-объектом и объектом канала.
IRpcProxyBuffer содержит два метода: Connect() и Disconnect(). Метод Connect() в качестве пара-
метра принимает указатель интерфейса IRpcChannelBuffer.
Связь между клиентом, прокси и объектом канала иллюстрирует рис. 1.7.
36
Пространство процесса клиента |
|
IRpcProxyBuffer |
|
Клиент, |
IDraw |
имеющий |
|
pDraw |
IDraw |
|
|
|
IRpcChannelBuffer |
|
Канал к CoHex- |
|
agon Draw |
|
IUnknown |
|
Передача запроса заглушке ин- |
|
терфейса IDraw кокласса CoHex- |
|
agon c помощью ORPC |
Рис. 1.7. Связь между клиентом, прокси |
|
|
и объектом канала |
Прокси-объекты поддерживают IRpcProxyBuffer, позволяющий им связываться с объектом канала. На серверной стороне объект-заглушка реализует стандартный СОМ-интерфейс IRpcStubBuffer, который аналогично интерфейсу IRpcProxyBuffer тоже поддерживает методы Connect() и Disconnect(). Запрос, полу-
ченный от объекта канала ORPC, направляется заглушкой серверу (см. рис. 1.8) .
Схема вызова метода удаленного интерфейса показана на рис. 1.9.
37
Менеджер |
Пространство процесса сервера |
|
IUnknown |
||
IUnknown |
||
IDra |
||
|
||
IDrawStub |
|
|
IRpcStubBuffer |
|
|
IUnknown |
CoHexagon |
|
IShapeEditStub |
|
|
IRpcStubBuffer |
IShapeEdit |
|
|
||
|
Реализация CoHexagon::Draw() |
|
Рис. 1.8. Заглушки реализуют IrpcStubBuffer для распаковки запроса и передают |
||
его реальному СОМ-объекту |
38
Клиент |
|
|
|
IUnknow |
|
|
|
|
|
||
pDraw |
IRpcProxyBuffer |
|
IDrawStub |
||
|
|
|
|
||
IDraw |
IDrawProxy |
IRpcStubBuffe |
|||
|
|
|
IUnknow |
||
|
|
|
|
||
IRpcChannelBuffe |
Канал к IDraw |
CoHexago |
|||
кокласса CoHex |
n |
||||
|
|
||||
|
|
|
|
IDraw |
Рис. 1.9. Схема вызова метода удалённого интерфейса
39
Объекты прокси и заглушки – это обычные объекты СОМ, которые создаются одной фабрикой класса с интерфейсом IPSFactoryBuffer. Как только клиент запрашивает доступ к удаленному интерфейсу, соответствующие менедже-
ры вызывают метод CreateProxy() или CreateStub() ин-
терфейса IPSFactoryBuffer. Далее прокси и заглушка загружаются в процессы клиента и сервера.
В процессе установки пограммы-сервера, то есть всем коклассам, присутствующим в исполняемом файле, присваивается идентификатор приложения AppID (GUID).
Все зарегистрированные в системном реестре СОМприложения перечисляются под ключом HKCR/AppID. Там же могут содержаться именованные значения, касающиеся параметров защиты конкретного приложения, например, список пользователей, которым разрешен доступ к серверу, уровень аутентификации и т.п.
Чтобы избежать недостатков внутрипроцессного СОМобъекта, то есть запустить внутрипроцессный СОМ-сервер в режиме локального сервера, применяется утилита dllhost.exe, строящая суррогатный процесс. В этом случае DLL на основе СОМ загружается с характеристиками отдельного процесса. Чтобы внутрипроцессный сервер загрузился в оболочку dllhost.exe, а не в процесс клиента, требуется внести необходимые записи в реестр системы.
Кроме того, надо перекомпилировать клиент с флагом
CLSCTX_LOCAL_SERVER в методе CoGetClassObject().
1.3.2. Виды маршалинга в модели СОМ
Имеется три основных способа обмена информацией между процессами.
1. Пользовательский маршалинг. Реализуется стандартный интерфейс IMarshal, не используется ORPC, программист самостоятельно разрабатывает программы обмена. Это сложный способ обмена.
40