Скачиваний:
100
Добавлен:
01.05.2014
Размер:
1.56 Mб
Скачать

Технология COM

  1. Назначение и принципы COM технологии.

    1. Проблемы, решаемые с помощью COM технологии.

    2. Основные понятия.

    3. Именование COM-объектов.

    4. Понятие интерфейса.

    5. Основы компиляции.

    6. Простейший пример использования.

    7. Интерфейс IUnknown.

    8. Еще один пример.

    9. COM-сервер.

    10. Создание "настоящего" COM-сервера.

    11. Фабрика классов.

    12. Использование фабрики классов.

    13. ITypeLib, ITypeInfo. Библиотеки типов. Информация о методах сервера. Язык IDL.

    14. IDispatch. Вызов методов "по имени".

    15. IMarshall, маршалинг и взаимодействие клиента с внутренними, локальными и удаленными серверами.

  2. Технология OLE.

    1. Внедрение и связывание объектов - OLE

    2. Использование OLE-документов в приложениях

    3. Использование свойств OleContainer.

  3. Создание элементов управления ActiveX.

    1. Понятие ActiveX.

    2. Создание элементов управления ActiveX на основе VCL-компонентов.

    3. Создание страниц свойств.

    4. Создание активных форм.

  4. Создание локальных серверов и контроллеров автоматизации.

    1. Понятие автоматизации.

    2. Создание приложения, подлежащего автоматизации

    3. Превращение приложения в сервер автоматизации.

    4. Библиотека типов.

    5. Реализация методов объекта автоматизации.

    6. Тестирование сервера автоматизации.

    7. Создание контроллеров автоматизации.

    8. Создание коллекций объектов.

    9. Экспонируемые свойства и методы

  5. Процессы в Windows

  6. Создание внутренних серверов и контроллеров автоматизации.

    1. Внутренний сервер автоматизации и передача данных.

    2. Работа внутреннего сервера автоматизации в многопоточном режиме.

  7. Применение COM-объектов, входящих в состав Windows.

    1. Создание ярлыков.

    2. Использование Internet Explorer в приложениях

Проблемы, решаемые с помощью технологии com

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

Конечно, такая технология не является новой и называется "динамическая загрузка", она давно известна и её преимущества очевидны. А модули, которые позволяют загружать себя таким образом, называются DLL. И в системе, именуемойMicrosoft Windowsтакая технология известна от самого её рождения... АDLLи есть тот самый "двоичный исполняемый модуль", который может быть присоединен к программе лишь на стадии её выполнения.

Однако, если просто весь проект распределить по нескольким динамическим библиотекам, то "двоичные компоненты" не получатся? Действительно, важнейший признак "компонентности" уже появится - исполняемую программу можно будет собирать из отдельных частей без операций сборки модуля. Но вот DLL- не компонента,DLLесть, если можно так выразиться, только "место обитания компонент" используемых в программе. Ведь из программы-то вызываются вполне конкретные процедуры и функции, которыетолько расположенывDLL. Кроме того, вызовы процедур "из своего модуля" и "изDLL" - не одинаковые действия. Вызов процедуры, которая располагается внутри "своего" модуля требует знания только имени этой процедуры, а если процедура располагается вDLL, то нужно знать ещё и имя самой библиотеки. Модель жеCOM позволяет этого "не знать", т.е. вызов объектовCOMиз своей программы осуществляется без знания того, где они расположены. Достаточно знать имя объекта.

Другое отличие COM, уже от привычных объектов в стиле объектно-ориентированного программирования (ООП), состоит в том, что объектыООПизвестны только компилятору. Это - абстракции, в которых мыслит программист и которые компилятор превращает в двоичные структуры "данные + код". ОбъектыООПсуществующие в разных единицах компиляции и, тем более, помещенные в разные двоичные модули, ничего не могут друг о друге "знать" просто потому, что их там нет и никогда не было. Не случайно заголовочные файлы, содержащие описания всех объектов проекта, подаются на вход именно компилятора - потом они уже никому не нужны. Объекты жеCOM- действительно существуют в двоичном виде как объекты. И в таком качестве известны всем, кто испытывает в них нужду.

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

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

