Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Модель компонентного объекта



Общие сведения о COM

 

COM (Component Object Model, объектная модель компонентов) — это технологический стандарт от компании Microsoft, предназначенный для создания программного обеспечения на основе взаимодействующих компонентов, каждый из которых может использоваться во многих программах одновременно. Стандарт воплощает в себе идеи полиморфизма и инкапсуляции объектно-ориентированного программирования. Стандарт COM мог бы быть универсальным и платформо-независимым, но закрепился в основном на операционных системах семейства Microsoft Windows. В современных версиях Windows COM используется очень широко. На основе COM были реализованы технологии: Microsoft OLE Automation, ActiveX, DCOM, COM+, DirectX, а также XPCOM.

 

Что такое COM

COM является платформно-независимой, объектно-ориентированной технологией, позволяющей создавать бинарные компоненты. Эти компоненты можно использовать как локально, так и в распределенном сетевом окружении. COM служит основой для: OLE (технология составных документов), ActiveX-объектов и элементов управления ActiveX, DCOM, COM+.

DCOM (Distributed COM) – это расширение COM, делающее эту модель распределенной, то есть позволяющей вызывать COM-объекты, находящиеся на другом компьютере в сети.

MTS (Microsoft Transaction Server) – это сервер приложений позволяющий создавать распределенные приложения, поддерживающие транзакции. Вопреки распространенному мнению, хотя слово «транзакция» входит в название этого сервера, приложения, создаваемые на базе MTS, совершенно не обязаны использовать предоставляемый механизм транзакций.

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

 

Немного истории

Технологии ActiveX охватывают обширные области программного обеспечения. Корпорация Microsoft применяет их повсеместно в своих продуктах. Они также интенсивно используются в операционных системах. В этой лекции мы рассмотрим технологию, которая лежит в основе стандартов OLE и ActiveX – модель компонентного объекта (Component Object Model - СОМ). Для лучшего понимания сущности этой модели будет разработан простой СОМ-компонент. Сначала мы напрямую воспользуемся возможностями языка C++, а затем перейдем к использованию библиотеки активных шаблонов (Active Template Library – ATL), которая представляет собой множество шаблонов языка C++, предназначенных для построения эффективных СОМ-компонентов.

 

Модель компонентного объекта

Модель компонентного объекта фирмы Microsoft является, как следует из её названия, моделью для проектирования и создания компонентных объектов. Модель определяет множество технических приемов, которые могут быть использованы разработчиком при создании независимых от языка программных модулей, в которых соблюдается определенный двоичный стандарт. Корпорация Microsoft обеспечивает реализацию модели СОМ во всех своих Windows-средах. В других операционных средах, таких как Macintosh и UNIX, технология СОМ также поддерживается, но не обязательно средствами фирмы Microsoft.

Технологии OLE и ActiveX являются высокоуровневыми программными сервисами, построенными фирмой Microsoft на основе технологии СОМ. Доступ к средствам СОМ, OLE и ActiveX обеспечивается операционной системой Windows посредством набора СОМ-интерфейсов и небольшого числа функций WIN32 API. Как и в случае с СОМ, в отличных от Windows операционных системах также поддерживаются сервисы подобные OLE и ActiveX.

 

Свойство СОМ: двоичный стандарт (независимость от языка программирования)

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

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

Например, если мы разрабатываем С++-класс, предназначенный для манипулирования с данными, то необходимым условием его использования в других приложениях является их разработка на языке C++. Только С++-компиляторы могут распознать С++-классы. Фактически, поскольку средства C++ не поддерживают никакого стандартного способа адаптации вызовов С++-функций к новой программной среде, использование программного обеспечения в этой новой среде требует применения такого же (или аналогичного) инструментального средства для его обработки. Другими словами, использование класса в другой операционной среде требует обязательного переноса в эту среду исходного текста программы данного класса.

Применение двоичного кода позволяет разработчику создавать программные компоненты, которые могут применяться без использования языков, средств и систем программирования, а только с помощью двоичных компонентов (например, DLL- или ЕХЕ-файлов). Эта возможность является для разработчиков очень привлекательной. Ведь теперь они могут выбирать наиболее удобный для себя язык и средство разработки компонентов, не заботясь о языке и средствах, которые будет использовать другой разработчик.

Таблица 1 дает нам представление о том, что что C++ и СОМ представляют собой две совершенно разные вещи.

Таблица 1. Сравнение объектов C++ и СОМ

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

Итак, C++ - это язык, а СОМ - технология.

 

Понятия OLE и ActiveX

Термин OLE имеет длинную историю. Вначале (приблизительно с 1991 года) он представлял собой сокращение слов Object Linking and Embedding (связывание и внедрение объектов). Первоочередной задачей OLE в то время была поддержка связывания и внедрения объектов в Windows-приложениях. Возможности получаемых таким образом составных документов позволяли пользователям внедрять электронные таблицы Excel непосредственно в документы Word и т.д.

Впоследствии, с выходом версии OLE 2.0 (приблизительно в 1993 году), термин OLE перестал употребляться как просто сокращение и вобрал в себя понятия нескольких технологий, основанных на модели компонентного объекта. Многие новые возможности OLE не имеют ничего общего со связыванием и внедрением. Хорошим примером этого является OLE-автоматизация (или просто автоматизация), вообще не имеющая отношения к составным документам. Основной задачей OLE-автоматизации является обеспечение взаимодействия компонентов и приложений независимо от языков программирования и средств разработки.

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

 

COM-объекты, интерфейсы, С++ и о том, как это работает

 

Язык C++, компоненты и интерфейсы

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

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

class Math

{

// описание интерфейса

public:

long Add( long Op1, long Op2 );

long Subtract( long Qp1, long Op2 );

long Multiply( long Op1, long Ор2 );

long Divide( long Op1, long Op2 );

 

private:

// реализация

string m_strVersion;

string get_Version( );

};

 

long Math:: Add( long Op1, long Op2 )

{

return Op1 + Op2;

}

 

long Math:: Subtract( long Op1, long Op2 )

{

return Op1 - Op2;

}

long Math:: Multiply( long Op1, long Op2 ) {

return Op1 * Op2;

}

long Math:: Divide( long Op1, long Op2 )

{

return Op1 / Op2;

}

 

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

COM-объект

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

Первым шагом будет определение для компонента интерфейса с помощью абстрактного класса такого вида:

class IMath{public: virtual long Add(long Op1, long Op2) = 0; virtual long Subtract(long Op1, long Op2) = 0; virtual long Multiply(long Op1, long Op2) = 0; virtual long Divide (long Op1, long Op2) = 0; };

 

Затем мы создадим производный класс и опишем его методы точно так же, как это делалось раньше:

class Math: public IMath{public: long Add(long Op1, long Op2); long Subtract(long Op1, long Op2); long Multiply(long Op1, long Op2); long Divide (long Op1, long Op2); };

 

Это лишь первый шаг в преобразовании класса C++ в объект, доступный для программ, написанных на других языках. СОМ-технологии, такие как OLE и ActiveX, в основном реализуются посредством интерфейсов типа рассмотренного нами ранее класса IMath. Наш новый класс является абстрактным, т.е. он содержит, по крайней мере, одну чисто виртуальную функцию и одни лишь методы (без каких-либо данных) компонентного объекта.

Начальная буква " I" в названии класса IMath отражает тот факт, что он является объявлением интерфейса. Такие обозначения используются в технологии программирования СОМ повсеместно. Класс IMath объявляет внешний интерфейс для компонента Math. Наиболее важным аспектом этого нового класса является его способность порождать виртуальную таблицу функций C++ (Vtable) в любом производном классе.

Программист никогда не взаимодействует с объектом и его данными напрямую. Для этого используются интерфейсы объектов.

 

СОМ-интерфейс

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

Реализация интерфейса (interface implementation) – это код, который программист создает для выполнения действий, оговоренных в определении интерфейса. Реализации интерфейсов, помещенные в COM-библиотеки или exe-модули, могут использоваться при создании объектно-ориентированных приложений. Разумеется, программист может игнорировать эти реализации и создать собственные. Интерфейсы ассоциируются с CoClass’ами. Чтобы воспользоваться реализацией функциональности интерфейса, нужно создать экземпляр объекта соответствующего класса, и запросить у этого объекта ссылку на соответствующий интерфейс.

В COM стало доброй традицией начинать названия интерфейсов с «I».

Например, для описания взаимодействия с некоторым абстрактным стеком можно определить интерфейс IStack. Этот интерфейс может содержать два метода, скажем, Push и Pop. Вызов метода Pop возвращает значения, заложенные до этого методом Push в стек, но в обратном порядке. Это определение интерфейса не говорит, как функции будут реализованы в коде. Один программист может реализовать стек как массив, а методы Push и Pop – как методы доступа к этому массиву. Другому же взбредет в голову использовать связанный список и соответствующую реализацию методов. Независимо от конкретной реализации методов, представление в памяти указателя на интерфейс IStack, и, соответственно, его использование клиентом полностью специфицируется определением интерфейса.

Простые объекты могут поддерживать только один интерфейс. Более сложные объекты, как правило, поддерживают несколько интерфейсов. Это свойство позволяет реализовать полиморфизм на уровне компонентной модели.

Слово «интерфейс» используется в COM не в том смысле, что в С++. Интерфейс в С++ ссылается на все функции, поддерживаемые классом. COM-интерфейс ссылается на предварительно оговоренную группу связанных функций, реализуемых COM-классом, но не обязательно на ВСЕ функции, поддерживаемые классом.

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

В технологии СОМ доступ к компонентам обеспечивается только с помощью указателей на виртуальные таблицы. Таким образом, прямой доступ к конкретным данным компонента становится невозможным. Внимательно изучите наш пример. Он достаточно прост, но отражает ключевую концепцию СОМ — использование виртуальных таблиц для доступа к функциональным возможностям компонента. Наконец, СОМ-интерфейс представляет собой просто указатель на указатель виртуальной таблицы (virtual table, или Vtable) C++. На рис. 1 отражено это взаимоотношение для случая компонента Math.

 

Рис. 1. Виртуальная таблица функций и СОМ-интерфейс

 

В нашем примере имеется несколько моментов, которые должны быть хорошо поняты.

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

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

3. Во многих случаях вы будете одновременно выступать в качестве производителя и потребителя СОМ-интерфейсов. Технологии ActiveX используют их очень широко. Взаимодействие между компонентами ActiveX достигается за счет интерфейсов. Запуск и согласование приложений осуществляется через интерфейсы. Фактически, СОМ-интерфейсы присутствуют везде.

 

Тип данных HRESULT

Большинство методов СОМ-интерфейса и функции API возвращают значение типа HRESULT (исключениями являются AddRef и Release). В Win32 тип данных HRESULT определяется как DWORD (32-битовое целое), а возвращаемое значение этого типа содержит информацию о результате вызова функции. Старший бит сигнализирует об успешном или ошибочном завершении работы функции, а следующие 15 битов идентифицируют тип ошибки и обеспечивают способ группировки однотипных кодов завершения; младшие 16 битов предоставляют специфическую информацию о происшедшем. Структура данных HRESULT идентична структуре значений флагов статуса, используемых функциями Win32 API.

Система разработки СОМ обеспечивает несколько макросов, помогающих узнать результат вызова метода. Макрос SUCCEEDED принимает значение TRUE при успешном вызове функции, а макрос FAILED принимает это же значение при ошибке вызова функции. Названные макросы не являются специфичными для СОМ и ActiveX, а используются повсеместно в среде Win32 и определяются в файле WINERROR.H. Возвращаемые значения в Win32 предваряются префиксом S_ в случае нормального завершения и префиксом Е_ — в случае ошибки.

Множественные интерфейсы

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

Объявление нескольких интерфейсов для одного класса C++ на первый взгляд не является трудным, но на самом деле может быть очень непростым делом. Во-первых, поскольку СОМ-интерфейсы фактически являются указателями на виртуальную таблицу функций C++, класс с множеством интерфейсов требует создания множества виртуальных таблиц. Другой причиной взаимосвязи компонентных объектов и их классов реализации интерфейса является необходимость подсчета количества обращений. Все интерфейсы СОМ-объекта должны взаимодействовать между собой в обеспечение подсчета обращений. Для каждого объекта существует только один счетчик обращений, и интерфейсы должны использовать его совместно. Эта взаимосвязь осуществляется с помощью множества интерфейсов IUnknown. Запомните: каждый СОМ-компонент должен обладать собственной реализацией интерфейса IUnknown.

В языке C++ существуют три основных способа обеспечения множества интерфейсов для СОМ-компонента:

- множественное наследование (Multiple Inheritance),

- реализации интерфейсов (Interface Implementations),

- вложенность классов C++ (C++ class nesting).

Мы сосредоточимся на одном из этих трех способов – множественном наследовании классов C++, так как именно с помощью него в активной библиотеке шаблонов (ATL) реализованы СОМ-интерфейсы. Вложенность классов C++ применяется и в библиотеках базовых классов Microsoft (MFC).

Язык C++ и множественное наследование

В примере компонента Math мы использовали один интерфейс IMath. Однако, большинство СОМ-компонентов предоставляют несколько интерфейсов. Например, предположим, что компонент Math предоставляет еще и интерфейс анализатора выражений, определенного следующим образом:

class IExpression: public IUnknown

{

public:

virtual void SetExpression(string strExpression) = 0;

virtual BOOL Validate() = 0;

virtual BOOL Evaluate() = 0;

};

 

Используя множественное наследование, мы могли бы снабдить класс Math обоими интерфейсами:

class Math: public IMath, public IExpression

{

// Реализация компонента включает

// и реализацию каждого наследуемого интерфейса

...

};

 

Единственная проблема этого подхода состоит в том, что в таком случае может возникнуть конфликт базовых интерфейсов IUnknown (так как оба класса, и IMath, и IExpression, наследуются от IUnknown), однако в данном случае ничего подобного не происходит, поскольку унаследованный класс должен " совместно использовать" реализацию интерфейса IUnknown. Важным моментом здесь является то, что СОМ-компоненты должны предоставлять несколько интерфейсов или, другими словами, несколько указателей на виртуальные таблицы. Если обеспечивать это с помощью множественного наследования, то необходимо, чтобы тип указателя данного экземпляра правильно приводился к типу указателя на виртуальную таблицу. Таким образом, метод QueryInterface для описанного выше класса будет иметь вид:

