На этом шаге мы рассмотрим библиотеки типов и информацию о методах сервера,
а также язык IDL.
На этом шаге будет рассказано о решении проблемы, состоящей в том, каким образом COM-сервер может информировать среду разработки об интерфейсах, их GUID, списке поддерживаемых методов и параметрах этих методов. В самом деле, COM-клиент всегда создается после того, как был создан COM-сервер. Было бы разумно получить от COM-сервера список его методов и список формальных параметров этих методов. Это позволило бы осуществить синтаксический контроль на этапе разработки клиента. Кроме того, названия методов и формальных параметров несут в себе смысловую нагрузку: разработчик легче их воспринимает, и часто назначение методов и параметров очевидно. Также список методов и параметров, определенных пользователем интерфейсов необходим для доступа к виртуальной таблице методов интерфейса - реализации так называемого раннего связывания (Early Binding).
Данная проблема решается при помощи библиотеки типов. При создании COM-сервера может быть реализована библиотека типов (а может быть, и не реализована - в этом случае доступ к методам COM-сервера осуществляется через интерфейс IDispatch). Библиотека типов представляет собой список фабрик класса, поддерживаемых данным COM-сервером. Для каждой фабрики класса можно получить список интерфейсов. Для каждого интерфейса приводится список поддерживаемых методов, для каждого из которых можно затребовать список формальных параметров. Порядок следования методов в списке соответствует их порядку в виртуальной таблице методов, поэтому на этапе компиляции клиента можно связать вызов метода сервера с соответствующим столбцом виртуальной таблицы.
Все эти списки сохраняются либо непосредственно в файлах COM-сервера (*.exe; *.dll; *.ocx), либо в отдельных файлах (*.tlb; *.olb). Для последних файлов предусмотрены специальные двоичные форматы списков. Соответственно языки программирования, поддерживающие импорт библиотек типов, должны знать форматы этих файлов, уметь читать данные из них и представлять эти данные разработчику в естественном, специфическом для данного языка программирования виде. Например, если библиотека типов импортирована в средство разработки, использующее компилятор C++, то ее реализация должна быть представлена с использованием синтаксиса C++; если импортирована в Delphi - то с использованием синтаксиса Pascal. При этом разработчик должен отдавать себе отчет, что реально библиотека типов хранится совсем в других форматах.
Если же описание библиотеки типов хранится непосредственно в COM-сервере, то на сервере можно реализовать интерфейс ITypeInfo. Пользуясь методами этого интерфейса, среда разработки может опросить сервер о тех же самых параметрах, что считываются из вышеперечисленных файлов. Пользоваться интерфейсом ITypeInfo гораздо проще, чем писать конверторы форматов, и опытный разработчик может легко узнать о содержимом библиотеки типов сервера в клиентском приложении. Соответственно сама библиотека типов в этом случае может храниться в сервере в произвольном формате.
Для создания и редактирования библиотек типов в Delphi имеется редактор, совмещенный с редактором интерфейсов (определение фабрик класса, интерфейсов и их методов).
Многие средства разработки, используемые для создания COM-серверов, содержат в комплекте поставки утилиты для автоматической генерации библиотек типов или клиентского и серверного кода на основании описаний интерфейсов сервера. Во многих случаях эти описания создаются на языке IDL (Interface Definition Language).
Зачем нужен IDL?
IDL используется для спецификации интерфейсов. Фактически это стандарт, позволяющий описывать вызываемые методы сервера и их параметры, не вдаваясь в детали и правила реализации серверов и клиентов на том или ином языке программирования. Используя IDL, можно описать интерфейсы сервера, а затем создать его реализацию на любом языке программирования с помощью широкого спектра средств разработки, равно как и реализацию клиента. В определенном смысле IDL - это стандарт для описания взаимодействия между компонентами распределенной системы, не зависящий от деталей реализации и языков программирования (а в общем случае и платформ, так как IDL используется не только в COM).
IDL COM заимствован из IDL DCE (Distributed Computing Environment) - спецификации межплатформенного взаимодействия сервисов, разработанной консорциумом Open Systems Foundation. Отметим, что в настоящее время существует несколько диалектов IDL (для COM, для CORBA, для DCE и др.). Тем не менее, различия между ними невелики.
Язык IDL немного похож на ту часть C++, которая содержит описания классов (то, что обычно помещается в h-файлы). В качестве примера приведем описание на IDL интерфейсов гипотетического COM-сервера, содержащего объект MyComObj, интерфейс которого IMyComObj (наследник IUnknown) экспонирует два метода: MyMethod1, получающий в качестве входных параметров два целых числа и возвращающий действительное число, и MyMethod2, не возвращающий данных и получающий в качестве входного параметра переменную типа Variant:
[ uuid(845256D0-8E96-11D2-B126-000000000000), version(1.0), helpstring("Project1 Library") ] library Project1 { importlib("STDOLE2.TLB"); importlib("STDVCL40.DLL"); [ uuid(845256D1-8E96-11D2-B126-000000000000), version(1.0), helpstring("Interface for myComObj Object") ] interface ImyComObj: IUnknown { [id(0x00000001)] double stdcall MyMethod1([in] long Param1, [in] long Param2); [id(0x00000002)] void_ stdcall MyMehod2([in] VARIANT Param3); }; [ uuid(845256D3-8E96-11D2-B126-000000000000), version(1.0), helpstring("myComObj Object") ] coclass myComObj { [default] interface ImyComObj; }; }
Многие средства разработки, поддерживающие создание COM-серверов, имеют в своем составе утилиты для генерации серверного и клиентского кода на основании описаний на IDL. В частности, в состав Microsoft Visual C++ включен компилятор MIDL, генерирующий код для клиентских и серверных DLL, ответственных за взаимодействие клиента и сервера, на основании созданных разработчиками описаний на IDL.
Однако, что при создании COM-серверов с помощью экспертов Delphi библиотеки типов и соответствующий код (или его "заготовки") генерируются автоматически и создавать вручную описания с помощью IDL необходимости нет. При этом всегда можно сгенерировать описание на IDL на основании библиотеки типов сервера, созданной с помощью соответствующего редактора.
Со следующего шага мы начнем рассматривать интерфейс IDispatch.