Вы находитесь на странице: 1из 53

КОМПОНЕНТНОЕ

ПРОГРАММИРОВАНИЕ

COM (Component Object


Model) – модель
многокомпонентных
объектов
Наиболее распространенные схемы
повторного применения: библиотеки и
объекты.
Недостатки динамических библиотек:
 сложность расширения функциональных
возможностей
 проблема установки в системе более одной
реализации одной и той же библиотеки
 не поддерживают объектно-
ориентированный подход
Проблемы использования объектов:
 отсутствие стандартов для компоновки
двоичного кода объектов
 несовместимость языков
 необходимость перекомпиляции всех
приложений, использующих объект при его
изменении
История развития СОМ
 технология СОМ начала развиваться как
технология OLE (Object Linking and Embedding –
связывание и внедрение объектов).
 OLE появилась как одно из направлений
развития технологии обмена данными (DDE –
Dynamic Data Exchange).
 Первое воплощение OLE представляло собой
механизм создания и работы с составными
документами.
 В начале 1996 года Microsoft ввела в оборот
новый термин – ActiveX.
 Развитие технологии СОМ не остановилось,
следующим её поколением стала технология
СОМ+.
 Технология .NET
Функционирование СОМ

 Основная цель технологии СОМ –


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

 Клиент получает доступ к сервисам объекта


только через интерфейс и его методы,
непосредственного доступа к объекту у них
нет.
Функционирование СОМ

 Уже созданный интерфейс не может быть


изменен ни при каких обстоятельствах.

 Объект COM всегда реализуется внутри


некоторого сервера.

 Сервер СОМ представляет собой


исполняемый файл.
Различают три типа серверов
 внутренний сервер (in-process server)
реализуется динамическими библиотеками,
которые подключаются к приложению-
клиента и работают в одном с ним
адресном пространстве.
 локальный сервер (local server) создается
отдельным процессом, который работает на
одном компьютере с клиентом.
 удаленный сервер (remote server) создается
процессом, который работает на другом
компьютере по отношению к клиенту.
 Для обеспечения работы локальных и
удаленных серверов используется механизм
маршалинга и демаршалинга. Маршалинг
реализует единый в рамках СОМ формат
упаковки параметров запроса, демаршалинг
отвечает за распаковку.

 Чтобы вызывать методы интерфейса объекта


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

 Любой объект СОМ является экземпляром


некоторого класса. Информация обо всех
зарегистрированных и доступных в данной
операционной системе классах СОМ собрана в
специальной библиотеке СОМ .
Схема работы с COM
1. Сначала клиент обращается к библиотеке
СОМ, передавая ей имя требуемого класса и
необходимого в первую очередь интерфейса
2. Библиотека при помощи диспетчера
управления службами (SCM – Service Control
Manager) обращается к системному реестру,
по идентификатору класса находит
информацию о сервере и запускает его
3. Сервер создает экземпляр класса – объект и
возвращает библиотеке указатель на
запрошенный интерфейс
4. После этого библиотека возвращает
клиенту указатели на объект и интерфейс
Объект COM

Каждый объект представляет собой


экземпляр соответствующего класса и
содержит один или несколько интерфейсов.

Объект имеет три основные характеристики:


 инкапсуляция
 наследование
 полиморфизм
Различают два способа наследования
 Наследование реализации - передача
родителем потомку всего программного кода.

 Наследование интерфейса - передача только


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

Также применяется механизм агрегирования,


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

 программист обязуется реализовать все


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

Для идентификации каждый интерфейс имеет


два атрибута:
 имя
 глобальный уникальный идентификатор (GUID)
Интерфейс IUnknown
Каждый объект СОМ обязательно имеет
интерфейс IUnknown. Он содержит три
метода:
 QueryInterface
 AddRef
 Release
 Метод QueryInterface возвращает указатель
на интерфейс объекта, идентификатор IID
которого передаётся в параметре метода.
Если такого интерфейса объект не имеет,
метод возвращает Null.
 AddRef и Release – механизм учёта ссылок.