HRESULT Math:: QueryInterface(REFIID riid, void** ppv){ switch(riid) { case IID_IUnknown: case IID_IMath: // Множественное наследование требует явного приведения типов *ppv = (IMath*) this; break; case IID_IExpression: // Множественное наследование требует явного приведения типов *ppv = (IExpression*) this; break; default: return(E_NOINTERFACE); } // Возвращаем указатель нового интерфейса // и таким образом вызываем AddRef для нового указателя AddRef(); return(S_OK); }

 

Указатель на интерфейс IUnknown может быть возвращен посредством обращения к IMath или IExpression, поскольку оба эти класса содержат такой метод. Мы выберем обращение к IMath. Поддержка нескольких интерфейсов объекта представляет собой одну из наиболее привлекательных особенностей СОМ.

В COM присутствует понятие класса. Класс в COM носит название CoClass.

CoClass – это класс, поддерживающий набор методов и свойств (один или более), с помощью которых можно взаимодействовать с объектами этого класса. Такой набор методов и свойств называется интерфейсом (Interface).

Каждый CoClass имеет два глобальных уникальных идентификатора – один из них, текстовый, называется ProgID и предназначен для человека, а второй, бинарный, называется CLSID.

Глобальные уникальные идентификаторы (GUID)

В распределенных объектных или компонентных средах уникальная идентификация компонентов имеет первоочередное значение. В СОМ используются технологии, описанные в стандарте распределенных вычислительных сред (Distributed Computing Environment – DCE) и используемые для вызовов удаленных процедур (Remote Procedure Call – RPC). Стандарт описывает и такое понятие, как универсальный уникальный идентификатор (Universally Unique Identifier – UUID). UUID представляет собой 128-разрядное значение, которому гарантируется статистическая уникальность. Это достигается путем сочетания уникального сетевого адреса (48 битов) с множеством других значений. Используемый в СОМ UUID называется глобальным уникальным идентификатором (Globally Unique Identifier – GUID), но в основных чертах он полностью идентичен UUID. В СОМ идентификаторы GUID используются для идентификации классов компонента (CLSID), интерфейсов (IID), библиотек типов и категорий компонентов (CATID). Ниже приведены GUID, используемые в нашем примере компонента Math.

// {A888F560-58E4-11d0-A68A-0000837E3100}DEFINE_GUID( CLSID_Math, 0xa888f560, 0x58e4, 0x11d0, 0xa6, 0x8a, 0x0, 0x0, 0x83, 0x7e, 0x31, 0x0); // {A888F561-58E4-11d0-A68A-0000837E3100}DEFINE_GUID( IID_IMath, 0xa888f561, 0x58e4, 0x11d0, 0xa6, 0x8a, 0x0, 0x0, 0x83, 0x7e, 0x31, 0x0);

 

Макрос DEFINE_GUID создает глобальную константу, которая может быть использована в любой вашей программе, как на стороне клиента, так и на стороне сервера. Однако ее значение определяется один раз. Система программирования СОМ предоставляет множество макросов, предназначенных для облегчения работы с глобальными идентификаторами. В той точке вашей программы, в которой требуется определить GUID-структуру, необходимо перед файлом заголовков с объявлениями включить файл INITGUID.H. Вот как это выглядит на нашем примере компонента Math:

/// imath.h//// {A888F560-58E4-11d0-A68A-0000837E3100}DEFINE_GUID( CLSID_Math, 0xa888f560, 0x58e4, 0x11d0, 0xa6, 0x8a, 0x0, 0x0, 0x83, 0x7e, 0x31, 0x0); // {A888F561-58E4-11d0-A68A-0000837E3100}DEFINE_GUID( IID_IMath, 0xa888f561, 0x58e4, 0x11d0, 0xa6, 0x8a, 0x0, 0x0, 0x83, 0x7e, 0x31, 0x0); class IMath: public IUnknown{public: virtual long Add(long Op1, long Op2) = 0; virtual long Subtract(long Op1, long Op2) = 0; virtual long Multiply(long Op1, long Op2) = 0; virtual long Divide (long Op1, long Op2) = 0; }; #include " client.h" #include < initguid.h> #include " imath.h"

 

За счёт включения в программу файла INITGUID.H мы отменяем значение макроса DEFINE_GUID таким образом, что он не просто объявляет тип переменной GUID, а создает и инициализирует переменную этого типа.

В примере Math нам потребовались два GUID. Идентификатор CLSID идентифицирует сам компонент, a IID — пользовательский СОМ-интерфейс. Существует множество способов генерации GUID для компонентов.

Если вы пользуетесь утилитами среды Visual C++ AppWizard и ClassWizard или мастером объектов ATL, то GUID будут генерироваться автоматически. Программно создать их можно с помощью СОМ-функции CoCreateGuid или двух программ Visual C++. Одна из них, UUIDGEN, вызывается из командной строки, и ее можно применить при создании последовательности GUID для целого проекта. Приведенное ниже содержимое командной строки обеспечит создание списка из 50 GUID и запись их в заданный файл.

c: \msdev\bin\uuidgen -n50 > Project_Guids.txt

Для создания экземпляра объекта используется CLSID. Если имеется только ProgID CoClass’а или CLSID в строковом виде (" {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} ", где X – шестнадцатеричная цифра), то CLSID можно получить, вызвав функцию CLSIDFromString. Для случая с ProgID информация о CoClass’е должна содержаться в реестре машины, на которой производится вызов функции. В реестр информация заносится автоматически при регистрации объекта (во время процедуры инсталляции или при компиляции).

Библиотека СОМ API предоставляет несколько функций, предназначенных для сравнения, создания и преобразования типов GUID. Наиболее употребительные из них приведены в табл. 2.

Таблица 2. Вспомогательные функции GUID

Функция Назначение
CoCreateGuid(GUID* pGuid) Обеспечивает создание одного уникального GUID
IsEqualGUID(REFGUID, REFGUID) Сравнивает два GUID
IsEqualIID (REFIID, REFIID) Сравнивает два IID
IsEqualCLSID(REFCLSID, REFCLSID) Сравнивает два CLSID
CLSIDFromProgID(LPCOLESTR, LPCLSID) Возвращает CLSID для заданного ProgID
ProgIDFromCLSID(REFCLSID, LPOLESTR*) Возвращает ProgID для заданного CLSID

 

Реестр

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

Информация в реестре упорядочена иерархически и имеет несколько предопределенных высокоуровневых разделов. В этой лекции наибольшее значение для нас будет иметь раздел HKEY_CLASSES_ROOT, в котором хранится информация о компонентах. Важным подразделом HKEY_CLASSES_ROOT является CLSID (идентификаторы классов), в котором описывается каждый компонент, установленный в системе. Например, компонент Math, который мы создали, нуждается для своей работы в нескольких элементах реестра. Перечислим их:

HKEY_CLASSES_ROOT\Math.Component.1 = Chapter 6 Math ComponentHKEY_CLASSES_ROOT\Math.Component.1\CurVer = Math.Component.1HKEY_CLASSES_ROOT\Math.Component.1\CLSID = {A888F560-58E4-11d0-A68A-0000837E3100} HKEY_CLASSES_ROOT\CLSID\{A888F560-58E4-11d0-A68A-0000837E3100} = Chapter 6 Math Component HKEY_CLASSES_ROOT\CLSID\{A888F560-58E4-11d0-A68A-0000837E3100}\ProgID = Math.Component.1 HKEY_CLASSES_ROOT\CLSID\{A888F560-58E4-11d0-A68A-0000837E3100}\VersionIndependentProgID = Math.Component HKEY_CLASSES_ROOT\CLSID\{A888F560-58E4-11d0-A68A-0000837E3100}\InprocServer32 = c: \book\chap6\server\debug\server.dll HKEY_CLASSES_ROOT\CLSID\{A888F560-58E4-11d0-A68A-0000837E3100}\NotInsertable

 

В первых трех строках создается программный идентификатор (ProgID) для компонента Math. Идентификатор класса CLSID компонента является его уникальным идентификатором, однако он очень неудобен для чтения и запоминания. Понятие ProgID включено в СОМ для облегчения взаимодействия с компонентами разработчиков. Более подробно этот аспект будет рассмотрен в следующем разделе данной лекции. В третьей строке обеспечивается непосредственная связь между ProgID нашего элемента управления и соответствующим CLSID.

В последних строках рассматриваемого фрагмента кода содержится вся информация, необходимая СОМ для помещения компонентов на хранение.

Между ProgID и информацией о версии компонента существует взаимосвязь. Однако наиболее важным элементом является раздел InProcServer32, который описывает точное положение хранилища компонентов. В таблице 3 основные элементы реестра описаны более подробно.

Таблица 3. Основные элементы реестра

Элемент Назначение
ProgID Задает строку ProgID для СОМ-класса. Может содержать 39 символов, в том числе и символ точки.
InProcServer32 Содержит путь и имя 32-разрядного DLL-файла. Наличие пути необязательно, но если он не указан, то загрузка компонента возможна только в случае размещения его в одном из каталогов команд Windows (задается переменной среды PATH). Понятие внутризадачный сервер будет рассмотрен немного позже.
LocalServer32 Содержит путь и имя 32-битового ЕХЕ-файла. Понятие локальный сервер будет рассмотрен немного позже.
CurVer ProgID последней версии класса компонента.

 

Хорошим средством просмотра реестра с точки зрения СОМ является утилита OLEVIEW, предоставляемая Visual C++ и средой SDK. Она обеспечивает несколько различных подходов к использованию компонентов в вашей системе, а также обладает множеством других полезных свойств.

Перевести CLSID, IID или любой другой GUID в строку можно с помощью функции StringFromGUID2. Как уже говорилось выше, практически все необходимые GUID генерируются автоматически, но при необходимости можно сгенерировать GUID вручную, с помощью утилиты guidgen.

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

Dim objMath As ObjectSet objMath = CreateObject(" Math.Component" )objMath.Add(100, 100)Set objMath = Nothing

 

Функция Visual Basic CreateObject в качестве параметра принимает ProgID компонента. На самом деле для преобразования ProgID в действительный CLSID компонента оператор использует СОМ-функцию CLSIDFromProgID. А затем уже CreateObject создает экземпляр компонента с помощью функции CoCreateInstance.

 

Экземпляр СОМ-объекта

Чтобы воспользоваться функциональностью COM-объекта, нужно создать его экземпляр (instance). Экземпляр COM-объекта аналогичен объекту в C++ или VB, за тем исключением, что он может быть создан в другом процессе или на другом компьютере.

Для создания экземпляра COM-объекта на C++ применяются функции CoCreateInstance, CoCreateInstanceEx, CoGetObject, CoGetClassObject, CoGetInstanceFromFile, CoGetInstanceFromIStorage, OleLoadFromStream и некоторые другие. На VB все немного проще. Там есть две универсальные функции, CreateObject и GetObject, и оператор new. Все объекты VB являются COM-объектами.

Чаще всего применяются функции CoCreateInstance, CoCreateInstanceEx, CreateObject и оператор new.

Чтобы создать экземпляр объекта с помощью CoCreateInstance, этой функции необходимо передать: CLSID требуемого объекта, контекст создаваемого объекта, IID требующегося интерфейса, и указатель, в который и будет возвращен указатель на интерфейс созданного объекта.

Контекст создаваемого объекта – это информация о том, где должен создаваться объект: в том же процессе (адресном пространстве EXE-модуля), в другом процессе того же компьютера, на удаленном сервере, или как локальная заглушка для удаленного объекта.

Функция CoCreateInstance была создана на заре существования COM-модели и предназначена для локального COM. Она не позволяет создавать объекты на конкретном удаленном сервере, вместо этого она берет информацию о сервере из реестра. Информацию о местонахождении сервера и атрибуты защиты можно настроить с помощью утилиты DCOMCNFG или средств администрирования MTS или COM+. К недостаткам CoCreateInstance можно отнести также то, что при ее использовании нет возможности задать учетную запись (и пароль), от имени которой будет создаваться объект, и то, что она позволяет получить указатель только на один интерфейс создаваемого объекта. Для локально создаваемого объекта эти ограничения не существенны – атрибуты защиты при этом не работают (имеется прямой доступ к объекту), а указатель на другой интерфейс можно молниеносно получить с помощью вызова метода IUnknown:: QueryInterface (ведь по принципам COM любой COM-интерфейс должен быть унаследован от IUnknown). Вызов же QueryInterface у удаленного объекта приводит к передаче данных по сети, что значительно медленней локального вызова.

Всех этих недостатков лишена новая версия этой функции – CoCreateInstanceEx.

Остальные функции позволяют создать объект, загрузив его состояние из разных источников (OleLoadFromStream, CoGetInstanceFromFile, CoGetInstanceFromIStorage), или создать объект с помощью моникера и строки параметра (CoGetObject).

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

Создание моникера – задача сложная, и по плечу она не каждому. Спасает то, что имеется много стандартных реализаций моникеров. Так, через них делается связывание документов в OLE, создание Queued-объектов (асинхронно работающих объектов повышенной надежности, о них речь пойдет дальше), и получение указателей на WMI-объекты, интерфейс новой технологии Windows 2000 – Active Directory. Существует интересная разновидность моникеров – URL-моникеры, которые позволяют получить указатель на объект, основываясь на URL.

 

Функции СОМ API

Фирма Microsoft поставляет множество функций Win32 API, специально предназначенных для СОМ, ActiveX и OLE. Существует более сотни функций, предназначенных для работы с СОМ, поэтому мы не в состоянии здесь рассмотреть их все. API-функции СОМ обеспечивают основу высокоуровневых сервисов, таких как OLE и ActiveX. Нужно также не забывать, что СОМ – это только группа определений интерфейсов, которые должны быть реализованы пользователем, а вызовы API всего лишь дают возможность сделать это. В табл. 4 приведены API-функции, которые будут упомянуты в этой лекции.

Таблица 4. Основные функции СОМ


Поделиться:



Популярное:

  1. VI. В зависимости от объекта международно-правового регулирования
  2. Аварии на химико-технологических объектах: характеристика разрушительного воздействия, типовая модель развития аварии, поражающие факторы.
  3. Анализ пожарной опасности объекта
  4. Виды потерь углеводородов на объектах трубопроводного транспорта и их отрицательное экономическое и экологическое воздействие
  5. Внесение сведений о ранее учтенных объектах недвижимости.
  6. Вопрос 34 Определение радиационно-опасного объекта. Основные радиационные источники. Классификации аварий на РОО
  7. Диалектика субъекта и объекта в познавательной и практической деятельности человека.
  8. ЗНАКИ БЕЗОПАСНОСТИ НА ОБЪЕКТАХ ЖЕЛЕЗНОДОРОЖНОГО ТРАНСПОРТА
  9. Изменение положение объекта относительно текста
  10. Использование итераторов для перебора элементов объекта-вектора
  11. Количественное и качественное описание Объекта оценки
  12. Краткая характеристика объекта


Последнее изменение этой страницы: 2016-04-11; Просмотров: 2379; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.075 с.)
Главная | Случайная страница | Обратная связь