Маршалинг и демаршалинг, Динамический маршалинг и информация о типе
• Если СОМ-объект реализован в составе внутреннего сервера, то клиентский указатель указывает непосредственно на интерфейс объекта.
• Если СОМ-объект реализован в составе локального сервера, то клиентский указатель указывает на заместителя (proxy) внутри клиентского процесса. Заместитель — это просто другой СОМ-объект, обычно предоставляюший клиенту те же интерфейсы, что и объект локального сервера, с которым Клиент пытается взаимодействовать. Вызов клиентом метода через такой указатель на интерфейс на самом деле вызывает исполнение кода заместителя. Заместитель принимает переданные параметры и упаковывает их для пересылки. Далее запрос передается в процесс, который фактически реализует объект.
Программы в среде Windows имеют дело с виртуальными адресами, которые отображаются на некоторые физические адреса. Это означает, что обратиться из одной программы по адресу другой программы для доступа к данным невозможно, поскольку неизвестно, какому физическому адресу соответствует виртуальный адрес. Поэтому передача данных между программами осуществляется с помощью низкоуровневых функций.
В случае вызова между процессами параметры и возвращаемые значения должны быть преобразованы в стандартный сетевой формат NDR (Network Data Representation), понятный обоим процессам и независящий от языка реализации. Кроме того, и в составе клиента и в составе сервера должны быть средства, осуществляющие упаковку и распаковку кода.
Упаковка параметров вызова в пакет данных стандартного формата для пересылки называется маршалингом с помощью функции API CoMarshalllnterface. A демаршалингом (unmarshaling) — обратная операция распаковки из стандартного формата в форму, приемлемую для принимающего процесса с помощью функции API CoUnMarshalllnterface. Код, знающий, как выполнять эти операции, называется кодом маршалинга, или, для краткости, маршалером (marshaler). Основная задача заместителей и заглушек — выполнение маршалинга и демаршалинга Фактически суррогат или заглушка (stub) является представителем клиента в адресном пространстве сервера, а заместитель (proxy) — представителем сервера в адресном пространстве клиента.
Маршализация бывает стандартная и пользовательская. Стандартная маршализация поддерживается операционной системой Windows. Для реализации пользовательской маршализации необходимо использовать интерфейс Marshal, включающий методы Marshallnterface и Unmarshallnterface.
Создание заместителей и заглушек
Microsoft разработала компилятор МIDL (Microsoft IDL), генерирующий из описания интерфейса код маршалинга, разбитый на заместителя и заглушку.
При создании COM-серверов с помощью экспертов Delphi нужный код генерируется автоматически, и необходимости в использовании IDL нет.
Динамический маршалинг и информация о типе
а) Динамический маршалинг. Хотя заглушки и заместители реализуются в виде Dll и поэтому загружаются по мере необходимости, предполагается, что клиент уже на этапе написания кода и компиляции знает, какие интерфейсы он будет использовать. Однако бывают ситуации, когда появляются новые интерфейсы, и для них заместители не были предусмотрены.
Для решения проблемы доступа к объектам, интерфейсы которых не известны на этапе проектирования, клиент должен уметь выполнять позднее (динамическое) связывание (late binding). Идея заключается в том, чтобы позволить клиенту конструировать вызовы вновь обнаруженных интерфейсов. Способность выполнять динамическое связывание основана на умении выполнять динамический маршалинг. Это в свою очередь подразумевает, что клиент каким-то образом должен динамически (в процессе работы) получать сведения об интерфейсах, поддерживаемых данным объектом.
б) Информация о типе. Для поддержки механизма позднего связывания в СОМ предусмотрены библиотеки типов. При создании СОМ-сервера может быть создана библиотека типов (а может быть и не создана, тогда доступ к СОМ-серверам осуществляется через интерфейс IDispatch).
Библиотека типов представляет собой список фабрик класса, поддерживаемых СОМ-сервером, и является независимым от языка реализации средством исчерпывающего документирования СОМ-объекта. Для каждой фабрики класса можно получить список интерфейсов.
Из библиотеки типов можно узнать интерфейсы, реализуемые объектом, имена объектов, имена, типы и параметры его методов и свойств.
Поддержка динамического маршалинга с помощью библиотеки типов обеспечивается универсальным маршалером, реализованным в модуле Оlе-Aut32.Dll.
в) Создание библиотеки типов в Delphi. В Delphi в качестве основного варианта создания библиотеки типов используется язык Object Pascal. Однако параллельно создается текст на языке IDL.
Для создания и редактирования библиотек типов (type library) в Delphi предусмотрен редактор, совмещенный с редактором интерфейсов.
Для создания библиотеки типов в Delphi необходимо:
File\New
• В открывшемся многостраничном окне (репозитории) New Items следует выбрать страницу ActiveX и активизировать пиктограмму Type Library.
Редактор библиотеки типов представляет собой экранную форму, вклкючающую панель инструментов для создания интерфейсов, со-классов, модулей и других характеристик. Редактор позволяет регистрировать библиотеку в реестре Windows, а также экспортировать код библиотеки в формат языка Microsoft IDL или CORBA IDL.
• Далее следует объявить необходимые интерфейсы и другие характеристики. После сохранения будет создан файл <имя сервера> TLB.Pas.
View\Type Library
г) Доступ к библиотеке типов. ХОТЯ библиотеки типов представляют собой обычные двоичные файлы с описанием интерфейсов СОМ-объектов и их методов, доступ к ним обычно осуществляется с помощью стандартного программного обеспечения, позволяющего рассматривать библиотеки и их содержимое как СОМ-объекты, работа с которыми ведется через стандартные интерфейсы. Доступ к библиотеке как к единому целому возможен несколькими способами:
• Используя интерфейс ITypeLib, включающий методы:
— GetTypeinfoOfGuid — возвращает указатель па интерфейс ITypelnfo для объекта из библиотеки типов, которому соответствует заданный GUID
FindName — возвращает указатель на интерфейсы ITypelnfo одного или нескольких объектов библиотеки типов, содержащих заданное символьное имя
IsName определяет нахождение объекта с указанным именем в библиотеке
GetTypelnfoCount возвращает количество объектов в библиотеке доступных непосредственно
• Для доступа к библиотеке типов по GUID используется функция API: LoadRegTypeLib(LIBID, MajorVersion, MinorVersion, LSID, pTypeLib);
• LIBID — GUID библиотеки типов
• MajorVersion — главный номер библиотеки типов (обычно это I).
• MinorVersion — малый номер библиотеки типов (обычно это 0).
• LSID — код национального языка библиотеки типов (обычно это 0)
• pTypeLib — требуемый указатель на интерфейс ITypeLib.
• Если клиенту известно имя файла библиотеки типов, то можно воспользоваться методом TComServer.LoadTypeLib
д) Для доступа к информации о типах в Delphi включен класс поддержки библиотеки типов TTypedComObject, в котором предусмотрен единственный новый метод, возвращающий указатель на CoClass конкретного класса:
TTypedComObject.GetClasslnfo(Out Typelnfo: ITypelnfo), HResult;
На сегодняшний день сведения из библиотеки типов чаше всего требуется клиентам объектов, поддерживающих интерфейс IDispatch. Используя лот интерфейс, клиент может получить доступ к методам диспинтерфейсов (Dispinterface).