Каждый элемент в документе XML состоит из следующих частей:
· Открывающий и закрывающий тэги.
· Переменные.
· Содержимое.
· Вложенные элементы.
Открывающий и закрывающий тэги.
Открывающий тэг содержит название элемента и переменные и является обязательным: <hmm type = "discrete">. Закрывающий тэг не является обязательным и используется только если у элемента есть содержимое и/или вложенные элементы:
<hmmtype="discrete">
<number_of_outputs>4</number_of_outputs>
3
</hmm>.
Переменные в XML-документе могут находиться только в открывающих тэгах элементов: <hmm type = "discrete">. Значения переменной должно располагаться в кавычках, одинарных или двойных. Между названием переменной, знаком «равно» и значением переменной может находиться любое количество пробелов. Название переменной не может содержать пробелов, друг от друга переменные отделяются пробелами. В рамках одного элемента названия переменных должны быть уникальны.
Содержимое элемента представляет собой одну или несколько текстовых строк, расположенных между отрывающим и закрывающим тэгами: <hmm>Содержимое</hmm>. В случае, если содержимое представляет собой набор строк, разделенных символами новой строки, XML-процессор интерпретирует их как набор элементов содержимого. Например, XML-процессор “XML++” в таком случае вернет массив элементов типа XMLConents. Данная особенность представления позволяет, например, интерпретировать содержимое как флаги.
Вложенные элементы любого XML-элемента располагаются между отрывающим и закрывающим тэгами элемента. Уровень вложенности является произвольным и определяется создателем документа, вложенные элементы подчиняются являются обыкновенными XML-элементами и ни чем не отличаются от элемента в который они вложены. Названия вложенных элементов уникальными не являются и могут повторяться сколько угодно раз на любых уровнях иерархии.
Из сказанного выше видно, что XML является мощным хорошо стандартизированным инструментом, несомненно заслуживающим внимания в случае возникновения задачи обобщенного описания данных. Наличие множества реализаций XML-процессоров на разнообразных языках программирования, в том числе и бесплатных, под лицензией GPL, избавляет от необходимости написания собственного процессора не зависимо от целей и бюджета проекта. Также следует обратить внимание на возможность использования XML в качестве основы для создания новых языков, подразумевающих описание данные.
Технология Майкрософт COM (Component Object Model - объектная модель компонентов) – это технологический стандарт от компании Майкрософт, предназначенный для создания программного обеспечения на основе распределенных взаимодействующих компонентов, каждый из которых может одновременно использоваться в нескольких программах[5]. Говоря о COM под «распределенными компонентами» нужно понимать, компоненты расположенные на одной машине, но не в одном выполняемом файле. Фактически COM-сервер является выполняемым файлом или dll (dynamic link library – динамически подгружаемая библиотека), которые соединяются с клиентом в процессе выполнения последнего по средствам специального заранее определенного интерфейса. Преимущество такого метода объединения компонент программы заключается в том, что в процессе компиляции и линковки клиентское приложение должно знать только программный интерфейс COM-сервера. Для соединения с сервером в процессе выполнения необходимо знать еще два числа - его идентификатор класса и идентификатор интерфейса, но они могут храниться в файле или системном реестре и подгружаться уже в процессе выполнения клиента. Идентификатор класса и идентификатор интерфейса являются уникальными числами, которые однозначно указывают на данный COM-сервер, зарегистрированный в системе. Эти числа являются гарантированно уникальными не только в рамках отдельно взятой машины, но и на любой другой машине т.к. они генерируются на основе MAC-адреса сетевой карты, который, как известно, уникален.[6]
Далее представлено описание базовых принципов, являющихся основой данной технологии.
Основой возможности обеспечения взаимодействия компонент написанных на разных языках программирования является idl (interface description language – язык описания сценариев), а для технологии COM – midl (Microsoft idl). Idl предоставляет новы, по сравнению с существующими языками программирования уровень абстракции при создании объектов. Фактически idl описывает только интерфейсы объектов не говоря ни слова о реализации. Idl обладает некоторыми ограничениями, которые с одной стороны позволяют на основе интерфейса генерировать реализацию на любом из языков, поддерживаемых стандартом, а с другой стороны – полностью скрывать от взаимодействующих компонент различия языков, на которых они были реализованы, а также скрывать возможную распределенность объектов и инкапсулировать сетевое взаимодействие. Midl в первую очередь ориентирован на язык C++ и поэтому допускает некоторые вольности в описании интерфейсов, такие как возможность использования указателей, также в качестве базовых типов данных в midl используются базовые типы языка C.
2.1.1 Анатомия Майкрософт idl файла.
В данной части будет приведен пример и описание базовых конструкций описания интерфейса:
import "mydefs.h","unknwn.idl"; [object,uuid(a03d1420-b1ec-11d0-8c3a-00c04fc31d2f),] interface IFace1 : IUnknown{HRESULT MethodA([in] short Bread, [out] BKFST * pBToast);HRESULT MethodB([in, out] BKFST * pBPoptart);}; [object,uuid(a03d1421-b1ec-11d0-8c3a-00c04fc31d2f),pointer_default(unique)] interface IFace2 : IUnknown{HRESULT MethodC([in] long Max, [in, max_is(Max)] BkfstStuff[ ], [out] long * pSize, [out, size_is( , *pSize)] BKFST ** ppBKFST);};Ключевое слово import является аналогом команды препроцессора C #include, она используется включения файла Mydefs.h, который содержит пользовательские типы и Unknwn.idl, который содержит определение интерфейса IUnknown, от которого наследуются IFace1 и IFace2.
Атрибут object сообщает компилятору о том, что интерфейс является интерфейсом объекта и для него нужно сгенерировать прокси-код.
Атрибут uuid устанавливает идентификатор интерфейса (IID). Каждому интерфейсу, классу и библиотеке присваивается собственный уникальный идентификатор. Для генерации идентификаторов используется утилита Uuidgen.exe. При создании idl-файла в ручную необходимо использовать также вручную вызвать данную утилиту и вставлять в код сгенерированный ей IID, в случае автоматической генерации idl-файла при помощи Visual Studio необходимые IID будут сгенерированы и вставлены в код автоматически.
Ключевое слова interface определяет название интерфейса. Все объектные интерфейсы должны явно или не явно наследоваться от IUnknown.
Параметр in обозначает, что значение передается только в одном направлении – от клиента к серверу, и значение параметра устанавливается клиентом. Параметр out обозначает, что значение передается только от сервера к клиенту. Использование обоих параметров одновременно обозначает, что значение передается в обе стороны – от клиента к серверу и обратно.
Атрибут pointer_default устанавливает тип указателя, используемый по умолчанию для всех указателей, кроме тех, которые включены в список параметров. В midl существует 3 типа указателей: unique обозначает указатель к которому применимы следующие утверждения:
· может быть NULL
· во время вызова метода может изменяться с NULL на не-NULL, с не-NULL на NULL, с одного не-NULL значения на другое
· может выделять новую память в адресном пространстве клиента. Когда значение указателя меняется с NULL на не-NULL, данные, которые возвращаются из сервера записываются в новое хранилище
· может использовать уже выделенную в клиенте память. Данные, которые возвращаются с сервера записываются в ту же область памяти, на которую указатель указывал до вызова метода
· память, на которую указывает не нулевой указатель может быть никогда не освобождена в случае, если после изменения данного указателя у клиента не остается других указателей на данную область памяти
если пользователь не указывает типа указателей по умолчанию, mild предполагает unique типом указателей по умолчанию.
ref обозначает указатель к которому применимы следующие утверждения:
· не может быть NULL, всегда указывает на область памяти
· никогда не изменяется во время вызова. Этот тип указателей указывает на одну и ту же область памяти до и после вызова
· не может выделять новую память в адресном пространстве клиента, данные, возвращаемые сервером записываются существующую область памяти, на которую указывает указатель до вызова
ptr обозначает полноценный указатель, обладающий функциональностью, полностью соответствующей указателю языка С.
В приведенном примере BkfstStuff представляет собой массив, чей размер определяется во время выполнения программы. Атрибут max_is устанавливает переменную, которая содержит максимальное значение индекса массива.
Атрибут size_is также устанавливает размер массива или, как представленном примере, нескольких уровней указателей. Функция из примера может быть вызвана без наличия предварительных знаний о размере возвращаемых данных.
2.1.2 Компиляция idl-файла
Для любого idl-файла, в котором описаны один или несколько COM-интерфейсов и библиотека типов, компилятор MIDL генерирует следующие файлы:
· Filename.h – содержит определения типов и объявления функций для всех интерфейсов, определенных в idl-файле, а также определения дополнительных процедур необходимых для работы интерфейса
· Filename_p.c – покси-файл, который содержит замены точек входа клиентов и серверов
· Filename_i.c – содержит определения идентификаторов для каждого интерфейса, содержащегося в idl-файле
· Filename.tlb – содержит информацию о типах и объектах