Модель COM
Модель COM — это независимая от платформы, распределенная объектно-ориентированная система для создания двоичных компонентов программного обеспечения, которые могут взаимодействовать. COM — это базовая технология для Microsoft OLE (составных документов), ActiveX (компонентов с поддержкой Интернета), а также других.
Чтобы понять модель COM (и, следовательно, все технологии на основе COM), важно понимать, что это не объектно-ориентированный язык, а стандартный. И COM не указывает, как должно быть структурировано приложение. сведения о языке, структуре и реализации оставлены разработчику приложения. Вместо этого COM указывает объектную модель и требования к программированию, позволяющие COM-объектам (также называемым COM-компонентами или просто объектами) взаимодействовать с другими объектами. Эти объекты могут находиться в одном процессе, в других процессах и даже быть на удаленных компьютерах. Они могут быть написаны на разных языках, и они могут быть структурно непохожими, поэтому COM называется двоичным стандартом. стандарт, который применяется после преобразования программы в двоичный код машинного кода.
Единственное требование к языку для COM заключается в том, что код создается на языке, который может создавать структуры указателей, явно или неявно, вызывайте функции с помощью указателей. Объектно-ориентированные языки, такие как C++ и Smalltalk, предоставляют механизмы программирования, упрощающие реализацию COM-объектов, но такие языки, как C, Java и VBScript, можно использовать для создания и использования COM-объектов.
COM определяет важный характер COM-объекта. Как правило, программный объект состоит из набора данных и функций, управляющих данными. COM-объект — это тот, в котором доступ к данным объекта осуществляется исключительно через один или несколько наборов связанных функций. Эти наборы функций называются интерфейсами, и функции интерфейса называются методами. Кроме того, модель COM требует, чтобы единственный способ получить доступ к методам интерфейса — через указатель на интерфейс.
Помимо указания базового двоичного объекта, COM определяет некоторые основные интерфейсы, которые предоставляют функции, общие для всех технологий на основе COM, и предоставляет небольшое количество функций, требуемых для всех компонентов. COM также определяет, как объекты работают вместе в распределенной среде и имеют новые функции безопасности, помогающие обеспечить целостность системы и компонентов.
В следующих подразделах этого раздела описываются основные проблемы COM, связанные с проектированием COM-объектов.
Технология COM
Введение
COM (Component Object Model) — это метод разработки программных компонентов, небольших двоичных исполняемых файлов, которые предоставляют необходимые сервисы приложениям, операционным системам и другим компонентам. Другими словами, COM определяет стандартный механизм, с помощью которого одна часть программного обеспечения предоставляет свои сервисы другой независимо от способа их реализации.
COM — это не язык программирования, а подход (спецификация) к созданию программ, обеспечивающий взаимодействие программ любых типов. Компоненты COM объединяются друг с другом для создания приложений или систем компонентов. Компоненты можно менять во время выполнения, без перекомпиляции или перекомпоновки приложения. COM — это основа, на которой построены такие технологии Microsoft, как ActiveX, DirectX и OLE.
Таким образом, ключевое слово при использовании COM — компонент. К компонентам обычно предъявляются следующие требования:
1. Компонент должен скрывать используемый язык программирования.
2. Компоненты должны распространяться в двоичной форме. Их необходимо поставлять уже скомпилированными, скомпонованными и готовыми к использованию.
3. Должна быть возможность модернизировать компоненты, не затрагивая уже существующих пользователей. Новые версии компонента должны работать как со старыми, так и с новыми клиентами.
4. Компоненты должны перемещаться по сети. Необходимо, чтобы компонент и использующая его программа могли выполняться внутри одного процесса, в разных процессах и на разных машинах.
Как вы, вероятно, догадались, компоненты COM удовлетворяют всем этим требованиям.
Преимущества использования компонентов
COM обеспечивает создание распределенных модульных систем в архитектуре «клиент-сервер». COM имеет следующие преимущества по сравнению с традиционной архитектурой программных систем:
1. COM предоставляет стандартный набор функций для доступа к провайдеру сервиса (COM-серверу), получения информации о предоставляемых им сервисах и вызова требуемого сервиса. В качестве COM-сервера может выступать операционная система или приложение.
2. COM использует объектно-ориентированные концепции для обеспечения модульности при построении сложных распределенных систем, а также для повторного использования готовых компонентов и их разработки с сохранением совместимости с предыдущими версиями.
3. COM реализует модель вычислений «клиент-сервер», что обеспечивает преимущества распределенной обработки данных.
4. COM обеспечивает вызов сервисов в сетевом окружении, независимо от расположения COM-сервера.
Использование программных компонентов, разработанных на основе технологии COM, значительно расширяет возможности разработчиков приложений, конечных пользователей и предприятий:
1. Разработчики приложений могут повысить эффективность своей работы за счет создания легко масштабируемых систем на базе готовых компонентов, а также получают возможность встраивать компоненты собственной разработки в существующие системы.
2. Конечные пользователи получают широкий выбор готовых стандартизированных программных компонентов, которые они могут использовать в своих системах.
3. Предприятия также могут использовать преимущества компонентного подхода, так как доступность готовых программных компонентов общего назначения позволяет сконцентрироваться на разработке компонентов, специфичных для сферы бизнеса данного предприятия. Компонентная архитектура также позволяет создавать интерфейсы к существующим корпоративным системам и предоставлять объектно-ориентированный доступ к их данным.
Кроме очевидных способности приложения эволюционировать с течением времени, удобства и гибкости при модернизации существующих приложений, создание программ из компонентов имеет другие достоинства.
Адаптация приложений. Пользователи часто хотят подстроить приложения к своим нуждам. Конечные пользователи предпочитают, чтобы приложение работало так, как они привыкли. Компонентные архитектуры хорошо приспособлены для адаптации, так как любой компонент можно заменить другим, более соответствующим потребностям пользователя.
Библиотеки компонентов. Одна из самых многообещающих сторон внедрения компонентной архитектуры — быстрая разработка приложений. Компоненты, помещенные в библиотеку, можно использовать как детали вашего нового приложения.
Распределенные компоненты. С возрастанием производительности и общего значения сетей потребность в приложениях, состоящих из разбросанных по разным местам кусков, будет только повышаться. Компонентная архитектура помогает упростить процесс разработки подобных распределенных приложений. Создать из обычного приложения распределенное легче, если это обычное приложение состоит из компонентов.
СОМ и объектно-ориентированный подход
СОМ является объектно-ориентированной технологией, но она отличается от других объектно-ориентированных технологий:
— СОМ-объект поддерживает более одного интерфейса
— Класс в СОМ понимается как описание конкретной реализации набора интерфейсов
— СОМ-объекты поддерживают только наследование интерфейса, т.е. потомок должен самостоятельно определить код методов родителя.
Понятие OLE и ActiveX
OLE (Object Linking and Embedding) — технология создания составных документов связыванием и внедрением. Документ сервера может быть либо связан, либо внедрен в документ контейнера. Методы создания составных документов: копирование и вставка через буфер обмена либо метод drag-and-drop.
Контейнер составных документов должен поддерживать интерфейсы: IOleClientSite (позволяет серверу обращаться к своему контейнеру) и IAdviseSink (сервер использует для того, чтобы информировать контейнер о том, что происходит с ним).
ActiveX — технология создания приложений на основе СОМ. Спецификация управляющих элементов ActiveX определяет четыре основных аспекта их функционирования: обеспечение пользовательского интерфейса, обеспечение вызова методов управляющего элемента контейнером, посылка событий контейнеру, получение информации о свойствах среды контейнера и обеспечение доступа к свойствам управляющего элемента и их модификации.
Интерфейсы СОМ-объекта
Интерфейс СОМ предназначен для связи между компонентами и включает в себя набор функций, которые реализуются компонентами и используются клиентами. Свойства СОМ-интерфейса такие: у каждого интерфейса имеется два идентификатора (пользовательский идентификатор и глобальный уникальный идентификатор); интерфейсы после своего опубликования не могут быть изменены; добавление новой функциональности требует определения нового интерфейса; для интерфейса определен стандартный двоичный формат; каждый интерфейс наследует стандартный интерфейс IUnknown; СОМ-объект может описывать свои интерфейсы на любом языке.
Назначение интерфейса Iunknown — запрос указателя на другой интерфейс и отслеживание текущего количества клиентов СОМ-объекта. Описание же интерфейса Iunkown выглядит следующим образом:
#define interface struct
interface IUnknown
<
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)=0;
// запрос интерфейса
virtual ULONG __stdcall AddRef()=0; // увеличение счетчика ссылок
virtual ULONG __stdcall Release()=0; // уменьшение счетчика ссылок
>;
Глобальный уникальный идентификатор
GUID(Globally Unique IDentifier) или UUID(Universally Unique Identifiers) — это 16-байтовая величина, которая генерируется специальной программной утилитой UUIDGEN.EXE или GUIDGEN.EXE. Любой GUID уникален во времени и пространстве. Он включает в себя время (60 бит — число 100-наносекундных интервалов, прошедших с 00:00:00:00 15 октября 1582 года) и адрес сетевой платы (48 бит). Например:
Описание интерфейса на С++ будет таким:
interface IА : IUnknown
<
virtual void __stdcall Fx() =0;
>;
Ключевое слово _stdcall указывает, что функция с фиксированным числом аргументов в СОМ-интерфейсах использует вызов в стиле Pascal.
QueryInterface
IUnknown содержит функцию — QueryInterface, при помощи которой клиент определяет, поддерживается ли тот или иной интерфейс. QueryInterface возвращает указатель на интерфейс, если компонент его поддерживает; в противном случае возвращается код ошибки (клиент может запросить указатель на другой интерфейс или аккуратно выгрузить компонент).
У QueryInterface два параметра :
Virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
Первый параметр — идентификатор интерфейса, так называемая IID-структура.
Второй параметр — адрес, по которому QueryInterface помещает указатель на искомый нтерфейс.
QueryInterface возвращает HRESULT (32-разрядный код результата, записанный в определенном формате). QueryInterface может возвратить либо S_OK, либо E_NOINTERFACE. Клиент не должен прямо сравнивать возвращаемое QueryInterface значение с этими константами; для проверки надо использовать макросы SUCCEEDED или FAILED.
Предположим, что у нас есть указатель на IUnknown, pI. Чтобы определить, можно ли использовать некоторый другой интерфейс, мы вызываем QueryInterface, передавая ей идентификатор нужного нам интерфейса. Если QueryInterface отработала успешно, мы можем пользоваться указателем:
void foo(IUnknown* pI)
<
// Определить указатель на интерфейс IX* pIX = NULL;
// Запросить интерфейс IX
HRESULT hr = pI->QueryInterface(IID_IX, (void**)&pIX);
// Проверить значение результата if (SUCCEEDED(hr))
<
// Использовать интерфейс pIX->Fx();
>
>
В этом фрагменте кода мы запрашиваем у pI интерфейс, идентифицируемый с помощью IID_IX. Определение IID_IX содержится в заголовочном файле, предоставляемом компонентом (или извлекается из библиотеки типа). Для неудачного запроса
QueryInterface должна устанавливать возвращаемый указатель в NULL. Однако, поскольку QueryInterface реализуется программистом компонента, в некоторых реализациях это наверняка не будет сделано. Для безопасности следует установить указатель в NULL самостоятельно. Ниже приведен пример реализации QueryInterface:
Тип данных HRESULT
QueryInterface и многие другие функции COM возвращают HRESULT. Что это? HRESULT — это 32-разрядное число, разбитое на три секции: источник ошибки (биты с 16 по 30), код ошибки (биты с 0 по 15) и признак ошибки (31 бит, 0 означает, что ошибки нет).
Коды возврата бывают такие:
— S_OK или NOERROR — функция отработала успешно, значение 0
— S_FALSE — функция отработала успешно, значение 1
— E_UNEXPECTED — неожиданная ошибка
— E_NOTIMPL — функция не реализована
— E_NOINTERFACE — объект не поддерживает интерфейс
— E_OUTOFMEMORY — объект не может выделить память
— E_FAIL — ошибка по неуказанной причине
А источники ошибки такие:
Макросы STDMETHOD и STDMETHODIMP
Макросы STDMETHOD и STDMETHOD_ применяются при объявлении методов интерфейса, а макросы STDMETHODIMP и STDMETHODIMP_ при описании реализации метода.
Вместо
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
можно записать
STDMETHOD(QueryInterface(const IID& iid, void** ppv));
Вместо
virtual void __stdcall Fy() =0;
можно записать
STDMETHOD_(void, Fy()) PURE;
The Component Object Model
The Microsoft Component Object Model (COM) is a platform-independent, distributed, object-oriented system for creating binary software components that can interact. COM is the foundation technology for Microsoft’s OLE (compound documents), ActiveX (Internet-enabled components), as well as others.
To understand COM (and therefore all COM-based technologies), it is crucial to understand that it is not an object-oriented language but a standard. Nor does COM specify how an application should be structured; language, structure, and implementation details are left to the application developer. Rather, COM specifies an object model and programming requirements that enable COM objects (also called COM components, or sometimes simply objects) to interact with other objects. These objects can be within a single process, in other processes, and can even be on remote computers. They can be written in different languages, and they may be structurally quite dissimilar, which is why COM is referred to as a binary standard; a standard that applies after a program has been translated to binary machine code.
The only language requirement for COM is that code is generated in a language that can create structures of pointers and, either explicitly or implicitly, call functions through pointers. Object-oriented languages such as C++ and Smalltalk provide programming mechanisms that simplify the implementation of COM objects, but languages such as C, Java, and VBScript can be used to create and use COM objects.
COM defines the essential nature of a COM object. In general, a software object is made up of a set of data and the functions that manipulate the data. A COM object is one in which access to an object’s data is achieved exclusively through one or more sets of related functions. These function sets are called interfaces, and the functions of an interface are called methods. Further, COM requires that the only way to gain access to the methods of an interface is through a pointer to the interface.
Besides specifying the basic binary object standard, COM defines certain basic interfaces that provide functions common to all COM-based technologies, and it provides a small number of functions that all components require. COM also defines how objects work together over a distributed environment and has added security features to help provide system and component integrity.
The following topics in this section describe basic COM issues related to designing COM objects: