Файл: Технология СОМ (Создание и повторное применение объектов СОМ. Маршалинг).pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 25.06.2023

Просмотров: 158

Скачиваний: 3

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

По прибытии в процесс локального сервера запрос передается заглушке (stub). Заглушка распаковывает параметры и вызывает метод внутри объекта. По завершении выполнения метода результаты возвращаются в обратном направлении по тому же маршруту. С точки зрения клиента вызов аналогичен вызову внутризадачного сервера, но выполняется гораздо медленнее (рис. 6).

Рис.6. Доступ к объекту СОМ, реализованному в локальном сервере

Наиболее сложный вариант - когда реализован удаленный сервер. Архитектура поддержки удаленных серверов (DCOM) во многом похожа на используемую для серверов локальных. Клиент использует заместитель, а сервер - заглушку. Но вызов метода осуществляется через сеть с помощью механизма вызова удаленной процедуры (RPC - remote procedure call). С точки зрения клиента вызов аналогичен предыдущим, но выполняется еще более медленнее (рис. 7).

Рис.7. Доступ к объекту СОМ, реализованному в удаленном сервере

Параметры, пересылаемые между процессами или машинами должны быть упакованы перед пересылкой и распакованы по прибытии. Подобные упаковка и распаковка называются маршалингом (marshaling) и демаршалингом (unmarshaling). Код, знающий как эти операции выполнять, называется кодом маршалинга или маршалером (marshaler). Основная задача заместителей и заглушек - выполнение маршалинга и демаршалинга для конкретного интерфейса.

Имеются программы, которые автоматически позволяют генерировать код маршалинга, разбитый на заместителя и заглушку по описанию интерфейса на IDL, например MIDL (Microsoft IDL). Файлы, полученные с помощью MIDL, можно непосредственно использовать в программах на языках С и C++.

Заместители и заглушки, создаваемые автоматически, используют стандартный маршалинг. В случае необходимости, разработчики программ могут заменить стандартный маршалинг собственным, например для повышения быстродействия.

Разработка заместителей и заглушек производится на этапе разработки объекта и, таким образом, являются статическим вариантом построения маршалеров. Предполагается, что клиент уже знает, какие интерфейсы он будет вызывать. Если же клиент имеет возможности работать с интерфейсами, о существовании которых он узнал уже во время выполнения, то такой вариант связывания не подходит. Используют так называемое «позднее связывание» (late binding). Его идея состоит в том, чтобы позволить клиенту динамически конструировать вызовы вновь обнаруженных интерфейсов.


Как было сказано ранее, описание интерфейса на IDL достаточна для генерации кода заместителя и заглушки, следовательно ее можно использовать и для осуществления динамического маршалинга. Для этого по описанию интерфейса на IDL генерируется библиотека типа (type library) с помощью, например MIDL, которая регистрируется в системном реестре.

3. Технологии, основанные на СОМ

3.1. Автоматизация (automation)

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

Часто для создания программ, управляющих другими приложениями используются простые графические инструменты типа Visual Basic. Но при этом возникает проблема. СОМ интерфейсы реализуются с помощью виртуальной таблицы указателей на функции и для вызова метода клиент должен быть способен с ней работать, что может быть недоступно для подобных сред.

Для решения этой проблемы служит стандартный COM-интерфейс IDispatch. Большинство объектов автоматизации поддерживают IDispatch, хотя это и не является обязательным. Автоматизация означает программируемость вообще.

Диспинтерфейсы. Основным методом интерфейса IDispatch является метод Invoke. Через него клиент может вызвать любой метод из некоторой группы методов. Группу методов, которые могут вызываться через IDispatch::Invoke называют днспинтерфейсом. Каждому методу днспинтерфейса ставится в соответствие целое число - диспетчерский идентификатор (dispatch identifier - DISPID). Для вызова метода диспинтерфейса клиент вызывает IDispatch::Invoke, передавая DISPID нужного метода диспинтерфейса, который по DISPID вызывает нужный метод. Таким образом, любой программе, использующей методы диспинтерфейсов, необходимо уметь вызывать только IDispath::Invoke и нет необходимости уметь работать с виртуальной таблицей методов, это за них сделает метод Invoke.