Интерфейс IDispatch
IDispatch — это интерфейс
автоматизации для контроллеров, не
использующих интерфейсы СОМ
напрямую
При доступе к объекту через интерфейс
IDispatch применяется отложенное
связывание – реальный доступ
происходит во время выполнения
Методы IDispatch
 GetIDsOfNames – отображает имя одного члена
класса и, по желанию, набор имен аргументов в
соответствующий набор целых
идентификаторов связи, которые затем можно
использовать в вызовах метода Invoke
 GetTypeInfo – извлекает информацию о типах
объекта
 GetTypeInfoCount – извлекает информацию о
типах, предоставляемых объектом (возвращает
0, если информации о типах нет, и 1 – если есть)
 Invoke – предоставляет доступ к свойствам и
методам объекта
 Во время выполнения клиент передает строку с
именем свойства (метода), которое он хочет
вызвать, методу IDispatch.GetIDsOfNames
 Если данное свойство (метод) объекта существует,
клиент получает идентификатор соответствующей
функции
 Затем его можно использовать для фактического
вызова свойства (метода) средствами метода
IDispatch.Invoke
 Методы GetTypeInfoCount и GetTypeInfo позволяют
получать из библиотеки типов компонента
информацию об интерфейсах, методах и свойствах,
которые он поддерживает
Распределенная модель
многокомпонентных объектов
• Распределённая модель многокомпонентных
объектов (Distributed Component Object Model,
DCOM) – это протокол, обеспечивающий гибкое,
защищённое и эффективное взаимодействие
программных компонентов в сетевой среде
• Когда клиент и компонент хранятся на разных
машинах, DCOM просто заменяет локальный
механизм взаимодействия процессов сетевым
протоколом. Ни клиент, ни компонент не знают
о том, что соединение между ними стало
гораздо длиннее
Технологии ActiveX
• ActiveX – это основанная на СОМ технология,
предоставляющая в распоряжение разработчика
базовые строительные блоки для создания
Windows-приложений
• Поддерживая нужные СОМ-объекты, каждый с
собственным набором интерфейсов, независимые
приложения могут совместно работать, чтобы
пользователь получил один составной документ.
• Компоненты ActiveX можно реализовать на
многих языках программирования
 
Технологии ActiveX

Элементы управления ActiveX – это


объекты, допускающие повторное
использование и содержащие
визуальные элементы и код
Они применяются в контейнерах и
служат для организации или
обогащения средств взаимодействия
пользователя с приложением
Элементы управления ActiveX можно
встраивать в Web-страницы, но область
их применения не ограничена
Интернетом
OLE (Object Linking and Embedding) —
это механизм, дающий возможность
вставить в приложение документ,
подготовленный в другом приложении .
Когда вы вставляете таблицу Excel в
документ Word, вы пользуетесь механизмом
OLE.
Приложение, в которое можно вставить
данные из другого приложения,
называется клиентом OLE,
а приложение-поставщик данных —
сервером OLE.
OLE автоматизация

Сервер автоматизации представляет


собой программу, которая может
управляться внешней программой —
контроллером автоматизации.
Сервером может быть Word или Excel, а
контроллер разрабатывается
программистом.
Механизм OLE может действовать двумя
способами:

Внедрение (embedding).
Внедренный объект становится частью того
документа, в который он вставляется.

Связывание (linking).
Связанный объект в приложении представляет
собой не сам документ, а только ссылку на
него.
Преимуществом связывания является то, что к
документу могут иметь доступ несколько
приложений одновременно.
Если одно приложение изменит документ,
изменения будут учтены также во всех других
приложениях, с которыми связан файл
документа.
Сервера автоматизации

Доступ к COM серверам Microsoft


Office
Приложения и объекты MS
Office

Приложения Office поставляют сервера COM,


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

Приложение MSOffice рассматривается как


совокупность объектов со своими методами,
свойствами, событиями, которые обеспечивают
скелет приложения.
Программист Office является не создателем
приложения, а он принимает участие в создании
системы документов.
Таким образом, ДОКУМЕНТ, а не программа
являются целью разработки.
Объектная модель приложений
MS Office

В объектной модели Оffice существует и


наследование, и встраивание классов.
Всегда существует задающий приложение
корневой объект, он всегда называется
Application.
Каждое приложение Office имеет свой
собственный корневой объект –
Word.Application, Excel.Application.
Объектная модель приложений
MS Office
Объектная модель документа
Word
Объекты Application
 Фундаментальным объектом любого приложения является Application.
Рассмотрим сценарий взаимодействия через сервера автоматизации:

1) Создаем новый
проект
2) На главную форму
выкладываем
компоненту с
закладки Servers,
которая называется
WordApplication
3) Устанавливаем
свойства
компоненты
AutoConnect и
AutoQuit в True
4) Запускаем
приложение на
выполнение.
Доступ к объекту
Application
Казалось бы, ничего не произошло, запустилась форма и
отобразилась на экране, на самом деле наше приложение запустило
сервер автоматизации Microsoft Word, этот факт можно обнаружить,
запустив на выполнение Task Manager и выбрав закладку Processes.
Среди прочих процессов мы обнаруживаем WINWORD.EXE. На самом
деле была приложением проделана следующая работа:
При создании формы, в системном реестре, по идентификатору CLSID
был найден сервер Word.Application
Запущено на выполнение приложение, находящееся по адресу в
реестре (ProgID)
Сервер предоставил нашему приложению, которое и является
контроллером автоматизации интерфейс, через который мы и
получим доступ к объекту Application.
Интерфейс Idispatch унаследован от Iunknown, который в свою
очередь имеет три метода, один из которых _ADDRef умеет считать
количество клиентов, в настоящий момент использующих сервер. Как
только от сервера отсоединиться последний клиент, он
автоматически будет выгружен из памяти компьютера.
Технология OLE Automation
(автоматизация OLE).
Сервер автоматизации представляет собой программу, которая может
управляться внешней программой — контроллером автоматизации.
Сервером в данном случае является Word или Excel, а контроллер
разрабатывается программистом.
Отличие технолгии OLE Automation в том, что она позволяет
использовать возможности СОМ не только языкам-компиляторам, но и
интерпретаторам, и обеспечивает связь с вызываемыми методами на
стадии выполнения приложения. Такой способ вызова называется
поздним связыванием. Методы при таком способе вызова
выполняются медленнее, причем заранее нельзя проверить
правильность написания объектов и их методов.
Преимуществом такого метода является независимость выбора среды
разработки от объекта, который нужно программировать.
Среда Delphi поддерживает вызовы методов серверов автоматизации.
Для этого используются переменные типа Variant, которые содержат
ссылки на объекты автоматизации. На этапе выполнения программы
серверу автоматизации передается команда в виде строки,
предварительно записанной в переменную типа Variant.
Доступ к объекту
Application
var
wd: OleVariant;
Пример 2
fileName: string;
begin
try
fileName := ExtractFilePath(Application.EXEName) + 'report.DOC';
//Создаем объект интерфейса для доступа к серверу COM
wd := CreateOleObject('Word.Application');
//Проверка наличия методов и правильность передачи параметров
//будет осуществляться на стадии выполнения приложения
wd.application.documents.add;
wd.application.activedocument.range.insertAfter(now);
wd.application.activedocument.saveas(fileName);
//выгружаем сервер из памяти компьютера
wd.application.quit(true, 0);
Except
End;
Интерфейс IDispatch
Интерфейс IDispatch описывается в модуле System
следующим образом:
type
IDispatch = interface(IUnknown)
['{00020400-0000-0000-C000-000000000046}']
function GetTypeInfoCount(out Count: Integer): Integer; stdcall;
function GetTypeInfo(Index, LocaleID: Integer; out TypeInfo):
Integer; stdcall;
function GetIDsOfNames(const IID: TGUID; Names: Pointer;
NameCount, LocaleID; Integer; DispIDs: Pointer): Integer;
stdcall;
function Invoke(DispID: Integer; const IID: TGUID; LocaleID:
Integer; Flags: Word; var Params; VarResult, ExcepInfo, ArgErr:
Pointer): Integer;
end;
Интерфейс IDispatch
Центральным элементом технологии OLE Automation является