На первый взгляд эта проблема решается достаточно просто, по крайней мере когда в качестве другого модуля используется динамически загружаемая библиотека - DLL. В этом случае оба модуля содержатся в одном и том же адресном пространстве. Казалось бы, создадим вDLLобъект, вызовем его методы из основного приложения - и данная задача решена. Однако это не так. Если использовать традиционное объектно-ориентированное программирование, то нельзя создать объект в одном модуле, а вызывать его методы в другом.

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

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

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

Следующая проблема возникает при передаче данных от одного приложения к другому - например, через двоичный файл. Предположим, имеются два приложения - одно написано на языке Фортран, другое - на Delphi. И в Фортране, и в Delphi имеются двухбайтовые целочисленные переменные со знаком и динамическим диапазоном -32768+32767. На первый взгляд для передачи данных достаточно считать данные из двоичного файла, созданного одним приложением, в другое приложение. Но при выполнении такой операции можно обнаружить, что данные оказываются искаженными. Причина заключается в различном представлении переменных в этих двух языках программирования. В Delphi битовое представление числа -1 выглядит следующим образом: 1000000000000001, а в Фортране 1111111111111110 (not 1). Эту проблему можно сформулировать так: в различных языках программирования допускается различное представление одних и тех же данных. Соответственно они по-разному обрабатываются. При сложении двух целых чисел компилятор Delphi генерирует команду процессора ADD, а компилятор Фортрана -AND.

Можно выделить еще одну проблему, которая встречается в традиционном программировании. Взаимодействие двух приложений подразумевает, что они выполняются одновременно. Это означает, что одно из приложений должно запустить другое или потребовать у пользователя запуск другого приложения. Эта ситуация прекрасно наблюдается при использовании обмена данными с помощью протокола DDE(Dynamic Data Exchange). Пользователь обязательно должен запуститьDDE-сервер вручную - иначе клиентское приложение не сможет работать. Это требует дополнительных операций и вызывает естественную негативную реакцию пользователя, что отрицательно сказывается на маркетинге приложений, являющихся клиентамиDDE. Все эти проблемы решаются с помощьюСОМ-технологии. Проблемы вызова методов объектов, освобождения и резервирования памяти, унифицированного представления данных решаются с помощью интерфейсов. Проблема предоставления среде разработки информации о названиях методов объектов и списков формальных параметров решается при помощи библиотек типов. Проблема передачи указателя из адресного пространства одного приложения в адресное пространство другого приложения решается с помощью маршрутизации. Маршалинг используется и для работы с объектами, созданными на других компьютерах. И наконец, проблему автоматического запуска сервера решает использование фабрики класса и ее регистрация в системном реестре.

COM-объект - это объект, который доступен так же, как и "локальный" объект данного проекта, хотя, фактически, он не располагается в данном проекте, а есть уже готовый двоичный исполняемый ресурс, который может располагаться где угодно. Обычно это - некаяDLL. Суровая правда состоит в том, что объектCOMможет располагаться действительно где угодно. ИDLL- не единственная форма его существования.COM-объект может жить и внутриEXE-модуля, который может исполняться независимо (параллельно!) от модуля, который использует этот объект, и даже - этот самый модуль может исполняться совсем на другом компьютере! Вы где-нибудь видели подобное? И зачем это нужно?

