Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
конспектлекцийАсоиу_до2012.doc
Скачиваний:
105
Добавлен:
11.02.2015
Размер:
1.79 Mб
Скачать

Маршалинг

Клиент может содержать прямую ссылку на СОМ-объект только в одном случае — когда СОМ-объект размещен в сервере «в процессе». В случае локального или удаленного сервера, как показано на рис. 13.23, он ссылается на посредника.

Посредник — СОМ-объект, размещенный в клиентском процессе и предоставляющий клиенту те же интерфейсы, что и запрашиваемый объект. Запрос клиентом операции через такую ссылку приводит к исполнению кода посредника.

Посредник принимает параметры, переданные клиентом, и упаковывает их для дальнейшей пересылки. Эта процедура называется маршалингом. Затем посредник (с помощью средства коммуникации) посылает запрос в процесс, который на самом деле реализует СОМ-объект.

Рис. 13.23. Организация маршалинга и демаршалинга

По прибытии в процесс локального сервера запрос передается заглушке. Заглушка распаковывает параметры запроса и вызывает операцию СОМ-объекта. Эта процедура называется демаршалингом. После завершения СОМ-операции результаты возвращаются в обратном направлении.

Код посредника и заглушки автоматически генерируется компилятором MIDL (Microsoft IDL) по IDL-описанию интерфейса.

IDL-описаниеи библиотека типа

Помимо информации об интерфейсах, IDL-описание может содержать информацию о библиотеке типа.

Библиотека типа определяет важные для клиента характеристики СОМ-объекта: имя его класса, поддерживаемые интерфейсы, имена и адреса элементов интерфейса.

Рассмотрим пример приведенного ниже IDL-описания объекта для работы с файлами. Оно состоит из 3 частей. Первые две части описывают интерфейсы IРаботаСФайлами и IПреобразованиеФорматов, третья часть— библиотеку типа ФайлыБибл. По первым двум частям компилятор MIDL генерирует код посредников и заглушек, по третьей части — код библиотеки типа:

-----------1-я часть

[ object,

uuid(E7CDODOO-1827-11CF-9946-444553540000) ]

interface IРаботаСФайлами; IUnknown

{ import "unknown.idl"

HRESULT ОткрытьФайл ([in] OLECHAR имя[31]);

HRESULT ЗаписатьФайл ([in] OLECHAR имя[31]);

HRESULT ЗакрытьФайл ([in] OLECHAR имя[31]);

}

----------- 2-я часть

[ object.

uuid(5FBDD020-1863-11CF-9946-444553540000) ]

interface IПреобразованиеФорматов: IUnknown

{ HRESULT ПреобразоватьФормат ([in] OLECHAR имя[31],

[in] OLECHAR формат[31]);

}

------------ 3-я часть

[ uuid(B253E460-1826-11CF-9946-444553540000),

version (1.0)]

library ФайлыБибл

{ importlib ("stdole32.tlb");

[uuid(B2ECFAAO-1827-11CF-9946-444553540000) ]

coclass СоФайлы

{ interface IРаботаСФайлами;

interface IпреобразованиеФорматов;

}

}

Описание библиотеки типа начинается с ее уникального имени (записывается после служебного слова uuid), затем указывается номер версии библиотеки.

После служебного слова library записывается символьное имя библиотеки (ФайлыБибл).

Далее в операторе importlib указывается файл со стандартными определениями IDL - stdole32.tlb.

Тело описания библиотеки включает только один элемент — СОМ-класс (coclass), на основе которого создается СОМ-объект.

В начале описания СОМ-класса приводится его уникальное имя (это и есть идентификатор класса — CLSID), затем символьное имя — СоФайлы. В теле класса перечислены имена поддерживаемых интерфейсов — РаботаСФайлами и IПреобразованиеФорматов.

Как показано на рис. 13.24, доступ к библиотеке типа выполняется по стандартному интерфейсу ITypeLib, а доступ к отдельным элементам библиотеки — по интерфейсу ITypelnfo.

Рис. 13.24. Доступ к библиотеке типа

  1. . Объекты автоматизации и интерфейс IDispatch

В технологиях OLE/COM (см. главу 25) активно используются так называемые объекты автоматизации (Automation objects). Эти объекты представляют собой экземпляры компонентных классов, родительским интерфейсом которых являет­ся специальный интерфейс IDispatch. Отличительной особенностью интерфей­са IDispatch является то обстоятельство, что методы объектов автоматизации никогда не вызываются напрямую, но всегда — с помощью метода Invoke интер­фейса IDispatch.