интерфейс IDispatch. Ключевыми методами этого интерфейса
являются методы GetIdsOfNames и Invoke, которые позволяют
клиенту запросить у сервера, поддерживает ли он метод с
указанным именем, а затем, если метод поддерживается –
вызвать его.
Когда клиенту требуется вызвать метод, он вызывает
GetIdsOfNames, передавая ему имя запрошенного метода. Если
сервер поддерживает такой метод, он возвращает его
идентификатор – целое число, уникальное для каждого метода.
После этого клиент упаковывает параметры в массив переменных
типа OleVariant и вызывает Invoke, передавая ему массив
параметров и идентификатор метода. Таким образом, все, что
должен знать клиент – это строковое имя метода. Такой алгоритм
позволяет работать с наследниками IDispatch из скриптовых
языков.
Методы GetTypeInfo и GetTypeInfoCount являются
вспомогательными и обеспечивают поддержку библиотеки типов
объекта. Реализация методов GetIdsOfNames и Invoke,
предоставляемая COM по умолчанию базируется на библиотеке
типов объекта.
Dispinterface
Dispinterface  
Dispinterface – это декларация методов, доступных через
интерфейс IDispatch. Объявляется он следующим образом:
type
  IMyDisp = dispinterface
    ['{EE05DFE2-5549-11D0-9EA9-0020AF3D82DA}']
    property Count: Integer dispid 1
    procedure Clear dispid 2; 
  end;
Самих методов может физически и не существовать
(например, они реализуются динамически в Invoke).
Пример DispInterface
Рассмотрим использование dispinterface на простом примере. Объявим диспинтерфейс объекта
InternetExplorer и используем его в своей программе:

type
  IIE = dispinterface
  ['{0002DF05-0000-0000-C000-000000000046}']
    property Visible: WordBool dispid 402;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  II: IIE;
begin
  II := CreateOleObject('InternetExplorer.Application') as IIE;
  II.Visible := TRUE;
end;

Эта программа успешно компилируется и работает, несмотря на


то, что в интерфейсе объявлено только одно из множества
имеющихся свойств и методов. Это возможно благодаря тому, что
Delphi не вызывает методы диспинтерфейса напрямую и, поэтому,
не требует полного описания всех методов в правильном порядке.
Dual интерфейс
Идея двойных интерфейсов очень проста. Сервер реализует
одновременно некоторый интерфейс, оформленный по стандартам COM
(VTable) и диспинтерфейс, доступный через IDispatch. При этом
интерфейс VTable должен быть унаследован от IDispatch и иметь
идентичный с диспинтерфейсом набор методов. Такое оформление
сервера позволяет клиентам работать с ним наиболее удобным для
каждого клиента образом. Клиенты, использующие VTable вызывают
методы интерфейса напрямую, а клиенты, использубщие позднее
связывание – через методы IDispatch. Большинство OLE-серверов
реализуют двойной интерфейс.
Технология Automation, ранее известная как OLE Automation, дает
совершенно другой способ вызова клиентом методов, экспонируемых
сервером, чем тот стандартный для СОМ способ, который мы уже
рассмотрели. Automation же использует стандартный СОМ-интерфейс
IDispatch для доступа к интерфейсам. Поэтому говорят, что любой
объект, поддерживающий IDispatch, реализует Automation. Также
говорят о дуальном интерфейсе, имея в виду, что он может быть вызван
как с помощью естественного способа (vtable), так и с помощью
вычурного способа Automation.
Базовый класс TOLEServer
На закладке Service находится набор компонент для доступа к
серверам автоматизации, не все компоненты возвращают
ссылку на объект Application, то есть могут быть получены
интерфейсы для доступа к вложенным объектам, таким как
Документ Word или рабочая книга Excel.
Все компоненты унаследованы от класса TOLEServer, который
наследует свойства класса Tcomponent. TOLEServer является
базовым классом всех COM серверов. Кроме этого этот класс
имеет еще несколько свойств и методов для управления связью
с COM сервером.
Среди таковых уже знакомое нам свойство AutoConnect, которое
автоматически запускает COM сервер и производит извлечение
из него интерфейса, обеспечивающего связь с контроллером.
Еще одно важное свойство класса TOLEServer – ConnectKind –
указывающее тип процесса, к которому устанавливается связь.
Свойство используется методом Connect, который вызывается
автоматически, если свойство AutoConnect истинно.
Значения свойства ConnectKind
ckRunningOrNew . Контроллер производит подключение к
уже существующему процессу, или запускает новый
процесс, при отсутствии такового. Этот вид взаимодействия
между COM сервером и контроллером наиболее часто
применяется на практике. Такое значение свойства
установлено по умолчанию.
ckNewInstance. При соединении с сервером каждый раз
создается новый экземпляр
ckRunningInstance. Соединение устанавливается с уже
запущенным COM сервером. Если таковой отсутствует –
будет создан соответствующий объект ошибки, который
необходимо обработать
ckRemote. Это значение используется совместно со
свойством RemoteMachineName, если необходимо
подключиться к серверу на удаленной машине
ckAttachToInterface.При установке этого значения интерфейс
не создается и соответственно нельзя указывать значение
True для свойства AutoConnect. Соединение с сервером
производится с помощью метода ConnectTo
Подключение к существующему
интерфейсу
При необходимости подключения к проекту таких компонентов,
как WordDocument или WordParagraphFormat производится
подключение к уже существующему интерфейсу не создавая его
заново. Также это может быть необходимо, когда контроллер
должен отслеживать события, происходящие в COM сервере.
Подключение к существующему
интерфейсу
procedure TForm1.WordApplication1DocumentChange(Sender: TObject);
begin
//производим подключение к текущему документу
WordDocument1.ConnectTo( WordApplication1.ActiveDocument);
//Контроллер добавляет новую строку в текущий документ
WordDocument1.Range.InsertAfter(#13+'Переход к
документу'+#13+
WordApplication1.ActiveDocument.Get_FullName+' произведен :'+
DateTimeToStr(Now));
end;

procedure TForm1.FormCreate(Sender: TObject);


begin
//COM сервер отображает себя на экране Пример 3
WordApplication1.Visible:=true;
end;
Классы – наследники ToleObject
TOleServer = class(TComponent, IUnknown)
TWordApplication = class(TOleServer)  
Благодаря такому объявлению, класс TwordApplication наследует свойства
и методы класса Tcomponent (способен устанавливаться на палитре
компонент и прочие…), а так же знает все о доступе к интерфейсам COM
серверов, благодаря наследованию интерфейса IUNknown. В библиотеке
типов прописаны все доступные методы и свойсва COM сервера. Когда
создается контроллер автоматизации, то приложение получает доступ к
Dual Interface описанный в библиотеке типов. Dual интерфейс – есть
совокупность пользовательского интерфейса, описанного в библиотеке
типов и dispinterface, который доступен в момент выполнения
приложения. Это реализовано с помощью COM VTABLE интерфейса,
унаследованного от IDISPATCH. Использование Vtable интерфейса имеет
ряд преимуществ:
1) Передаваемые параметры, их типы и количество проверяется на
стадии проектирования и редактор кода сопровождает разработчика
всевозможными хинтами и подсказками.
2) Через Vtable интерфейс осуществляется значительно более быстрый
доступ к серверу автоматизации, чем через DispInterface
В то же время, не всегда разработчик получает доступ к библиотеке
типов и соответственно к V – таблице, поэтому приходится иногда
пользоваться Idispatch интерфейсом
Доступ к функциям Ms
Excel
Тестовый проект
Позднее связывание (OLE)
procedure TMainForm.BtExcelOLEClick(Sender: TObject);
Var i,j : integer;
ExcelApplication:Variant;
begin
Application.Minimize;
try
ExcelApplication:=CreateOleObject('Excel.Application');
ExcelApplication.visible:=true;
ExcelApplication.WorkBooks.Add;
except ShowMessage('Ошибка инициализации Excel'); exit; end;
for i:=0 to SG.ColCount-1 do
for j:=0 to SG.RowCount-1 do
ExcelApplication.Cells[j+1,i+1].value:=SG.Cells[i,j];
Application.Restore;
ShowMessage('Экспорт завершен');
end;
Связывание через Dual интерфейс
procedure TMainForm.BtExcelServersClick(Sender: TObject);
var
WorkBk : _WorkBook; // определяем WorkBook
WorkSheet : _WorkSheet; // определяем WorkSheet
i,j : integer;
begin
XLApp.Connect; // Добавляем WorkBooks в ExcelApplication
XLApp.WorkBooks.Add(xlWBatWorkSheet,0); // Выбираем первую WorkBook
WorkBk := XLApp.WorkBooks.Item[1]; // Определяем первый WorkSheet
WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;
for i:=0 to SG.ColCount-1 do
for j:=0 to SG.RowCount-1 do
Worksheet.Cells.Item[j+1,i+1].value:=SG.Cells[i,j];
XLApp.Visible[1]:=true;
Application.Restore;
ShowMessage('Экспорт завершен');
end;
Передача массива через Dual
интерфейс
var
WorkBk : _WorkBook; // определяем WorkBook
WorkSheet : _WorkSheet; // определяем WorkSheet
TabGrid : Variant;
i,j,r,c : integer;
begin
r:=SG.RowCount; c:=SG.RowCount; // Заполняем TabGrid
TabGrid := VarArrayCreate([0,(r-1),0,(c-1)],VarOleStr);
for i:=0 to SG.ColCount-1 do for j:=0 to SG.RowCount-1 do
TabGrid[j,i]:=SG.Cells[i,j];
XLApp.Connect; // Добавляем WorkBooks в ExcelApplication
XLApp.WorkBooks.Add(xlWBatWorkSheet,0); // Выбираем первую WorkBook
WorkBk := XLApp.WorkBooks.Item[1];
// Определяем первый WorkSheet
WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;
Worksheet.Range['A1', Worksheet.Cells.Item[R,C]].Value2 := TabGrid;
XLApp.Visible[1]:=true;
Application.Restore;
ShowMessage('Экспорт завершен');
end;
Заполнение шаблона

OleReport:
TOleContainer;
Текст процедуры
заполнения
var
WorkBk : _WorkBook; WorkSheet : _WorkSheet;
TabGrid : Variant; i,j,r,c : integer; Path : string;
begin
r:=SG.RowCount; c:=SG.RowCount; TabGrid := VarArrayCreate([0,(r-1),0,(c-
1)],VarOleStr);
for i:=0 to SG.ColCount-1 do for j:=0 to SG.RowCount-1 do
TabGrid[j,i]:=SG.Cells[i,j];
Path:=ExtractFilePath(Paramstr(0))+'shablon.xls';
XLApp.Connect;
XLApp.Workbooks.Open(Path, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam,
EmptyParam, EmptyParam, EmptyParam, EmptyParam, 0);
WorkBk:=XLApp.ActiveWorkbook;
WorkSheet := WorkBk.WorkSheets.Get_Item(1) as _WorkSheet;
Worksheet.Range['B3', 'F7'].Value2 := TabGrid;
path:=ExtractFilePath(Paramstr(0))+'report.xls';
WorkBk.SaveCopyAs(path,0); WorkBk.Close(false,0,0,0);
XLApp.Disconnect; //Разрываем связь с сервером
//Отображаем полученный отчет у себя на форме.
OleReport.CreateObjectFromFile(path,false); OleReport.Visible:=true;
ShowMessage('Экспорт завершен');
end;

Вам также может понравиться