Начнем с ответа на второй вопрос. Зачем это нужно и, если нужно, насколько это важно? Представьте себе ситуацию - у вас есть хороший, славный, удачный алгоритм. Скажем, сортировка или "вычисление средней температуры по больничной палате". Вообще говоря, этот алгоритм появился не как самостоятельная сущность, а в процессе разработки какой-то большой программы мониторинга этой средней температуры. Заказ был именно на неё, и работать эта программа должна была на компьютере дежурной медсестры. Только вот в процессе работы над этой программой выяснилось, что существует и значительно реже используемая и совсем не первоочередная задача подсчёта всевозможнейшей статистики, которая, может быть, будет отдана вам на реализацию позднее. А может быть - и не будет отдана. Во всяком случае, такую возможность вы видите, и при подсчёте этой самой статистики вы будете использовать тот же алгоритм. Ваши возможные действия? Оформить библиотечной процедурой? Дело хорошее, но в расчёте той статистики используются не только ваша программа, но и программы других разработчиков. И они - мыслят так же. Сколько отдельных библиотек они создадут? Сколько при этом образуется независимых "единиц поддержки"? И как будет жить тот, кто в этих условиях будет писать статистику? Вот если бы у вас была возможность объявить свою, находящуюся не в библиотеке, а прямо в исполняемом модуле, процедуру доступной для вызова из другого исполняемого модуля, то вы бы убили сразу двух зайцев: 1) вам не нужно поддерживать два файла вместо одного; 2) вам не нужно как-то специально тестировать вашу библиотеку. Есть еще и третье обстоятельство - эту процедуру из вашего модуля "не выковырять", и, если у вас есть какие-то алгоритмы, составляющие ваше know how, то вам не нужно их помещать в значительно более беззащитную объектную библиотеку, которая, к тому же, может распространяться отдельно от вашего модуля. И - отдельно от вашего гордого имени тоже.

Вместо всего этого кошмара вы просто объявляете COM-объект, находящийся внутри вашего исполняемого модуля. Объявляете как его вызвать - и всё. Более того, если компьютер статистика соединен с компьютером медсестры сетью, то - то статистику даже не нужно иметь ваш модуль на своей машине - он сможет его запустить (и получить доступ к функциональности вашегоCOM-объекта) на машине медсестры со своей машины. Если вы с уважением относитесь к авторскому праву, то знаете, что программы не продаются (ввиду очевидной глупости такого подхода), а лицензируются для использования. Платить приходится, фактически, по числу процессоров, которые могут исполнять программу. Запуск на машине медсестры не нарушает лицензионного соглашения, а запуск второй копии на машине статистика - нарушает его. Эта особенность программы становится выгодной, если программа, содержащая не часто используемую функцию, стоит дорого. Конечно, для вас обстоятельство, понуждающее клиента купить вашу программу еще раз, - выгодно. Но, подумайте, были бы вы в том же лагере, если бы уже вы писали бы ту же статистику с использованием функций из чужих программ?

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

В этом - пожалуй, самое большое преимущество COM. Вы знаете, что практически никогда не встречается случай, когда бы ваша программа в момент ее окончания была бы именно тем, что вы представляли себе, когда начинали ее писать. Изменения технического задания, переделки во внутренней конструкции, изменение требований заказчика - да мало ли что может произойти, почему вдруг вашей программе понадобилось стать другой. Если вы работаете над большим проектом, то в какой-то момент времени это становится проклятием - вы не можете изменить что-то без того, чтобы не "поплыло" что-то другое. Если же ваш проект делается как "грамотныйCOM", то фактически, вы разбиваете его на много согласованно работающих, но самостоятельных частей. Причем - несущественно, работают ли эти части на одной машине или на нескольких... Конечно, и здесь не все так просто, но переконфигурирование безусловно проще переписывания и последующего полнообъёмного тестирования. Что делаетCOMочень удобной архитектурной платформой для проектов, масштаб которых заранее не очень понятен и впоследствии может измениться.

Кроме того, поскольку сопрягаются двоичные объекты, - не все ли равно на каком языке эти объекты написаны?! Кроссплатформенная совместимость - бич Божий, кроме обмена примитивными типами и вызова примитивных процедур, как правило, двинуться не удается - не знает компилятор PascalилиVisual Basicкак вызывать класс из модуля, написанного наC++. А что такоеCOM-объект - все они прекрасно знают. Более того, пользователиVBмогут с удовлетворением отметить, что все идентификаторы, которые они с любовью разделяют в тексте точками, обозначая цепочечную ссылку, фактически являютсяCOM-объектами. Т.е. для того, чтобы в обиходVBввести "свой" объект его нужно сделатьCOM-объектом. И - всё.

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