Для объявления класса автоматизации используется специальное зарезерви­рованное слово dispinterf асе, а перечисляемые в объявлении методы и свой­ства должны снабжаться целочисленными идентификаторами, которые вставля­ются в конце описания методов (свойств) после зарезервированных слов dispid:

type

IStringsDisp = dispinterface

['{EE05DFE2-5549-11DO-9EA9-0020AF3D82DA}']

property ControlDefault[Index: Integer]: OleVariant dispid 0; default;

function Count: Integer; dispid 1;

property Item[Index: Integer]: OleVariant dispid 2;

procedure Remove(Index: Integer); dispid 3;

procedure Clear; dispid 4;

function Adddtem: OleVariant): Integer; dispid 5;

function _NewEnum: lUnknown; dispid -4; end;

С помощью зарезервированного слова dispid методу (свойству) интерфейса ставится в соответствие целочисленный номер. Это дает возможность языкам про­граммирования, не поддерживающим указатели (Visual Basic, Java и др.), обра­щаться к методам и свойствам интерфейсных объектов по их именам. Для этого объект, имеющий интерфейс, родителем которого является dispinterface, ав­томатически создает таблицу имен его методов и свойств с указанием идентифи­каторов dispid. При обращении к методу по имени компилятор создает код вы­зова специального метода IDispatch.GetlDsOfName. Этот метод отыскивает в таблице имен нужное имя и возвращает соответствующий идентификатор dispid (если имя не найдено, возникает исключительная ситуация). Затем программа

использует полученный идентификатор как один из аргументов вызова метода IDispatch. Invoke. Этот метод отыскивает описание вызываемого метода в спе­циальной таблице, проверяет количество и тип передаваемых методу параметров вызова и, если все правильно, вызывает его.

В отличие от обычного компонентного класса, класс автоматизации не может иметь родительского класса, и поэтому за словом dispinterf асе нельзя указать список родителей. Идентификаторы методов (свойств) должны быть уникальны­ми в пределах объявления класса. Все возвращаемые функциями и свойствами результаты, а также все параметры обращения к методам должны иметь один из следующих типов: Byte, Currency, Real, Double, Longlnt, Integer, Single, Smalllnt, AnsiString, WideString, TDateTime, Variant, OleVariant, WordBool или любой интерфейсный тип. За исключением директивы default, которую можно указать для свойства-массива, никакие другие директивы в объяв­лении методов и свойств не допускаются.

Для доступа к объектам автоматизации используются переменные типа вариант. Инициализация такой переменной осуществляется вызовом функции Create-OleOb j ect, определенной в модуле ComOb j. Эта функция возвращает ссылку на интерфейс IDispatch, с помощью которой можно обращаться к методам и свой­ствам класса автоматизации так, как если бы они были методами и свойствами варианта. Например:

Uses ComObj;

... ^ var

Word: Variant; begin

Word := CreateOleObject('Word.Basic'); Word.FileNew('Normal'); Word.Insert('Первая строка'#13); Word.Insert('Вторая строка'#13); Word.FileSaveAs('c:\temp\test.txt', 3) ; end;

Параметром обращения к методу CreateOleOb j ect является имя сервера авто­матизации, которое должно быть предварительно зарегистрировано в реестре 32-раз­рядных версий Windows. Характерно, что методы сервера не известны на этапе ком­пиляции программы, поэтому компилятор никак не контролирует правильность их вызовов. Названия методов не подчиняются правилам построения идентификато­ров Delphi, и в них могут использоваться символы национальных алфавитов.

Передаваемые методам параметры могут быть позиционными и именованны­ми. Позиционные параметры являются обычными для подпрограмм Delphi пара­метрами-значениями. Именованные параметры записываются в следующем виде:

<имя_параметра> := <значение>

Например, при обращении к методу FileSaveAs (см. выше) были использо­ваны два позиционных параметра. Это же обращение можно было бы записать с ис­пользованием именованных параметров следующим образом:

Word.FileSaveAs(Format := 3, Name := 'c:\temp\test.txt');

Именованные параметры могут перечисляться в произвольном порядке, но обя­зательно после позиционных параметров, если те тоже присутствуют в обраще­нии.

Интерфейсы — наследники от IDispatch — называются дуальными, так как они дублируют свойства и методы основного интерфейса. Иными словами, Delphi может выполнять одну и ту же работу, либо обращаясь к экземплярам компонент­ного класса и используя указатели на нужные методы, либо по имени — с помощью дуального интерфейса. В отличие от этого, в Visual Basic доступен только послед­ний способ. Методы дуальных интерфейсов (кроме унаследованных от интерфей­сов lUnknow и IDispatch) должны компилироваться в режиме safecall.