Параметры методов диспинтерфейса должны передаваться при вызове метода Invoke, причем передаваться всегда однотипно. Клиент перед вызовом Invoke упаковывает параметры диспинтерфейса в вариант (variant). Вариант определяет стандартную форму для каждого параметра и идентификатор типа параметра (короткое целое, длинное целое, строка и т.п.). Этот вариант передается методу Invoke вместе с DISPID. Метод Invoke распаковывает вариант и вызывает нужный метод, передавая ему содержащиеся в варианте параметры. Возвращаемы методом результаты упаковываются методом Invoke, а распаковываются клиентом. Таким образом, заглушка и заместитель для IDispath любого диспинтерфейса всегда одни и те же, что позволяет выполнять позднее связывание. Для получения информации о методах диспинтерфейса можно использовать библиотеку типов, а при ее отсутствии - метод IDispatch:


GetlDsOfNames - возвращает DISPID по имени метода.

Методы IDispath::GetTypeInfo возвращает указатель на информацию о типе (Itypelnfo), а метод IDispatch::GetTypeInfoCount - возвращает информацию о том, поддерживает ли данный объект выдачу информации о типе в период выполнения.

Рис. 8. Диспинтерфейсы

Дуальные интерфейсы. Доступа к методам объекта только через диспинтерфейсы во многих случаях недостаточно. Если для клиентов на Visual Basic нужны диспинтерфейсы, то клиенты на С предпочитают виртуальные таблицы (из соображений быстродействия, типов параметров, которые можно паковать в вариант, и необходимости дополнительной работы при вызове методов через IDispatch). В этом случае используется дуальный интерфейс (dual interlace). Методы дуального интерфейса могут вызываться и через IDispatch и напрямую, через виртуальную таблицу.

Каждый дуальный интерфейс является потомков IDispatch. Он включает методы IDispatch и собственные методы интерфейса. Таким образом, эти методы доступны через виртуальную таблицу, и именно их вызывает IDispatch::Invoke.

Рис. 9. Дуальный интерфейс

3.2. Перманентность (persistent)

Объекты состоят из методов и данных, многим объектам необходимо сохранять свои данные в периоды неактивности, сохраняя их, обычно, на диске. Такие данные называют перманентными.

Так как СОМ обеспечивает совместную работу разных объектов в одной программе, то эти отдельные СОМ объекты должны быть способны сохранять информацию в одном общем файле, независимо от того какие именно и сколько объектов его создают. Один из наиболее распространенных путей достичь этого - структурированное хранилище.

Один файл структурированного хранилища состоит из хранилищ (storage) и потоков (stream). Реализацию файлов подобной структуры называют в Microsoft Windows составными файлами (compound file).

Каждый составной файл содержит корневое хранилище, в котором могут располагаться другие потоки и хранилища, в этих хранилищах в свою очередь потоки и хранилища - получается древовидная структура. Объектам, использующим структурированное хранилище, выделяются его потоки или хранилища.

Хранилища и потоки рассматриваются как COM-объекты, и доступ к каждому осуществляется через соответствующий интерфейс: хранилища - IStorage, потоки - IStream.

Обычно нет необходимости писать свою реализацию для этих интерфейсов - она предоставляется системой. Но при желании можно реализовать свою схему хранения.


Реализация структурированного хранилища включает функции:

- StgCreateDocFile - создает новый составной файл,

- StgOpenStorage - открывает существующий составной файл,

- StglsStorageFile - позволяет определить, является ли некоторый файл составным.

Первые две возвращают в качестве параметра указатель на интерфейс IStorage.

Структурированное хранилище - один из способов, каким клиент может организовать перманентное хранение данных всех его объектов. Рассмотрим, каким образом происходит взаимодействие клиента и объектов на предмет сохранения или загрузки данных. Для этого объект должен реализовать один из интерфейсов IPersist*, таких как:

- IPersistStream - загрузка и сохранение данных в потоке (в качестве параметров методов Save и Load передается указатель на IStream)

- IPersistStreamlnit - похож на предыдущий + возможность сообщить о том, что он инициализируется в первый раз

- IPersistStorage - загрузка и сохранение данных в хранилище (в качестве параметров методов Save и Load передается указатель на IStorage)

- IPersistFile - загрузка и сохранение данных в обычном файле (в качестве параметров методов Save и Load передается имя файла)

- IPersistPropertyBag - загрузка и сохранение данных как набора свойств

- IPersistMoniker - загрузка и сохранение данных с помощью моникера

IPersistMemory - загрузка и сохранение данных в у казанной области памяти.

Создав объект СОМ объект клиент обычно первым запрашивает его интерфейс из группы IPersist*, и вызывает его метод Load, передавая соответствующий параметр (например указатель на соответствующий поток IStream в предварительно открытом составном файле). После того, как объект загрузит свои данные, он готов к работе. Когда клиенту необходимо сохранить все данные на диске, например перед выгрузкой, он вызывает метод Save интерфейсов IPersist* всех своих объектов, заставляя тем самым объекты сохранить свои данные там, где у казано.

3.3. Моникеры (moniker)

Моникер представляет собой COM-объект специфического назначения - он знает как создавать и инициализировать экземпляр другого объекта. Вообще, моникеры в среде СОМ не необходимы, но полезны. Создать и проинициализировать COM-объект клиент может, вызвав CoCreatelnstance, а затем метод Load одного из интерфейсов IPersist* для созданного экземпляра объекта. Но проще это сделать с помощью моникера.

Моникер идентифицирует конкретный объект. Он является COM-объектом, который поддерживает интерфейс IMoniker и имеет собственные перманентные данные, которые достаточны, чтобы создать и проинициализировать экземпляр объекта.


Если клиент имеет указатель на IMoniker, то он может получить уже проинициализированный конкретными данными объект, вызвав метод BindToObject этого интерфейса. В качестве параметра передается IID задающего требуемый интерфейс целевого объекта. Этот метод выполнит все обычные действия по созданию и инициализации объекта. Понятно, что перед тем, как использовать методы моникера, клиент должен его создать и проинициализировать. Если эти действия не проще создания и инициализации нужного объекта, то моникер не даст никакого выигрыша. Но иногда использовать его удобно.

Например, при организации составного документа, данные внедренных объектов можно хранить в том же файле или в другом файле - связывание. Тогда файл контейнера должен содержать ссылку на связанный файл, в качестве которой и можно использовать моникер, точнее его перманентные данные. Это позволит контейнеру однотипно работать со связанными документами, создаваемыми любыми приложениями.

Определены различные стандартные классы моникеров: файловые моникеры, моникеры элементов, композитные моникеры и др. Наиболее интересны композитные моникеры, которые содержат указатели на моникеры элементов. Реализации интерфейса IMoniker для стандартных классов предоставляются системой. Разрабатывать их надо только для нестандартных классов.

Для создания экземпляра моникера можно использовать CoCreateInstance с соответствующим CLSID, но имеются и специальные системные функции, типа CreateFileMoniker, CreateltemMoniker. Первой из них в качестве параметра передается полное имя файла, а возвращается в качестве параметра указатель на интерфейс IMoniker. Класс экземпляра объекта, который должен быть создан, файловый моникер может определить по расширению файла.

3.4. Единообразная передача данных

Обмен данными - фундаментальная операция в программировании, поэтому имеется множество схем. Стандартный способ обмена информацией в СОМ - единообразная передача данных (Uniform Data Transfer). Основополагающий интерфейс для единообразной передачи данных - IDataObject.

Любой COM-объект, реализующий IDataObject рассматривается как объект данных (data object). Данные всех таких объектов принимаются и передаются ими по одной стандартной схеме. IDataObject служит для создания одного стандартного интерфейса с одним набором методов, который позволял бы получить доступ к любым данным объекта.