Ну просто не может быть, чтобы в такой бочке мёда не было хотя бы маленькой ложки дёгтя! И дёготь действительно есть...

Во-первых, технология COM- сложная технология. Сложная как в концепции, так и в реализации. Она - намного сложнее, чем технологияС++, реализуемая компилятором. Эта сложность не должна пугать - к настоящему времени разработано достаточное количество инструментов и средств разработки, которые позволяют "легко писать" и "легко использовать"COM-компоненты. Но эта сложность есть. На её преодоление тратятся ресурсы компьютера во время выполнения, а слабо понимающий концепцииCOMпрограммист, несмотря на все эти редакторы, не сможет создать что-то приемлемо работающее, большее, чем примитивный пример. К счастью, это стандартная проблема - умение программировать есть не умение писать код, а только умение мыслить соответствующими категориями и конструкциями. И наVBможно написать плохо работающую программу, хотя наC++сделать это значительно легче :). Никакая технология не в состоянии предложить приемлемого решения этой проблемы - технические средства могут только избавить от рутины, но не от необходимости думать и понимать.

Во-вторых, технология COM- замкнутая технология. Её решения применимы пока только на платформеMicrosoft. Нельзя сказать, что другие платформы не предлагают ничего подобного, но это - другие, несовместимые на двоичном уровне сCOMтехнологии.

В-третьих, технология COM- неполна. Неполна в том смысле, что она разрабатывалась "снизу", как средство "склеивания модулей в единую конструкцию". И до полноценного проектирования распределенных приложений она пока еще не добралась. Так что для тех, кого интересует действительно изначально кроссплатформенное распределённое приложение, больше подойдет технологияCORBA, которая как раз для этих целей и разрабатывалась "сверху".

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

Кстати, нужно где-то сказать и о том, что COMимеет большое множество ассоциированных с собой аббревиатур, технологий и торговых марок. То, что мы сейчас называемCOMв момент своего рождения называлось совсем по другому,OLE-Object Linking Embedding- встраивание и связывание объектов. (что, после небольшой стилистической правки, соответствующей русскому языку, вполне можно перевести какПиВО- привязывание и встраивание объектов)

"Чистая OLE" породила технологиюOLE Automation- автоматизацию, а затем изOLEконцептуально выкристаллизовалась технология самого нижнего уровня -COM. После этогоMicrosoftпереименовалаOLEвActiveXи заявила, чтоCOMявляется не частьюOLE, а самостоятельной платформой. Платформой, на которой и располагаются все другие "компонентные" технологии. ПоэтомуActiveXявляется производной технологией, выстроенной на платформеCOM. От перемены названия суть технологий (да и большая часть кода) не изменилась -ActiveXиOLEявляются преемственными технологиями, аOLE Automationвообще осталась почти в первозданном виде.

Нужно так же сказать, что долгое время OLE/COMсуществовала только в пределах одной машины. Но в какой-то момент времени появилась (весьма для компонентной технологии естественная) возможность разместить клиент и сервер на разных машинах в пределах одной сети. Чтобы подчеркнуть прорывность этого шагаMicrosoftособо выделила и названиеDCOM- DistributedCOM. Ныне оно уже не актуально - в состав любой современной операционной системыMicrosoftвходят системные средства, поддерживающие что локальное, что распределённое создание объектов (ранее это был толькоoption pack).

Впоследствии Microsoftразработала на платформеCOMнабор интерфейсов для доступа к базам данных и опубликовала его под названиемOLE DB, а также предложила платформу промежуточного уровняTransaction Server - MTS. При разработке операционной системыWindows 2000(NT 5.0) средстваMTSбыли встроены в систему (ранее это был толькоoption pack), и результирующая платформа получила названиеCOM+. Это многообразие не должно сбивать с толку, все эти наименования относятся к одной и той же области понятий, база которой -COM.