    ЧАСТЬ       V 

    Работа с OLE 

    18. Работа с OLE, серверы документов и элементы управления ActiveX 
    19. Работа с интерфейсами СОМ 
    20. Автоматизация OLE 
    21. Создание элементов управления ActiveX 

    ГЛАВА              18 

    Работа с OLE, серверы документов i и элементы управления ActiveX 

    Квентин Серефиччен 


    —— Создание контейнеров OLE 

    Контейнеры OLE времени разработки и выполнения. 

    —— Встраивание и связывание объектов 

    Способы добавления объектов OLE в контейнер. 

    —— Чтение и запись 

    Сохранение объектов OLE в файлах баз данных. 

    —— Переопределение встроенных диалоговых окон контейнера OLE 

    Пример создания собственного диалогового окна Custom Insert. 

    —— Активизирование и слияние меню 

    Управление формой с помощью объектов OLE. 

    ВВ Глаголы OLE 

    Использование глаголов OLE внутри собственных приложений. 

    —— Доступ к серверам автоматизации 

    Вызов методов серверов автоматизации. 

    —— Передача необязательных параметров 

    Позиционные и именованные ар

    О технологии OLE наслышаны многие разработчики, но не все из них понимают, 
что мощь этой технологии можно использовать в собственных приложениях. За 
последний год технология OLE воплотилась в сотнях объектов ActiveX, и Delphi 
позволяет использовать элементы управления ActiveX с той же простотой и 
легкостью, что и компоненты VCL. 
    Термин элементы управления ActiveX используется для ссылок на элементы 
управления OLE, серверы OLE и контейнеры OLE. Он укоренился в профессиональной 
лексике из-за значительного развития технологии ActiveX за прошедший год. 
Элементы управления ActiveX включают полезные свойства, которые можно 
использовать при разработке программ в Delphi. В частности, техноло1,h; гия 
контейнеров OLE используется довольно давно. В Delphi возможности контейнеров 
реализованы в классе TOleContainer. Этот класс обладает многими полезными 
свойствами и некоторые разработчики даже не знают, какими возможностями они 
обладают. В этой главе будут детально изложены методы работы с контейнерами 
OLE и элементами ActiveX. Это позволит эффективно использовать потенциал OLE. 
    В Delphi 2 класс TOleContainer значительно улучшен по сравнению с Delphi 
I. Новые улучшения этот класс получил в последней версии Delphi (Delphi 3). 
Наиболее важным усовершенствованием класса TOleContainer является поддержка 
документов тина Active Document. 

    404 

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

    Современные технологии OLE 

    С появлением новых, более мощных, компьютеров и средств программирования, 
которые облегчают создание элементов ActiveX, было создано новое поколение 
элементов управления на базе OLE. Они предоставили разработчикам довольно 
широкий спектр инструментов, использование которых повышает производительность 
и сокращает время создания приложений. Технологии OLE используются при 
разработке практически всех приложений и в ближайшем будущем также будут 
применяться для создания операционных систем. 
    В технологии OLE используется парадигма, аналогичная парадигме Delphi, — 
повторное использование кода (code reusability). Другими словами, если 
существует OLE-сервер, который выполняет некоторые функции, то в Delphi не 
нужно изобретать колесо — можно просто воспользоваться существующим сервером OLE. 
    Наиболее привлекательным преимуществом OLE является возможность 
использования методов других серверов приложений. Читатель согласится, что 
намного удобнее использовать функциональность электронных таблиц, таких как 
Excel, или текстовых процессоров, таких как Word, вместо того чтобы 
разрабатывать аналогичную функциональность в собственном приложении. 
    Delphi позволяет легко создавать элементы управления ActiveX различных 
типов. Более детально методы создания элементов ActiveX изложены в главе 21, 
"Создание элементов управления ActiveX". 
    Работать с элементами ActiveX очень просто. Для этого сначала нужно 
поместить элемент в библиотеку VCL, а затем — в форму. Далее в этой главе 
рассмотрен пример вставки элемента ActiveX в модуль (package) и способ его использования. 
    Среда программирования Delphi поставляется с набором различных элементов 
управления ActiveX. Элементы управления ОСХ сгруппированы на странице ОСХ 
палитры компонентов. На странице Win95 собраны элементы управления OLE, 
которые заключены в модули-оболочки. Кроме того, несколько элементов ActiveX 
размещено на странице Internet. Как и в случае с компонентами VCL, для 
использования перечисленных элементов ActiveX достаточно вставить их в форму. 
Между компонентами VCL и компонентами, созданными на базе OLE, есть одно 
большое различие— компоненты OLE можно использовать в любой среде и в любом 
языке программирования, т.е. в любой среде программирования, которая 
поддерживает элементы управления ActiveX. 

    Обзор технологии OLE 

    Что же такое технология OLE? В предыдущих разделах уже упоминалось об этой 
технологии, но никто не объяснил, что это такое. Изначально технология OLE 
являлась стандартом, обеспечивающим связывание и встраивание объектов (Object 
Linking and Embedding) на основе СОМ (Component Object Model). С момента 
выпуска первой версии стандарта OLE (OLE 1.0) эта технология изменилась 
настолько, что возможности связывания и встраивания объектов стали лишь 
небольшим подмножеством всех ее возможностей. Поэтому аббревиатура OLE 
употребляется только для обозначения названия технологий^а не в качестве сокращения. 
    СОМ— это спецификация API, созданная для поддержки создания СОМ-объектов. 
Такие объекты позволяют приложениям взаимодействовать в рамках структуры, 
независящей от языка программирования. Объекты, созданные на основе СОМ, во 
многом похожи на компоненты VCL, но они не обладают свойствами и событиями. 
    В будущем спецификация СОМ не будет зависеть от операционной системы и от 
платформы. Это позволит приложениям и операционным системам использовать 
коммуникации между процессами. Компания Microsoft разрабатывает новую 
операционную систему, которая полностью базируется на OLE. Поэтому в недалеком 
будущем можно ожидать появления операционной системы OLE, и нам, 
программистам, нужно освоить технологию OLE, так как большинство задач 
программирования будет решаться на основе элементов OLE. 
    Когда приложение — сервер OLE — активизируется, это происходит внутри 
контейнера, расположенного в вашем приложении. В версии OLE 1.0 при 
активизировании объекта сервер OLE запускался в отдельном окне, в котором 
располагались и данные для редактирования. Иногда такую форму активизирования 
можно встретить и в современных программах. Поскольку более новой версией OLE 
является версия 3, спецификация OLE 2.0 здесь будет опущена. 
    Визуально при активизировании сервера OLE текущие панели инструментов и 
меню заменяются панелями инструментов и меню сервера OLE или сливаются с ними. 
Кроме того, часть формы становится окном сервера OLE, так как сервер принимает 
на себя управление областью формы. Далее в этой главе представлены примеры 
RESUME. ЕХЕ и OLEDB. ЕХЕ, которые демонстрируют возможности активизирования по месту. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   405 

    ActiveX покрывает большой спектр технологий OLE. Взгляните на список всех 
элементов управления ActiveX, которые можно вставить в форму. Эти элементы 
очень быстро переходят в ранг стандартных элементов для построения приложений 
в Internet, так как элементы ActiveX обеспечивают повторное использование кода 
между различными платформами. Пример, приведенный в разделе "Использование 
элементов управления ActiveX", демонстрирует способ использования проверки 
орфографии текста в поле DBMemo. 

    Связывание и встраивание объектов OLE 

    Связыванием (linking) называют ассоциирование файла объекта OLE с 
контейнером OLE. Файл объекта никогда не сохраняется в контейнере, но 
контейнер OLE ссылается на файл. Файл объекта OLE должен быть создан до того, 
как на него можно будет ссылаться из контейнера. 
    "р! Документ Word или файл растрового изображения (BMP-файл) не является 
файлом объектов OLE — это 'И просто файл данных. Чтобы создать из документа 
файл объекта OLE, нужно указать, что сервер OLE должен -  создавать файл в 
формате объекта. 
    Одним из преимуществ связывания объектов является то, что множество 
пользователей, серверов OLE и приложенийконтейнеров могут получать доступ к 
одному документу. Следовательно, достаточно расположить данные в известном 
каталоге и обеспечить доступ к данным для всех приложений, которые эти данные 
используют. Когда данные объекта OLE изменяются, то .изменения автоматически 
отражаются во всех контейнерах, содержащих ссылки на файл этого объекта, 
включая и ваш собственный контейнер. 
    ' '"Встраивание (emEeddIng)~o6beKTOB"'—- это^ втордй..метод, используемый 
при работе с объектами OLE. При встраивании объектов реальный объект 
сохраняется в вашем приложении и другие контейнеры OLE не имеют доступа к 
этому объекту. Встроенные объекты OLE не хранятся в файлах — такиеТюъекты 
сохраняютсяГв контейнерах внутрй^приложенДГВстраивание объектов гарантирует, 
что объект не будет случайно удален, изменен или поврежден, как это случается 
при хранении объектов во внешних файлах.                    
    ТГрёймущёством"встрайвания, как говорилось выше, является хранение данных 
как части приложения, а недостатком такого способа хранения является то, что 
размер контейнера OLE вашего приложения увеличивается на размер вставленoro 
объекта. Таким образом, чем больше размер объекта, тем больше размер вашего приложения. 
    Если во время выполнения приложения в объект OLE внесены изменения и 
необходимо сохранить их до следующего запуска приложения, тос помощью метода 
SaveToFile объект OLE необходимо записать в файл. .   ^ 
    Когда же использовать встраивание и связывание? Оба способа работы с 
объектами OLE имеют свои достоинства и недостатки. Ниже приведено несколько 
аргументов, которые помогут вам выбрать, какой из способов больше подходит в 
конкретном случае. 

    Связывание или встраивание? 

    Аргументы за связывание объектов. 
    Я Необходимо, чтобы изменения в данных объекта OLE были отражены во всех 
приложениях и документах, использующих этот объект. 
    •• Файл объекта не планируется перемещать или удалять. 
    Я Объект очень большой, и вы планируете распространять его по сети или 
электронной почте. 
    в Есть ограничения на дисковое пространство. 
    Аргументы за встраивание объектов. 
    • Изменения данных объекта влияют только на один объект. 
    • Объект маленький. 
    •I Объект большой, но приложение не будет распространяться по сети или 
электронной почте. 
    • Объект не планируется модифицировать, или все изменения будут вноситься 
через единственную копию приложения — контейнера OLE. 
    •! Файл объекта может быть удален или перемещен. 
    • На диске достаточно места. 
    В следующем разделе описано несколько программ, демонстрирующих 
использование обоих способов работы с объектами OLE. 

    406                                           Часть V. Работа с OLE 


    Использование TOIeContainer 

    Компонент TOIeContainer инкапсулирует функции контейнера OLE в компоненте 
VCL, который значительно проще в использовании. К вставленным в контейнер 
серверам OLE пользователь может получить прямой доступ или доступ посредством 
программных средств."* 
    Когда я начал изучать TOIeContainer, то подумал, что это будет раздел, в 
котором описывается несколько простых методов, так как TOIeContainer не 
казался особо сложным или мощным инструментом. Теперь я изменил свое мнение: 
TOIeContainer — очень мощный инструмент. В мире существует не много вещей, 
которых нельзя сделать с помощью контейнера. Тем не менее нужно время, чтобы 
понять, как работает контейнер и что происходит вне TOIeContainer. Я попытался 
углубиться в изучение TOIeContainer настолько, насколько позволяло время и 
тема этой главы. 
    В Delphi 3 компонент TOIeContainer был создан заново, чтобы обеспечить 
вставку активных документов в контейнер. Теперь во время разработки в 
контейнер можно вставлять активные документы из Microsoft Word и редактировать 
их непосредственно в контейнере. В пакет программ Microsoft Office 97 вошли 
единственные на сегодняшний день приложения, которые манипулируют активными документами. 
    Активные документы обладают интересными возможностями, называемыми 
подшивками (binders). На экране подшивка представлена в виде панели с левой 
стороны окна приложения. На этой панели в виде пиктограмм (icons) хранится 
множество объектов. После щелчка на одной из пиктограмм соответствующий объект 
активизируется в контейнере как часть активизированного по месту сервера. 
    Компонент TOIeContainer позволяет связывать и встраивать объекты OLE в 
приложение. В этом компоненте скрыта большая часть сложных механизмов OLE, что 
позволяет пользователям вставлять объекты в приложение путем вызова метода 
InsertObjectDialog (рис. 18.1). Для встраивания объекта OLE программными 
средствами следует воспользоваться методом CreateObj ect, CreateLinkToFile или 
каким-либо другим методом создания связанных объектов OLE. 
    

    Рис. 18.1. Простое приложение, демонстрирующее два контейнера 
TOIeContainer в одной форме 


    TOIeContainer — это очень мощный инструмент, и в следующих разделах будут 
освещены следующие его аспекты. 
    • Какие методы и свойства TOIeContainer можно использовать. И Как 
встраивать или связывать объекты OLE. 
    • Вырезание (cut) и вставка (paste) объектов OLE в буфер обмена Windows. 
    • Активизирование по месту и пиктограммные (iconic) контейнеры. И Слияние 
меню контейнеров OLE и меню вашего приложения. 
    • Файловые потоки OLE. 
    • Вызовы метода DoVerb. 
    • Работа со свойством OleProperty. Создание собственного диалогового окна 
Insert Object. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   407 


    Определение класса TOIeContainer 

    В класе TOIeContainer добавлено одно новое свойство— AllowActiveDoc. Оно 
используется для поддержки документов типа ActiveDocument. Если свойство 
AllowActiveDoc принимает значение True, то в контейнер можно вставлять 
активные документы. 
    В табл. 18.1-18.3 представлены все методы, свойства и события, 
специфические для класса TOIeContainer или имеющие специальное назначение при 
работе с этим классом. 

    Таблица 18.1. Методы класса TOIeContainer 

    Метод Описание 

    CreateLinkToFile Создает ссылку на физический файл объекта OLE 
    CreateObj ect Создает встроенный объект в контейнере OLE 
    CreateObj ectFromFile Создает встроенный объект OLE на основе данных из 
файла, имя которого указано в контейнере 
    CreateObj ectFromInfo Создает объект на базе спецификации, которая 
хранится в записи Tcreatelnfo 
    DestroyObject Уничтожает объект вместе со всеми внесенными в него изменениями 
    DoVerb Передает объекту OLE запрос на выполнение определенных действий 
    GetIconMetaPic Возвращает глобальный дескриптор (Global Handle) 
пиктограммы объекта OLE. Пик- j тограмма создана в формате метафайла | 
    InsertObjectDialog Открывает диалоговое окно Insert Object. Это окно 
позволяет вставлять новые, связанные или встроенные объекты OLE 
    ChangeIconDialog Позволяет пользователю сменить пиктограмму объекта OLE 
    PasteSpecialDialog Предоставляет пользователю контроль над вставкой 
содержимого буфера обмена Windows в контейнер I 
    ObjectPropertiesDialog Позволяет пользователю просматривать и 
редактировать свойства объекта OLE 
    LoadFromFile Загружает объект OLE из указанного файла 
    LoadFromStreaiti Считывает объект OLE из потока 
    SaveToFile Сохраняет объект OLE в указанном файле 
    SaveToStream Записывает объект OLE в поток j 
    Copy Копирует объект из контейнера в буфер обмена Windows 
    Paste Вставляет объект из буфера обмена Windows в контейнер 
    Run Переводит объект OLE в состояние osRunning 
    UpdateObj ect Повторно считывает объект, чтобы гарантировать, что объект 
содержит актуальные данные | 
    UpdateVerbs Обновляет список глаголов, которые объект OLE может распознать j 
    SourceDoc Имя исходного документа для связанного объекта OLE j 
    State Состояние объекта OLE (osEmpty, osLoaded, osRunning, osOpen, osin- ! PlaceActive,osUIActive) 
    Storagelnterface Интерфейс I storage объекта OLE | 


    408 Часть V. Работа с OLE 


    1 Таблица 18.2. Свойства класса TOIeContainer 

    Свойство              Описание 

    AllowInPlace	Если нужно, чтобы объект всегда появлялся в собственном окне, 
присвойте этому свойству значение False 
    AllowActiveDoc	Если это свойство имеет значение True, то TOIeContainer 
будет автоматически создавать всплывающее меню, в которое будут помещены все 
глаголы объектов 
    AutoActivate	Определяет способ активизирования объекта OLE в контейнере 
(aaManual — активизиро-вание вручную, aaGetFocus —активизирование после 
получения фокуса, aaDouble-Click — активизирование после двойного щелчка) 
    Align	При активизировании по месту этому свойству нужно присвоить значение alClient 
    CanPaste	Указывает, можно ли вставлять данные объекта из буфера обмена в 
контейнер в качестве встроенного объекта 
    CopyOnSave	Если это свойство имеет значение True, то для записи объекта 
OLE, сжатия избыточных данных и сохранения дискового пространства используется 
временный файл 
    Iconic	Если этому свойству присвоить значение True, то в контейнере будет 
показана пиктограмма объекта. В противном случае в контейнере отобразятся 
данные объекта OLE 
    Linked	Для связанных объектов это свойство принимает значение True 
    ObjectVerbs	Возвращает список строк, который содержит все глаголы, 
поддерживаемые объектом в данный момент 
    OleClassName	Имя класса объекта OLE 
    OleObject	Возвращает объект автоматизации OLE (OLE Automation), который 
соответствует находящемуся в контейнере объекту OLE 
    01eObjectInter face	Возвращает интерфейс lOleObj ect для объекта OLE. 
Интерфейс IQleObj ect полезен для получения доступа к API OLE на низком уровне 
    Modified	Принимает значение True, если объект был изменен, перемещен или 
заменен другим объектом 
    Newlnserted	Принимает значение True, если объект OLE заново создан с 
помощью диалогового окна Insert Object, а не посредством вставки из бу4)ера 
обмена или ссылки на файл 
    OldStreamFormat	Позволяет для сохранения объектов использовать формат 
версии OLE 1.0. Это обеспечивает обратную совместимость 
    SizeMode	Управляет размерами объекта OLE в контейнере (smClip, smCenter, 
smScale, smStretch,smAutoSize) 
    

    Таблица 18.3. Событие класса TOIeContainer                                 

    Событие          Описание 

    OnObj ectMove     Происходит, когда пользователь перетаскивает объект OLE 
или изменяет его размеры 

    Событие OnObj ectMove является специфическим для класса TOIeContainer. 
Если необходимо предоставить пользователям возможность перемещать контейнер 
или изменять его размеры (перемещая или изменяя размеры пунктирной рамки 
вокруг объекта OLE), то это событие нужно обрабатывать. В обработчике события 
в записи BoundsRect нужно установить значения, полученные в параметре Bounds 
обработчика события, в противном случае контейнер не изменит положения и 
размера. Ниже показан код простого обработчика события OnObj ectMove. 

    procedure Tformi.OleContainerlObjectMove(OleContainer: TOIeContainer; 
    const Bounds: TRect); 
    begin 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   409 


    // Не допустить, чтобы размеры контейнера были 
    // меньше размеров объекта. 
    with Bounds do begin 
    if Left < 100 then Left := 100 
    if Right < 100 then Right := 100 
    end; // with 
    OleContainerl.BoundsRect := Bounds; 
    end; // Tforml.OleContainerlObjectMove 


    Встраивание новых объектов OLE 

    Компонент TOle-Container позволяет связывать и встраивать объекты OLE в 
приложении. В этом компоненте скрыта большая часть сложных механизмов OLE, что 
позволяет вставлять объекты в приложение путем вызова одного методаInsertObjectDialog. 
    Ниже приведен пример, поясняющий все вышесказанное. 
    1. Откройте новое приложение в Delphi. 
    2. Выберите компонент TOleContainer на странице System в палитре компонентов. 
    3. Поместите этот компонент в форму и дважды щелкните на нем. На экране 
появится диалоговое окно Insert Object (рис. 18.2). 
    
    Рис, 18.2. Диалоговое окно Insert Object 

    4. В списке Object Type выберите тип Bitmap Image и щелкните на кнопке ОК. 
    5. Дважды щелкните на контейнере. Активизируется приложение-контейнер, и 
на экране появится программа Paint в отдельном окне. Создайте в этом 
приложении небольшой рисунок (рис. 18.3). (Вероятно, у вас получится лучше, 
чем у меня.) 
    6. Закройте графический редактор. В контейнере OLE должен появиться 
рисунок, который вы создали в редакторе Paint. Если вы наблюдательны, то 
заметите, что изменения, вносимые в рисунок в редакторе, автоматически 
отображаются в вашей форме. 

    Рис. 18.3. Создание рисунков в приложении Paint 
    

    410                                   Часть V. Работа с OLE 

    В результате выполненных действий вы встроили объект Paint в при- 
|IЖтаll!'lтаЗI!'Я'ff^glИi^^ ложение. Теперь, как показано на рис. 18.4, для 
изменения свойств объекта ^гсепйаНув» 1 OLE можно использовать диалоговое окно 
ObjectPropertiesDialog. ; 
    Это окно появится на экране после щелчка правой кнопкой мыши на кон- 
lllAateBitmap image тейнере и выбора команды Object Properties. 

    Рис. 18.4. Диалоговое окно свойств для объекта Paint 

    Диалоговое окно ObjectPropertiesDialog можно вывести на экран и с помощью 
программных средств, например: 

    Procedure TFormI.ButtonlClick(Sender: TObject); 
    begin 
    with OleContainerI do 
    if ObjectPropertiesDialog then 
    ShowMessage('Свойства объекта OLE изменены'); 
    // Мы еще не знаем, какие свойства изменены. 
    end; //Tforml.ButtonlClick 

    Чтобы встроить объект OLE в контейнер TOleContainer с помощью программных 
средств, воспользуйтесь методом CreateObject, а для создания связанного 
объекта OLE предназначен метод CreateLinkToFile. 
    Заметьте, что не каждый файл может быть вставлен в TOleContainer. Для 
вставки подходят только те файлы, которые контейнер распознает. Если в 
контейнер вставляется документ, то в Windows должна быть зарегистрирована 
ассоциация для загрузки сервера OLE, в противном случае нужно использовать 
файл объекта. В показанном ниже фрагменте кода выполняется проверка 
возможности вставки объекта. Если объект нельзя вставить, то выводится 
соответствующее сообщение. 

    Procedure TFormI.ButtonlClick(Sender: TObject); 
    begin 
    with OleContainerI do 
    if InsertObjectDialog then 
    DoVerb(ovShow) ; 
    else 
    ShowMessage('An object MUST be specified'); 
    end; // TForml.ButtonlClick 

    Объекты OLE можно создавать и программными средствами. Например, для 
создания объекта OLE с помощью метода CreateObject нужно указать значение 
идентификатора программы (Progid) и вид объекта (в виде пиктограммы) или сам 
объект. Для создания объекта-изображения можно использовать два 
идентификатора: Paint. Picture и Pbrush, которые можно найти в системном 
реестре. Фрагмент кода, показанный ниже, создает объект Paint и отображает в 
контейнере содержимое, а не пиктограмму объекта OLE. 

    CreateObject С Paint.Picture', False) ; 

    Идентификаторы программ (Progid}— это хранимые в реестре и связанные с 
идентификаторами классов OLE (CLSID) значения. Для вставки объектов можно 
создавать собственные диалоговые окна. Самая сложная часть этого процесса — 
получение списка доступных объектов OLE. 
    На практике не существует способа получить данные из стандартных 
диалоговых окон InsertObjectDialog и ObjectPropertiesDialog. Как правило, 
очень сложно получить доступ к свойствам всех стандартных диалоговых окон. 
Значительно проще создать собственные аналоги диалогового окна 
InsertObjectDialog, а затем приспособить созданное диалоговое окно для своих нужд. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   411 

    Фрагмент кода, показанный ниже, используется в программе OleDB для 
создания собственного диалогового окна Insert Object. Этот фрагмент кода 
получает из реестра список типов объектов и соответствующие идентификаторы 
программ. На дополнительно распространяемой дискете вы найдете метод 
TdlglnП1"ИЯ!ЯЯ sertableOleObj . GetInsertableObjects, код которого показан в 
листинге 18.1. 

    Листинг 18.1. \UDELPHl3\CHPl8\OLEDB\lnsertable01eObju.PAS. Код для 
создания диалогового окна Insert Object 

    procedure TdiginsertableOleObj.Getln5ertable0bjects(OLENames, Proglds: TStrings); 
    var 
    i: integer; 
    OleType, CLSID: String; 
    KeyNames: TStrings; 
    begin 
    // Эта процедура находит все типы объектов в системном реестре, 
    // которые могут вставляться в контейнер OLE. 
    KeyNames:= TStringList.Create; 
    try 
    with TRegistry.Create do 
    try 
    RootKey := HKEY_CLASSES_ROOT; 
    if not OpenKey('\', False) then exit; 
    GetKeyNames(KeyNames) ; 
    with KeyNames do 
    for i := 0 to count - 1 do begin 
    CloseKey; 
    RootKey := HKEY_CLASSES_ROOT; 
    if OpenKey(Strings[i], False) then begin 
    if KeyExists('Insertable') then begin 
    OleType := ReadString(''); 
    OpenKey('CLSID', False); 
    CLSID := ReadString(''); 
    CloseKey; 
    if OpenKey('CLSID\' + CLSID, False) then begin 
    OLENames.Add(OleType) ; 
    if OpenKey('Progid', False) then 
    Progld.Add(ReadString('') ) 
    else 
    Progld.Add(' [NO PROG ID] '); 
    end; // if CLSID 
    end; // if 
    end; // for 
    end; // with KeyNames 
    finally 
    Free ; 
    end; // try 
    finally 
    KeyNames.free; 
    end; // try 
    end; // TdiginsertableOleObj.GetInsertableObjects 

    Метод GetInsertableObjects сначала считывает список всех ключевых слов в 
корне реестра, после чего циклически проверяет каждый ключ на наличие 
вложенного ключа с именем Insertable. Если такой ключ найден, то он содержит 
информацию о типе объектов, а все, что нужно узнать, — это идентификатор 
программы данного типа объектов. Идентификатор программы можно найти в ключе 
CLSID, соответствующем выбранному типу объектов. 

    412                                           Часть V. Работа с OLE 


    Как я нашел все вставляемые объекты 

    В процессе исследования этого метода поиск всех объектов, которые можно 
использовать в диалоговом окне insertObjectDialog, занял много времени. Нужно 
решить двойную проблему. Во-первых, известно, что информация обо всех искомых 
типах объектов находится где-то в реестре Windows, но настройка объекта 
TRegistry займет много времени. 
    В справке по методу createObject указано, что ему необходим идентификатор 
программы (Progid). Таким образом, переменной RootKey присваивается значение 
HKEY_CLASSES_ROOT и можно ожидать, что метод Орепкеу начнет поиск с текущего 
положения в реестре или с корневого ключа. На практике метод Орепкеу всего 
лишь перемещает текущую позицию в положение, указываемое путем к нужному 
ключу. Чтобы переместить указатель в корень реестра, нужно установить 
соответствующее значение переменной RootKey. 
    Одним из методов поиска объектов, которые можно использовать в диалоговом 
окне InsertObjectDialog, является поиск всех идентификаторов классов (CLSID), 
для которых определен вложенный ключ progid. В результате будет получен 
список, практически совпадающий со списком объектов в диалоговом окне 
InsertObjectDialog. Но в полученном списке содержатся типы объектов, которых 
нет в диалоговом окне InsertObjectDialog. Я заметил, что для некоторых типов 
объектов определен ключ insertable, и, выполнив поиск в реестре, я выяснил, 
что для получения списка объектов, используемых в диалоговом окне 
InsertObjectDialog, достаточно найти все вложенные ключи CLSID ключа 
HKEY_CLASSES_ROOT, для которых определен ключ insertable. Неожиданно мной был 
получен список, точно соответствующий списку в стандартном диалоговом окне 
InsertObjectDialog. После этого остается воспользоваться идентификатором 
класса, соответствующим ключу insertable, для поиска идентификатора программы 
(Progid) и класса (CLSID) вставляемого объекта. Например, поиск в реестре 
ключа insertable дал следующий результат. 

    HKEY_CLASSES_ROOT 
    AVIFile 
    CLSID                                      {00022602-0000-0000-COOO-00000000046) 
    Compressions 
    Defaultlcon 
    Extensions 
    Insertable 

    Теперь, выполнив поиск по идентификатору класса (CLSID), можно найти 
идентификатор программы, в данном случае это значение AVIFile. 
    Просматривая список расширений файлов (например, BMP и DOC), можно 
получить список всех типов объектов, которые можно связывать или встраивать в 
ваши приложения. Вы можете контролировать способ вставки таких объектов — 
связывание или встраивание. Более детально я не изучал метод получения списка 
объектов подобного типа, но вы можете сделать это самостоятельно. 
    Таким образом, в распоряжении разработчика находится очень мощный 
инструмент. С помощью описанных приемов можно определить объекты, добавляемые 
в ваше приложение. Описанные приемы также позволяют управлять способаМИ 
Добавления объеКТОВ—— ПОЛЬЗОВаТеЛЯМ МОЖНО раЗреШИТЬ СВЯЗЫВаТЬ объеК

    MiDiSequence 

    Netscape Hypertext Document                    : 

    ты или встраивать их. Если разрешено связывание, то в распоряжение 
разработ-   д5^р!1^Ьор image чика поступает путь к файлу связанного объекта, 
    Нами разработан метод получения списка типов объектов и соответствующих 
идентификаторов программ. Осталось создать обычное диалоговое окно, подобное 
показанному на рис.18.5, чтобы позволить пользователям выбирать тип объекта 
ДЛЯ контейнера. 

    WordPad Document 
    Video Clip 
    MIDI Sequence 
    Media Clip 
    Netscape Hypertext Document 
    
    Рис. 18.5. Пользовательское диалоговое окно Insert New Ole Object 

    Показанный в листинге 18.2 исходный код можно найти в файле 
InsertableOleObjeU. Раз на дополнительно распространяемой дискете. 

    Листинг 18.2. \UDELPHl3\CHP18\OLEDB\lnsertable01eObjU.PAS. Создание и 
вывод на экран диалогового окна со списком объектов OLE, которые можно 
добавлять в приложение 

    unit InsertableOleObjU; 
    interface 
    uses 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   413 


    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, 
StdCtrls, ExtCtrls, Buttons, Mask, DBCtrls; 
    type    ! 
    TdlgInsertableOleObj = class(TForm) 
    Paneil: TPanel; 
    ListBoxl: TListBox; 
    Panel2: TPanel; 
    btnCancel: TBitBtn; 
    BitBtn3: TBitBtn; 
    procedure FormCreate(Sender: TObject); 
    procedure ListBoxIDblClick(Sender: TObject); 
    procedure BtnCancelClick(Sender: TObject); 
    procedure FormShow(Sender: TObject); 
    procedure GetInsertableObjects(OLENames, Progid : TStrings); 
    private 
    Proglds: TStrings; 
    public 
    Selected_ProgId : String; 
    end; 
    var 
    dIgInsertableOleObj: TdlgInsertableOleObj ; 
    implementation 
    uses Registry, OLEDBU, OLEu; 
    {$R *.DFM) 
    procedure TdlgInsertableOleObj.GetInsertableObjects(OLENames, Progid : TStrings); 
    var     ; 
    i: integer; 
    OleType, CLSID: String; 
    KeyNames: TStrings; 
    begin 
    KeyNames:= TStringList.Create; 
    try 
    with TRegistry.Create do 
    try 
    RootKey := HKEY_CLASSES_ROOT; 
    if not OpenKey('\', False) then exit; 
    GetKeyNames(KeyNames) ; 
    with KeyNames do 
    for i := 0 to count - 1 do begin 
    CloseKey; 
    RootKey := HKEY_CLASSES_ROOT; 
    if OpenKey(Strings[i], False) then begin 
    if KeyExists('Insertable') then begin 
    OleType := ReadString('') ; 
    OpenKey ('CLS-ID', False); 
    CLSID := ReadString(''); 
    CloseKey; 
    if OpenKey('CLSID\' + CLSID, False) then begin 
    OLENames.Add(OleType) ; 
    if OpenKey('Progid', False) then 
    Progid.Add(ReadString('') ) 
    else 
    Progid.Add(' [NO PROG ID] '); 


    414                                           Часть V. Работа с OLE 


    end; // if CLSID 
    end; // if 
    end; // for 
    end; // with KeyNames 
    finally 
    Free; 
    end; // try 
    finally 
    KeyNames.free; 
    end; // try 
    end; // TdlgInsertableOleObj.GetInsertableObjects 
    procedure TdlgInsertableOleObj.FormCreate(Sender: TObject); 
    begin 
    Proglds := TStringList.Create; 
    end; 
    procedure TdlgInsertableOleObj.ListBoxIDblClick(Sender: TObject); 
    begin 
    Selected_ProgId := Proglds[ListBoxl.Itemlndex]; 
    ModalResult := mrOk; 
    end; 
    procedure TdlgInsertableOleObj.BtnCancelClick(Sender: TObject) ; 
    begin 
    Selected_ProgId := ''; 
    ModalResult := mrCancel; 
    end; 
    procedure TdlgInsertableOleObj.FormShow(Sender: TObject); 
    begin 
    Selected_ProgId := ''; 
    GetInsertableObjects(ListBoxl.Items, Proglds) ; 
    end; 
    end. 

    Для встраивания в контейнер TOleContainer объектов из файлов с расширением 
DOC или BMP можно воспользоваться методом CreateObjectFromFile. Код, 
показанный в листинге 18.3, выполняет встраивание объекта из файла с помощью 
диалогового окна TOpenDialog и метода CreateObjectFromFile. Исходный код 
представленного здесь метода TfrmMain. LoadEmbeddedlClick читатель найдет на 
дополнительно распространяемой дискете. 

    1 Листинг 18.3. \UDELPHl3\CHPl8\OLEDB\OLEDBU. PAS. Метод, встраивающий 
объекты в TOleContainer       ! 

    procedure TfrmMain.LoadEmbeddedlClick(Sender: TObject); 
    var S: String; 
    begin 
    if OpenDialogI.Execute then 
    Form2.OleContainerI.CreateObjectFromFile(OpenDialogI.FileName, 
    IconViewl.Checked); 
    end; 

    Компонент TOleContainer позволяет связывать и встраивать объекты OLE в 
ваше приложение. В этом компоненте скрыта большая часть сложных механизмов 
OLE. Это предоставляет пользователям возможность вставлять объекты в 
приложение путем вызова метода Insert66jectDialog. Для встраивания объекта OLE 
программными средствами следует воспользоваться методом CreateObject, 
CreateLinkToFile или каким-либо другим методом создания связанных объектов OLE. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   415 


    Связывание объектов OLE 

    Связывание объектов позволяет пользователям получать доступ к одному и 
тому же объекту, даже в одно и то же время. Кроме того, изменения, вносимые в 
объект, автоматически отображаются во всех приложениях, которые связаны с 
объектом. Как и при встраивании объектов, для их связывания можно использовать 
диалоговое окно InsertObjectDialog. Ниже представлен метод создания связи с 
растровым файлом (BMP) во время разработки приложения в Delphi 3. 
    1. Откройте новое приложение в Delphi. 
    2. В палитре компонентов на странице System выберите компонент TOleContainer. 
    3. Поместите TOleContainer в форму и дважды щелкните на этом компоненте. 
На экране появится диалоговое окно Insert Object (рис. 18.6) 
    4. Выберите опцию Create From File и установите флажок Link (рис. 18.7). 
    5. Теперь введите имя файла или выберите необходимый файл с помощью кнопки 
Browse. Чтобы упростить пример, выберите один из растровых файлов каталога 
Windows. Щелкните на кнопке ОК. Выбранный файл должен появиться в контейнере. 

    Рис. 18.6. Диалоговое окно Insert Object связи с объектом из файла 

    Рис. 18.7. Диалоговое окно Insert Object для создания 

    На рис. 18.8 показан результат создания связи с файлом С: \WIN\WAVES . BMP. 
    Связь с объектом можно создавать и во время выполнения программы. Ниже 
показан код метода, который связывает или встраивает объект в контейнер. 
Исходный код метода TfrmMain. LoadDocument, представленный в листинге 18.4, 
можно найти на дополнительно распространяемой дискете. 

    рис. 18.8. Вид контейнера, содержащего файл WAVES . BMP, во время 
разработки приложения 

    Листинг 18.4. \UDELPHI3\CHP18\OLEDB\OLEDBY. PAS. Создание связи во время 
выполнения                  j 

    Procedure TfrmMain.LoadDocument(FileName: string; Embedded: Boolean); 
    begin 
    with OleContainerI do begin 
    if Embedded then 
    CreateObjectFromFile(FileName, false) 
    else 
    CreateLinkToFile(FileName, false); 
    M" DoVerb(ovShow) ; 
    end; //with 
    end; // TfrmMain.LoadDocument 


    416                                           Часть V. Работа с OLE 


    Активизирование по месту и свойства пиктограммы объекта 

    Активизирование по месту — это перевод объекта в активное состояние внутри 
контейнера OLE. Хорошо! А как можно использовать активизирование по месту в 
вашем приложении? Проще всего следовать указаниям, приведенным ниже. 
    1. Поместите контейнер TOleContainer в новую форму и установите для его 
свойства Align значение alClient. Свойству AutoActivate присвойте значение aaGetFocus. 
    2. Дважды щелкните на контейнере и выберите тип объекта, например 
растровое изображение или документ Word. 
    3. Создайте небольшой рисунок в программе Paint или наберите некоторый 
текст в Word. После этого закройте приложение. 
    4. Теперь запустите вашу программу. Приложение — сервер объекта должно 
запуститься внутри контейнера. 
    Не все объекты OLE можно активизировать по месту. 
    Свойство AutoActivate может принимать одно из трех значений: aaManual, 
aaGetFocus и aaDoubleClick. По умолчанию оно принимает значение aaDoubleClick. 
Если используется это значение, то контейнер активизирует и отображает сервер 
OLE только после двойного щелчка на контейнере. 
    Значение aaGetFocus (используется во многих примерах в этой главе) 
заставляет контейнер автоматически активизировать сервер OLE после получения 
контейнером фокуса ввода. 
    Третье значение — aaManual — используется для активизирования сервера 
только в случае возникновения специфических событий или условий. 
    Все это хорошо, но где меню и панель инструментов? Эти элементы легко 
добавить в ваше приложение. Для создания меню"достатбчно вставить в форму 
компонент TM'afnHenu, расположенный на странице Standard палитры компонентов. 
Теперь снова запустите создаваемую программу. В программе появится меню 
приложения Paint. Более детально о слиянии и дополнении меню можно узнать из 
раздела "Слияние меню". 
    Если объект OLE не может расположить панели инструментов в форме, то они 
становятся "плавающими" (как в Microsoft Word) или не отображаются вообще. 
Чтобы обеспечить отображение панелей инструментов объекта OLE, необходимо в 
верхней части формы создать панель с выравниванием а I Т 6р.'Объекты OLE, 
активизируемые по месту, устанавливают панели инструментов серверов OLE 
непосредственно в окно приложения. Обычно любые панели вашей программы, 
используемые в качестве панелей инструментов, заменяются на панели 
инструментов сервера OLE. Такую замену панелей можно отключить, если присвоить 
свойству Locked соответствующей панели значение True. 
    Продолжим работу с предыдущим примером. 
    5. Свойству Align контейнера TOleContainer присвойте значение aINone. 
    6. Создайте две панели в окне приложения. Одну панель выровняйте по 
верхнему (alTop) краю окна приложения, вторую — по нижнему(alBottom). 
    
    Рис. 18.9. Форма с двумя панелями, меню и контейнером OLE 

    Рис. 18.10. Форма с двумя панелями, меню и контейнером OLE 

    7. Установите значение True в свойстве TPanel. Locked для панели, 
выровненной по нижнему краю окна. 
    8. Установите значение alClient в свойстве TOleContainer .Align. 
    Созданная форма должна быть похожа на форму, которая показана на рис. 
18.9. Теперь запустите программу. Форма должна выглядеть так, как на рис. 18.10. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   417 
    14 Использование Delphi 3 Специальное издание 

    Если во время разработки свойству Iconic контейнера TOleContainer 
присвоить значение True, то объекты Е контейнере будут отображаться в виде 
пиктограмм. Если после этого запустить приложение, то сервер OLE после 
активизирования будет запускаться в собственном окне. Некоторые объекты, 
хранимые в контейнерах OLE, не поддерживают активизирование по месту и 
открывают'отдельное окно сервера OLE независимо от значения свойства Iconic. 
Если в контейнереГиспользовать^объект типа Sound Object, то при 
активизировании будет использовано приложение Microsoft Sound Recorder, 
которое всегда запускается в собственном окне. 
    Если для работы с активными документами нужно использовать подшивки 
(binders), то в окне приложения добавьте еще одну панель, выровненную по 
левому краю окна (а 1 Left). 
    Во время выполнения программы можно создать и сам контейнер OLE. Ниже 
приведен пример кода, демонстрирующий, как создать контейнер, добавить в него 
объект OLE, установить автоматическое активизирование по месту и отобразить 
объект OLE. Показанный фрагмент кода предполагает использование меню и панелей 
инструментов сервера OLE. 

    procedure TFormI.FormShow(Sender: TObject); 
    begin 
    //Создание верхней панели. 
    with TPanel.Create(self) do begin 
    Parent :="self; " """-— 
    Align := alTop; 
    end; // create TPanel 
    // Создание меню. 
    with TMainMenu.Create (self) do begin 
    Parent := self; 
    end; // create TMainMenu 
    // Создание контейнера OLE. 
    with TOleContainer.Create(self) do begin 
    Parent := self; 
    AllowInPlace := True;        // По умолчанию. 
    AutoActivate := aaGetFocus; // Автоматическое активизирование 
    // при запуске приложения. 
    Align := alClient; 
    // Создание контейнера по умолчанию. 
    CreateObjectС Paint.Picture', false); // Отображать объект. 
    Iconic := False;                      // Не показывать пиктограмму. 
    // Установить фокус для этого окна. 
    SetFocus; 
    end; // with TOleContainer create 
    end; //TFormI.FormShow 


    Слияние меню 

    Когда в контейнере объект активизируется по месту, то меню сервера OLE 
интегрируется в меню TMainMenu, если этот компонент находится в той же форме, 
что и контейнер TOleContainer. МенкГформы может быть объединено с меню сервера 
OLE. Это означает, что, если в форме создано меню File и сервер OLE содержит 
меню File, после активизирования сервера в форме появится только одно меню 
File. TOleContainer автоматически выполняет слияние команд меню формы 
контейнера и активизированного по месту сервера OLE. 
    С помощью свойства Grouplndex элементов меню можно управлять способом 
слияния меню. Элементы меню верх(»   него уровня с индексами Grouplndex, 
равными 0, 2 и 4, остаются неизменными, а элементы, для которых свойство 
Grouplndex равно 1, 3 или 5, будут заменены на меню приложения— сервера OLE. 
Таким образом, для традиционной MDI-формы значения свойств Grouplndex 
присваиваются согласно табл. 18.4. 

    Таблица 18.4. Слияние меню и значения свойства Grouplndex 

    Меню             Значение свойства Grouplndex Меню               Значение 
свойства Grouplndex 

    File                0                              Window              4 
    Edit                1                              Help                  5 
    Object              2 


    418                                           Часть V. Работа с OLE 


    Следовательно, раскрывающиеся меню File, Object и Window не изменятся, а 
команды меню Edit и Help будут заменены командами меню сервера OLE.            
                                                    ; 
    Заметьте,что.значение 3 для свойства Group.IiidQx.He используется (и в 
этом нет ничего страшного). 

    Рис. 18.11. Меню формы до слияния с меню документа Word 

    Рис. 18.12. Меню формы после слияния с меню документа Word 

    На рис. 18.11 и 18.12 показана форма до и после слияния меню. На этих 
рисунках можно заметить различия в меню до и после слияния. 

    Использование буфера обмена для копирования и ставки уществующих объектов OLE 

    Копирование и вставка объектов во время разработки приложения в Delphi 
работают так же, как и при работе в других приложениях Windows. Копировать и 
вставлять объекты можно и во время выполнения. Для этого необходимо 
воспользоваться методом Copy, Paste или PasteSpecialDialog. 
    Методы Copy и Paste работают с контейнером TOleContainer так же, как и с 
другими компонентами Delphi. Единственное отличие при вставке объектов OLE в 
том, что сервер OLE запрашивает, могут ли объекты, находящиеся в буфере 
обмена, помещаться в контейнер. С помощью метода CanPaste во время выполнения 
приложения можно проверить, разрешается ли вставлять объект OLE в контейнер. 
    В методе Paste выполняется запрос к буферу обмена, чтобы проверить, 
распознает ли этот метод объект, передаваемый из буфера обмена. Ниже показан 
пример использования метода Paste. 

    Procedure Tform.DoPaste; 
    begin 
    with OLEContainerI do 
    if CanPaste then 
    Paste 
    else 
    ShowMessage('Can not paste OLE object from Windows clipboard'); 
    end; // Tform.DoPaste 

    Метод PasteSpecialDialog предоставляет больше средств управления способами 
вставки содержимого буфера обмена Windows в контейнер (рис. 18.13). Диалоговое 
окно Paste Special позволяет пользователю выбрать формат данных, указать, 
будет ли объект встроенным или связанным и отображать ли объект OLE в виде 
пиктограммы. Кроме того, это диалоговое окно позволяет изменить пиктограмму 
объекта, используемую по умолчанию. 

    Procedure TFormI.DoPasteSpecial; 
    begin 
    with OLEContainerI do 
    if PasteSpecialDialog then 
    ShowMessage('Paste Done') ; 
    end; // TFormI.DoPasteSpecial 

    На рис. 18.14 показана вставленная в контейнер таблица Excel. 


    Работа с диалоговыми окнами OLE 

    В контейнер OLE встроено четыре диалоговых окна. В Delphi доступ к этим 
окнам можно получить с помощью методов ChangeIconDia 
log,InsertObjectDialog,Object Properties Dialog и PasteSpecialDialog. 
    Единственным диалоговым окном, которое не рассматривалось в предыдущих 
разделах, является окно Change Icon. С его помощью пользователь может изменять 
пиктограмму, связанную с объектом OLE и отображаемую в контейнере. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   419 

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

    Procedure TFormI.ChangeIconlClick(Sender: TObject); 
    begin 
    with OleContainerI do 
    // Объект должен быть в контейнере. 
    if State <> osEmpty then 
    if ChangeIconDialog then 
    ShowMessage('Icon was Changed'); 
    end; // TFormI.ChangeIconlClick 
    fdit VBW jreert Fotmat Tools fiate Urip 
    

    Рис. 18.13. Диалоговое окно Paste Special, с помощью       
которого в контейнер вставляется таблица Excel 

    Рис. 18.14. Таблица Excel, вставленная в контейнер OLE 

    Все описанные диалоговые окна являются частью TOleContainer и не содержат 
дополнительных свойств и методов, к которым можно получить прямой доступ. Это 
означает, что не существует способа установить перед вызовом специфического 
диалогового окна каких-либо значений по умолчанию. Также не существует способа 
получить информацию об установках, которые пользователь сделал в диалоговом окне. 
    выполнения приложения (рис. 18.15). В разделе "Встраивание новых объектов 
OLE'' описывается способ построения собственного диалогового окна Insert 
Object. В этом разделе рассказывается о способе получения пиктограммы объекта 
OLE, находящегося в контейнере TOleContainer. 

    Рис. 18.15. Диалоговое окно Change Icon 

    Показанный ниже фрагмент кода демонстрирует способ получения пиктограммы 
объекта OLE и сохранения ее в формате метафайла Windows. 

    // !!!! Эта функция вызывается основной процедурой, определенной ниже!!!! 
function Win32Chk(Win320K: Integer): Integer; 
    var 
    Buffer: String; 
    begin 
    Result := Win320K; 
    if Win320K = 0 then begin 
    SetLength(Buffer, ERRORSIZE) ; 
    if FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil, GetLastError, 0, 
    PChar(Buffer), ERRORSIZE, nil) = 0 then 


    420                                           Часть V. Работа с OLE 


    Buffer := 'Internal Error: Error creating Error String'; 
    SetLength (Buffer, StrLeriC'Pchar (Buffer) ) ) ;                           
    raise EWin32Error.Create(Buffer); 
    end; 
    end; // Win32Chk 
    Procedure TFormI.ChangeIconlClick(Sender: TObject); 
    var 
    Hg: HGlobal; 
    Mfp: PMetaFilePict; // HMetaFile; 
    Hmf: HMetaFile;                                                            
    HHH: HMetaFile;                                                            
    const mfile: pchar = 'c:\test.wmf; 
    begin 
    with OleContainerI do 
    // Объект должен находиться в контейнере. 
    if State <> osEmpty then 
    if ChangeIconDialog then begin 
    Hg := OleContainerI.GetIconMetaPict; 
    Hmf := PMetaFilePict(GlobalLock(Hg)".hMF; 
    HHH := CopyMetaFile(hmf, mfile); 
    if HHH = 0 then Win32Chk(boolean(HHH)); 
    GlobalUnLock(Hg) ; 
    end; // if end; //TFormI.ChangeIconlClick 

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

    TOIeContainer и файловый ввод-вывод 

    Компонент TOIeContainer позволяет сохранять объекты OLE двумя разными 
способами. Чаще применяется считывание и запись объектов OLE в файлы. 
    Например, показанная ниже процедура считывает объект OLE из файла. 

    procedure TFormI.LoadObject; 
    begin 
    with OleContainerI do 
    LoadFromFile('c:\udelphi3\chpl8\TestFile-bmp') ; 
    end; // TFormI.LoadObject 

    /^k    Файл TESTFILE. BMP находится на дополнительно распространяемой 
дискете в каталоге \Udelphi\Chpl8\. 
    Файл testfile. bmp является файлом объекта OLE, а не растровым файлом. 
Размер файла исходного растрового файла составлял 13 Кбайт, а размер файла 
объекта— 190 Кбайт. 
    Процедура TFormI. LoadObject загружает объект OLE "TESTFILE.BMP". В 
процессе считывания нового объекта хранящийся в контейнере объект будет удален 
вместе со всеми внесенными в него изменениями. Если свойство OleStreamFormat 
содержит значение True, то с помощью метода LoadFromFile можно загрузить любой 
файл объекта, созданный с помощью компонента TOIeContainer из Delphi 1.0. 

    procedure TFormI.SaveObject; 
    begin 
    with OleContainerI do 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   421 


    if State <> osEmpty then 
    SaveToFile('c:\udelphi3\chpl8\testfile.bmp') ; 
    end; // TFormI.SaveObject 

    Файл testfile.bmp можно найти в каталоге \Udelphi3\chpl8\ на дополнительно 
распространяемой дискете. Показанный выше фрагмент кода запишет объект, 
который находится в контейнере OLE, в файл объекта OLE. Объект должен быть 
загружен в контейнер, прежде чем начнется его запись в файл. Если в момент 
записи свойство OldStreamFormat содержит значение True, то метод SaveToFile 
создаст файл, совместимый с реализацией TOleContainer в Delphi 1.0. 
    Значение True в свойстве OldStreamFormat нужно использовать, только если 
крайне необходимо обеспечить обратную совместимость с файлами объектов, 
созданными контейнером TOleContainer, реализованным в Delphi 1.0. Во всех 
остальных случаях этому свойству следует присваивать значение False. В elphi 
2.0 и более поздних версиях в заголовках объектов OLE содержится 
дополнительная информация, которую TOleContainer использует для проверки файла 
или потока. 
    Методы LoadFromStream и SaveToStream ведут себя так же, как и описанные 
выше методы LoadFromFile и SaveToFile. Единственное различие между этими 
методами заключается в том, что для методов LoadFromStream и SaveToStream 
вместо файлов используются потоки ввода-вывода. В следующем разделе буде 
показано, как использовать потоки для считывания и записи объектов OLE в базу данных. 

    Использование потоков для считывания и записи объектов OLE в базу данных 

    До сих пор я не встречал программ, которые считывают и записывают объекты 
OLE в базу данных. Поэтому я решил создать программу OLEDB. ЕХЕ. Полный 
исходный код этой программы можно найти на дополнительно распространяемой дискете. 
    В таблице базы данных есть поле OLE Obj ect. Для считывания и записи 
значений этого поля в примере используется компонент TBIobStream. В листинге 
18.5 содержится исходный код метода TfrmMain.LoadFromStreamOLE. Этот же код 
можно обнаружить в файле OLEDBU. РАЗ на дополнительно распространяемой дискете. 

    I Листинг 18.5. \UDELPHl3\CHPl8\OLEDB\OLEDBU. PAS. Считывание файла OLE из потока 

    procedure TfrmMain.LoadFromStreamOLE; 
    var 
    BS: TBIobStream; 
    begin 
    BS := TBIobStream.Create (Tablel.FieldByName('OLE_Object') as TBIobField, 
bmRead) ; 
    if BS.Size <> 0 then 
    try with frmOLE, OLEContainerI do begin 
    LoadFromStream(BS) ; 
    AllowInPlace := True; 
    end; // with 
    finally 
    BS.Free; 
    end; // Try 
    end; // TfrmMain.LoadFromStreamOLE 

    Заметьте, что свойство Iconic можно устанавливать только после загрузки 
объекта в контейнер. Для пустого контейнера это свойство использовать нельзя. 
    В программе OLEDB метод LoadFromStream вызывается из метода 
TDataSource.OnDataChanged. Таким образом, содержимое контейнера OLE будет 
изменяться каждый раз, когда курсор таблицы перемещается на новую запись. В 
листинге 18.6 показан исходный код метода TfrmMain. WriteToStreamOLE. Это 
пример записи объекта OLE в таблицу. Этот фрагмент кода можно найти в файле 
OLEDBU. PAS на дополнительно распространяемой дискете. 

    422                                           Часть V. Работа с OLE 

    Листинг 18.6. \UDELpHi3\CHPl8\OLEDB\OLEDBU.PAS. Запись файла OLE в поток 

    procedure TfrmMain.WriteToStreamOLE; 
    var 
    BS:   TBIobStream; 
    begin 
    BS := TBIobStream.Create( 
    Tablel.FieldByName('OLE_Object') as TBIobField, bmWrite); 
    try 
    with frmOLE.OLEContainer! do 
    if State <> osEmpty then 
    SaveToStream(BS) ; 
    finally 
    BS.Free; 
    end; // try 
    end; // TfrmMain.WriteToStreamOLE 

    Оптимальным местом вызова этого метода является обработчик события 
OnBeforePost компонента TTable. Единственной проблемой остается определение 
момента, когда изменяется объект OLE, а это можно сделать с помощью свойства 
TOleContainer. Modified. Если значение этого свойства равно True, значит, 
объект OLE изменен. 

    TOIeContainer и масштабирование 

    TOleContainer позволяет объектам изменять собственные размеры пятью 
способами, определяемыми значениями свойства SizeMode, приведенными в табл. 18.5. 

    | Таблица 18.5. Значения свойства SizeMode 

    Чняченщ»          Опнгяние 

    smClip	Объект OLE имеет свои обычные размеры; части объекта, не 
помещающиеся в контейнер, не отображаются. Это значение присваивается свойству 
SizeMode по умолчанию 
    smCenter	Объект OLE отображается с обычными размерами в центре контейнера 
    smScale	Объект OLE увеличивается или уменьшается до размеров контейнера. 
Высота и ширина объекта изменяются пропорционально 
    smStretch	Объект OLE увеличивается или уменьшается до размеров контейнера 
независимо от пропорций объекта OLE 
    smAutoSize	Оказывает тот же эффект, что и smClip. Изменяет размер 
контейнера при изменении размеров объекта OLE 

    Я умолчал еще об одном интересном эффекте. Обычные документы OLE (не 
принадлежащие типу Active Document) некорректно определяют собственное 
состояние в контейнере (например, объекты Paint или линейки в объектах Word). 
Чтобы решить эту проблему, вставьте контейнер TOleContainer в панель (TPanel) 
и установите для нее ширину границы (свойство BorderWidth), равную 10 или 
больше, если это нужно для отображения всех элементов интерфейса объекта OLE. 
Активные документы корректно определяют, что можно использовать всю область 
окна, и отображают всю необходимую информацию. Следовательно, при работе с 
документами OLE типа Active Document не требуется помещать контейнер в панель. 

    заметку г   • 
    Чтобы использовать активизирование по месту для панели и контейнера, 
следует установить выравнивание размеров объекта по клиентской области окна (alClient). 

    Два следующих рисунка поясняют, что я имел в виду, говоря о ширине границ. 
На рис. 18.16 показана форма с документом Word без линеек. В этой форме ширина 
границ панели была установлена по умолчанию. На рис. 18.17 показана форма, в 
которой ширина границ панели была изменена. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   423 


    Рис. 18.16. Документ Word в форме, в которой ширина границы панели не изменялась 

    Рис. 18.17. Документ Word в форме, в которой ширина границы панели была изменена 


    Использование глаголов OLE 

    Контейнеры OLE имеют некоторый набор глаголов (verbs), которые 
распознаются ими для выполнения специальных действий, таких как передача 
внутрь контейнера глаголов, специфических для объекта,ОЬЕ, помещенного в 
контейнер. Набор глаголов, распознаваемых объектом OLE, изменяется от объекта 
к объекту, но существует стандартный набор глаголов. Для выполнения действий, 
связанных с определенным глаголом, нужно воспользоваться методом Do Verb, как 
показано ниже. 

    DoVerb(ovShow) ; 

    Этот глагол (ovShow) должен отобразить на экране сервер объекта OLE, 
находящегося в контейнере. TOleContainer распознает несколько специальных 
глаголов, которые определяют действия, выполняемые над сервером OLE. В табл. 
18.6 перечислены все глаголы, действия которых могут выполняться с помощью 
метода DoVerb. 

    Таблица 18.6. Специальные глаголы OLE 

    Глагол                Выполняемое действие 

    ovPrimary	Активизирует интерфейс пользователя, используемый при 
активизировании по месту (in-place User Interface) 
    ovOpen	Открывает сервер OLE в отдельном окне 
    ovShow	Пытается выполнить глагол ovPrimary. Если это сделать не удается, 
то контейнер OLE выполняет глагол ovOpen 
    ovHide	Если объект активизирован по месту, то полностью деактивизирует 
объект. В остальных случаях скрывает окно сервера OLE 
    ovUIActivate	Активизирует используемый по месту интерфейс пользователя 
сервера OLE 
    ovInPlaceActivate	Активизирует сервер OLE по месту. При этом интерфейс 
пользователя не активизируется 
    ovDiscardUndoState	Сервер удаляет всю накопленную информацию об отмене 
действий (undo information) 
    
    Эти глаголы определены компанией Microsoft, и каждый сервер OLE должен 
распознавать их, но в разных приложениях перечисленные глаголы могут 
использоваться по-разному. Глаголы ovShow и ovHide дополняют один другого — 
глагол ovShow делает объект' видимым, а ovHide скрывает объект. 
    В Delphi используются только глаголы ovShow и ovOpen. Когда используется 
глагол ovPrimary, то на самом деле выполняется глагол с индексом 0 (нуль). Для 
большинства серверов OLE индекс 0 (нуль) имеет глагол Open. Если выполняется 
глагол оуРгГтагу, то сервер объекта OLE запустится в отдельном окне, но если 
этот глагол выполняется контейнером OLE, то сервер будет отображаться в контейнере. 

    Procedure TFormI.LoadDocumentEmbedded; 
    begin 
    // Встраивание документа в контейнер. 
    ТОС.CreateObjectFromFile('test.doc', false); 


    424      Часть V. Работа с OLE 


    if TOC.State <> osInPlaceActive then 
    TOC.DoVerb(ovOpen); // Загрузка Word вне Delphi. 
    end; // TFormI.LoadDocumentEmbedded 

    Delphi позволяет определять состояние, в котором в текущий момент 
находится контейнер. В табл. 18.7 перечислены определенные компанией Microsoft 
константы для обозначения состояний. 

    Константа состояния   Описание 

    osEmpty              g контейнере нет объекта 
    os Loaded              Некоторая часть кода объекта, находящегося внутри 
выполняющегося процесса (in-process), загружена в область приложения. Это не 
означает, что загружен сервер объекта. Область 
    TOleContainer остается пустой 
    05Running            Сервер объекта OLE полностью загружен и активен. 
Пользовательский интерфейс создан, но не виден конечному пользователю. Сервер 
OLE выполняется в отдельном окне. В это состояние объект OLE можно перевести с 
помощью метода RUN 
    osOpen                Интерфейс пользователя активизирован 
    osInPlaceActive     Объект имеет собственное окно внутри контейнера 
TOleContainer. Этот объект может обрабатывать события мыши и перерисовывать 
самого себя 
    osUIActive           Интерфейс пользователя отображен на экране, 
следовательно, через TOleContainer в форме можно получить доступ к серверу OLE 

    Глаголы (verbs) — это действия, которые может выполнять объект OLE. Их 
можно применять и к встроенным или связанным объектам. Например, Word 
распознает два глагола: Open и Edit. Следовательно, выполнение глагола Open 
приведет к активизированию объекта Word в контейнере. Все глаголы, 
распознаваемые объектом, можно отыскать с помощью программы REGEDIT.EXE. Все 
глаголы, которые распознает приложение Paint, "можно" найти в ключе 
HKEY_CLASSES_ROOT\Paint.Picture\Protocol\StdFileEditing\verb. Единственный 
глагол, который распознает приложение Paint, — это Edit. 
    Все глаголы объекта OLE можно найти и во время выполнения программы. Все 
глаголы объекта можно добавить в раскрывающееся меню Verb с помощью показанной 
ниже функции. 

    // Примечание. Необходимо наличие компонентов 
    // TOleContainer и TMainMenu в форме Formi. 
    function TFormI.AddVerbs; 
    var 
    I: integer; 
    Temp: TMenuItem; 
    begin 
    // Проверка присутствия меню Verb. 
    // Удаление всех элементов меню Verb. 
    With MainMenul do begin 
    For I := 0 to Items.Count -1 do 
    if MainMenul.Items[I].Caption = 'Verb' then begin 
    while Items[I].Count > 0 do begin 
    Temp := Items[I].Items[0]; 
    Items[I].Delete (0); 
    Temp.Free; 
    end; // while 
    end; // if 
    // if no verbs then exit 
    if OleContainerI.ObjectVerbs.Count = 0 then exit; 
    // Создаем пункт Verb главного меню. 
    Temp := Tmenultem.Create(self); 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   425 


    Temp.Caption := 'Verb'; 
    Items.Add(Temp) ; 
    end; // with 
    // Заполняем меню Verbs вложенными элементами. 
    With OleContainerI do 
    For I := 0 to ObjectVerbs.Count - 1 do begin 
    Temp := TMenuItem.Create(self); 
    Temp.Caption := ObjectVerbs[I]; 
    MainMenul.Items.Items[MainMenul.Items.Count -1].Add(Temp) ; 
    end; // For 
    end; // Т Form.Add Verb 5 

    Использование свойства OleObject для доступа к серверу автоматизации в 
составе сервера OLE 
    Контейнеры OLE отлично подходят для работы с другими серверами приложений, 
но время от времени необходимо выполнять некоторые операции исключительно 
программными средствами. Например, сервер документов Word не позволяет 
сохранять или печатать файлы с помощью команд меню. 
    В Delphi заложена возможность доступа к серверу автоматизации (Automation 
Server) объекта, помещенного в контейнер. Получив доступ к объекту 
автоматизации, вы можете вызывать любые методы этого объекта. 

    procedure TFormI.ButtonlClick(Sender: TObject); 
    Var V: Variant; 
    begin 
    OleContainerI.DoVerb(OLEIVERB_UIACTIVATE) ; 
    V := OleContainerI.OleObject; // Доступ к объекту OLE. 
    V := V.Application.WordBasic; // Запрос к серверу автоматизации. 
    V.Insert('Delphi becomes greater everyday') 
    end; 

    Строка Delphi becomes greater everyday должна быть вставлена в контейнер 
OLE в текущей позиции курсора. 
    Наиболее сложным при работе с серверами автоматизации является поиск 
информации о методах, поддерживаемых конкретным сервером. Некоторые версии 
Word поставляются с файлом wordbasic. hip. Аль-  тернативным источником 
информации является сеть MSDN (Microsoft Software Developer's Network), в 
которой можно найти полный список методов сервераТвтоматйзации wordbasic. 
    В приложении можно создать кнопку для создания и сохранения новых 
документов Word. Ниже показана процедура, выполняющая эти действия. 

    procedure TFormI.ButtonlClick(Sender:TObject) ; 
    var V: Variant; 
    begin 
    V := OleContainerI.OleObject.Application.WordBasic; 
    V.FileNew; 
    V.Insert ('Delphi is a temple from ' + #13); 
    V.Insert('Greek mythology'); 
    V.SaveFileAs('DelphiHistory') ; 
    end; // TFormI.ButtonlClick 


    Позиционные и именованные аргументы 

    Серверы автоматизации позволяют при вызове их методов использовать 
необязательные параметры. Ниже показан полный набор аргументов метода 
FormatFont. В таком виде этот метод представлен в справочном файле wordbasic. hip. 

    FormatFont [.Points = number] [, .Underline = number] [, .Color = number] 
    [, .Strikethrough = number] [, .Superscript = number] 
    [, .Subscript = number] [, .Shadow = number] [, .Hidden = number] 
    [, .SmallCaps = number] [, .AllCaps = number] [, .Outline = number) 
    [, .Spacing = number] [, .Position = number or text] [, .Kerning = number] 
    [, .KerningMin = number or text] [, .Default] 
    [, .Tab = number] [, .Font = text] [, .Bold = number] [, .Italic = number] 


    426                                           Часть V. Работа с OLE 

    Метод FormatFont содержит 20 необязательных параметров. Было бы мучением 
вводить двадцать аргументов при необходимости изменить всего лишь размер 
шрифта. К счастью, объекты автоматизации позволяют не беспокоиться об этом. 
Чтобы установить размер текущего шрифта равным 12 пунктам, можно 
воспользоваться следующей строкой кода. 

    V.Format Font(12); 
    А чтобы выбрать больший размер шрифта и применить атрибут подчеркивания, 
можно воспользоваться строкой кода, показанной ниже. 
    V.Format Font(40, 1) Аргументы Bold и Underline, по сути, принадлежат типу boolean. 
    • О OFF 
    т 1 ON 

    Для одновременного выбора размера шрифта и включения стиля Bold 
воспользуйтесь следующей строкой. 

    V.FormatFont(12, Bold := 1); 

    В качестве первого параметра передается значение 12, а параметру Bold 
присваивается значение 1 (включается стиль Bold). В данном случае второй 
аргумент был передан с помощью метода, называемого передача именованных 
параметров. Методы передачи параметров можно комбинировать, а можно передавать 
значения исключительно посредством именованных аргументов. 

    V.FormatFont(Bold := 1, Points := 12); 

    Эта строка кода выполняет те же действия, что и предыдущая, но здесь 
используются только именованные параметры. Порядок записи именованных 
аргументов не имеет значения, но в процедуру нужно передавать как значение 
параметра, так и его имя. Это делается путем присвоения, например Bold := 1. 
    При передаче именованных параметров используется стиль присвоения, 
являющийся по своей сути "визуально-базовым" (игра слов, основанная на прямом 
переводе названия среды разработки Visual Basic, в которой часто используются 
именованные аргументы). Но еще важнее то, что порядок аргументов не имеет 
значениями ненужные .параметры можно^ опускать. 
    Delphi передает все параметры в Word без проверки типов. Именно поэтому в 
таком строго типизированном языке, как Delphi, позволяется опускать некоторые 
параметры. Если Word не примет данных, которые ему передавались, то возникнет 
исключительная ситуация (exception). 
    Третий, и последний, метол передача „параметров — позиционный метод. При 
его использовании параметры указываются только в необходимых позициях, другие 
позиции остаются незаполненными. В показанном ниже примере устанавливается 
размер шрифта 13 пунктов и включаются стили Underline и Bold. 

    V.FormatFont(13,1,,,,,,,,,,,,,,,,, 1) ; 

    '_        При использовании позиционных параметров запятыми нужно 
обозначать пропущенные параметры, которые расположены перед последним 
указываемым параметром. Необязательные параметры, расположенные ^ за последним 
передаваемым параметром, можно игнорировать, например 

    IB., 
    V.FormatFont(13,!,,!); 

    В листинге 18.7 содержится более сложный пример форматирования. Здесь 
изменяются не только свойства шрифта. 
    Исходный код процедуры Title можно найти в файле MAINU.PAS на 
дополнительно распространяемой дискете. Эта процедура используется в программе Resume. 

    j Листинг 18.7. \UDELPHl3\CHPl8\RESUME\MAlNU. PAS. Пример форматирования 

    procedure Title(V: variant); 
    begin 
    // Выровнять заголовок по центру. 
    // Установить полужирный шрифт размером 12 пунктов. 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   427 


    V.FormatFont(Bold := 1, Points := 12); 
    V.CenterPara; 
    V.FormatParagraph(0); // Убрать отступ слева. 
    end/ // Title 


    Интерфейс /Storage 

    Вне рассмотрения остался еще один интересный метод— интерфейсный метод 
IStorage. Он используется для манипуляций хранилищами: открытия и создания 
потоков и подчиненных хранилищ. Кроме того, этот интерфейс позволяет 
перечислить содержимое хранилища, получить или установить информацию об 
элементе. Детали его использования выходят за рамки этой главы. Если вы хотите 
поглубже изучить этот интерфейс, воспользуйтесь одной из книг об интерфейсах 
OLE, например Delphi 2 Unleashed (Second Edition, Borland Press, 1996). 

    Примеры демонстрационных программ 

    Для демонстрации всех описанных методов и свойств было создано две 
программы. Первая — это приложение Resume, которое с помощью контейнера 
TOleContainer и объекта OLE Word создает документ Word. В ней 
продемонстрирован способ вызова методов объекта Word для создания 
форматированного резюме (документа Word), которое можно смело рассылать работодателям. 

    Пример №1. Построитель мини-резюме          ^ 

    Первым примером является программа, выводящая на экран форму, в которую 
пользователь должен внести информацию о себе. После этого программа RESUME 
поместит полученные данные в документ Word, который находится в контейнере 
основного окна приложения. На рис. 18.18 показано приложение Resume в процессе 
работы. Эта программа демонстрирует использование следующих возможностей. 
    
    Рис. 18.18. Приложение Resume, демонстрирующее использование интерфейса oleobject 

    • Доступ к серверам автоматизации для вызова методов документа 
программными средствами. 
    • Вставка документа Word. 
    • Выполнение приложения с активизированием по месту. 


    428                                           Часть V. Работа с OLE 


    • Использование методов FilePrint, Save и SaveAs объекта Word. 
    И Использование формы ввода персональной информации. 
    • Создание документа-резюме на основе информации, хранящейся в компонентах 
Edit и Memo. 
    • Форматирование текста в документе Word. 
    • Сохранение и загрузка документов как файлов объектов. 

    Пример №2. База данных OLE 

    Вторая демонстрационная программа называется OLEDB. В этом примере 
показаны методы копирования объектов OLE в базу данных и из нее. Приложения 
такого типа можно применять, например, для создания книги. Все, что относится 
к этой книге, включая тексты глав, рисунки и другие материалы, можно сохранить 
в небольшой базе данных для быстрого доступа к ним. На рис. 18.19 показано 
окно приложения OLEDB. В этой программе содержатся примеры использования 
перечисленных ниже возможностей. 
    
    Рис. 18.19. Приложение OLEDB, демонстрирующее возможности хранения 
объектов OLE в базе данных 
    
    Чтение/запись объектов OLE в базу данных. 
    • Использование диалоговых окон Insert Object и Paste Special в контейнере TOleContainer. 
    • Переключение значений свойств Iconic и AutoActivate для демонстрации 
возможностей этих свойств. Запись и чтение объектов OLE в базу данных Paradox. 
    • Сохранение и загрузка объектов OLE с диска. 
    Создание собственного диалогового окна Insert Dialog. 
    Получение из реестра Windows списка объектов, которые можно помещать в 
контейнер OLE. 

    Использование элементов управления ActiveX 

    Элементы ActiveX — это элементы управления, которые можно использовать в 
любой среде разработки приложений, которая поддерживает технологию ActiveX. 
Как упоминалось выше, элементы ActiveX не зависят от языка программирования. 
Следовательно, рассмотрим их использование в Delphi. 

    Вставка элементов ActiveX в палитру компонентов Delphi 

    С точки зрения пользователя, добавление элементов ActiveX в палитру 
компонентов Delphi — это пара пустяков. От пользователя требуется только 
добавить элемент управления в палитру. После вставки в палитру элементы 
ActiveX можно использовать так же, как компоненты VCL. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   429 

    Процесс установки элементов ActiveX в Delphi 3 отличается от их установки 
в предыдущих версиях. Ниже перечислены все этапы установки элементов ActiveX. 
    • Регистрация элементов ActiveX в реестре Windows. 
    • Создание файла-оболочки. 
    • Добавление файла-оболочки в пакет. 
    • Установка пакета в палитру компонентов. 
    Если вы нуждаетесь в более подробной информации о модулях, обращайтесь к 
главе 15, "Работа с пакетами". 

    на заметку 
    Ниже рассказывается об установке элементов ActiveX в Delphi. Для 
демонстрации используются элементы ActiveX, находящиеся в каталоге 
\WinNT\System32. Читатель может использовать те же элементы или установить 
какие-либо другие элементы ActiveX. 

    В описании процесса установки элементов ActiveX предполагается, что 
соответствующий модуль еще не создан. В противном случае нужно использовать 
только пп. 4-10 и 13. Некоторые рисунки могут слегка от-  личаться от тех, 
которые появляются на экране вашего компьютера. 
    Для установки элементов ActiveX в палитре компонентов выполните следующие действия. 
    1. Прежде всего, создайте модуль, в который будут добавляться элементы 
ActiveX. Выберите команду File^New, и на экране появится диалоговое окно, 
показанное на рис. 18.20. Выберите в нем пиктограмму Package и щелкните на 
кнопке ОК. На экране появится диалоговое окно New Package. В поле File Name 
введена строка "test", а в поле Description — краткое описание модуля (рис. 
18.21). После ввода имени файла и описания модуля щелкните на кнопке ОК. 
    
    Рис. 18,20. Диалоговое окно New Items. В нем можно выбрать элемент, с 
которого вы начнете создание своего приложения 

    Рис. 18.21. Диалоговое окно New Package, испсльзуемое для ввода имени модуля 

    2. На экране появится новое диалоговое окно, показанное на рис. 18.22. Мы 
создали пустой модуль. В этот модуль можно вставлять элементы ActiveX. 
Щелкните на кнопке Add (на ней изображен знак "+"). 
    3. Откроется диалоговое окно Add (рис. 18.23). Поскольку импортируется 
элемент ActiveX, нужно выбрать вкладку Import ActiveX. 
    4. Теперь ваше диалоговое окно Add должно быть похоже на окно, показанное 
на рис. 18.24. Это окно разделено на две части. В верхней его части расположен 
список всех зарегистрированных в Windows элементов управления ActiveX. Из него 
можно добавлять элементы в системный реестр и удалять их из реестра. Нижняя 
часть диалогового окна позволяет выбрать способ создания оболочки (wrapper) 
Delphi для выбранного элемента ActiveX. 

    430                                           Часть V. Работа с OLE 


    Рис. 18.22. Диалоговое окно управления модулем                    

    Рис. 18.23. Диалоговое окно Add, которое используется для вставки элементов 
ActiveX в Delphi 

    5. Если элемент управления, который нужно вставить в Delphi, указан в 
списке в верхней части окна, то можно перейти к п. 6. В противном случае 
элемент управления нужно сначала зарегистрировать. Для этого щелкните на 
кнопке Add, и на экране появится диалоговое окно Register OLE Control (рис. 
18.25). Выберите файл элемента ActiveX, который нужно установить, и щелкните 
на кнопке Open. Элемент управления будет зарегистрирован в системном реестре, 
и диалоговое окно Register OLE Control исчезнет с экрана. Здесь 
зарегистрирован элемент Hours . Осх, хотя в вашем компьютере этого элемента 
может не быть. 

    Рис. 18.24. Вкладка Import ActiveX диалогового окна Add             

    Рис. 18.25. Диалоговое окно Register OLE Control 

    6. Просмотрите список зарегистрированных элементов в верхней части вкладки 
Import ActiveX и выберите нужный элемент ActiveX (рис. 18.26). Теперь 
проверьте значения элементов в нижней части диалогового окна. С помощью этих 
элементов можно управлять способом вставки элемента ActiveX в палитру 
компонентов. В элементе Class Name показаны имена классов элементов управления 
OLE, которые находятся в выбранной библиотеке OLE. Другие библиотеки OLE могут 
использовать указанные классы, следовательно, нет причин изменять предлагаемые 
имена классов. Если вы все же решились изменить имена классов, то в 
соответствии с соглашениями о именовании начинать имена классов нужно с 
большой латинской буквы Т. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   431 

    7. Список Page Palette позволяет выбрать страницу палитры компонентов, в 
которую будет помещен выбранный элемент ActiveX. По умолчанию все элементы 
ActiveX помещаются на страницу ActiveX, но можно выбрать любую из существующих 
или, при желании, создать новую. 
    8. В поле Unit file name указан путь к файлу оболочки, которую Delphi 
создает в качестве интерфейса в элементе Ас-. tiveX. По умолчанию оболочка 
создается в том же каталоге, в котором находится файл элемента ActiveX. 
Заметьте, что файл оболочки имеет то же имя, что и элемент ActiveX, а 
расширение файла — РАЗ. 
    9. В поле Search Path указан путь к каталогам, в которых Delphi ищет файлы 
в процессе компиляции. 
    10. Обычно очень редко возникает необходимость изменять значения элементов 
в нижней части вкладки Import ActiveX. 
    Если вы все-таки внесли изменения в элементы в нижней части вкладки Import 
ActiveX, щелкните на кнопке ОК. (Если вы совершили ошибку при добавлении 
элемента ActiveX, щелкните на кнопке Cancel для отмены внесенных изменений.) 
    Delphi создаст оболочку для элемента AclivcX, и этот элемент можно будет 
использовать в Delphi. 

    Рис. 18.26. Вкладка Import ActiveX с выбранным элементом ActiveX 

    Рис. 18.27. Диалоговое окно Package с установленным элементом ActiveX 

    11. Теперь вы вернетесь в диалоговое окно Package, как показано на рис. 
18.27. Созданный пакет нужно сохранить и скомпилировать. Щелкните на кнопке 
Build. Когда Delphi закончит работу, нужно установить созданный пакет. Для 
этого щелкните на кнопке Install. Если все прошло согласно плану, то на экране 
появится сообщение, подобное показанному на рис. 18.28. 

    Рис. 18.28. Сообщение, подтверждающее корректность установки пакета Test.dpI 

    12. Если дважды щелкнуть на элементе ActiveX в диалоговом окне Package 
(см, рис. 18.27), то откроется окно редактора, в котором находится исходный 
код оболочки элемента ActiveX. После выполненных действий в палитре 
компонентов должен появиться элемент ActiveX. 
    В следующем разделе файл оболочки будет исследован более детально. 

    432                                           Часть V. Работа с OLE 


    Оболочка OLE 

    Оболочка элемента ActiveX представляет собой стандартный модуль, который 
можно использовать в проекте приложения. Фактически оболочка похожа на модуль 
стандартного компонента Delphi. 
    Имя модуля должно совпадать с именем элемента ActiveX (в рассмотренном 
примере имя модуля — axHours). Префикс ах добавлен к имени для обозначения 
модуля — оболочки элемента ActiveX. 
    В начале модуля иногда создается группа комментариев, называемая журналом 
конвертирования (conversion log). Если при создании модуля-оболочки возникли 
какие-либо ошибки, то информация о них вставляется именно в журнал 
конвертирования. Чаще всего возникает конфликт имен между именем элемента 
ActiveX и зарезервированными словами. В этом случае Delphi автоматически 
немного изменяет имя элемента ActiveX и помещает запись об изменениях в журнал конвертирования. 
    Для всех компонентов и оболочек необходимо использовать классы. Все 
оболочки элементов ActiveX порождаются классом TOleControl. Класс Telecontrol 
является "хранителем" дескриптора окна. Он наследован от класса TwinControl. 
Telecontrol используется в Delphi для обеспечения корректной работы элементов ActiveX. 

    Методы 

    Единственным методом модуля-оболочки является InitControlData, 
переопределяющий одноименный метод абстрактного класса Telecontrol. Метод 
InitControlData присваивает классу уникальный идентификатор класса и 
уникальные идентификаторы событий. Кроме того, он выполняет специфические 
действия по инициализации объекта. Это защищенный метод класса, так как вне 
класса от него нет никакой пользы. 
    В данном случае элемент управления Hours . осх не предоставляет метода 
AboutBox, но большинство элементов ActiveX включается этим методом. Метод 
AboutBox выводит на экран диалоговое окно About с информацией об элементе 
управления ActiveX. Когда вызывается метод оболочки, такой как AboutBox, 
происходит вызов метода InvokeMethod класса TOleControl. Метод InvokeMethod не 
выполняет прямого вызова метода элемента ActiveX, вместо этого в InvokeMethod 
используется автоматизация OLE для вызова указанного метода. 

    Свойства 

    Свойства оболочки можно разделить на две группы. К первой относятся 
свойства, значения read и write которых не указаны. Это стандартные свойства, 
унаследованные от классов TWinControl и TComponent. 
    Все свойства, которые принадлежат элементу ActiveX, можно найти, учитывая, 
что каждое такое свойство имеет индекс и для него указаны методы get и set. С 
помощью специальных методов get и set в Delphi размывается граница между 
свойствами элемента ActiveX и свойствами стандартных компонентов Delphi. 
    В модуле оболочки нет ничего сложного. Самое интересное сосредоточено в 
методе InitControlData. Delphi выполняет большую работу, превращая с помощью 
оболочек (wrapper) такие сложные механизмы, как элементы управления ActiveX, в 
нечто простое и легко используемое. 

    Файл оболочки 

    Ниже показан исходный код оболочки, созданной для элемента HOURS . ОСХ. 
Этот элемент управления был помещен в палитру компонентов в предыдущем примере. 

    unit axhours; 
    interface 
    uses 01e21, Classes, Graphics, OleCtrls; 
    type 
    THours = class(TOleControl) 
    private 
    protected 
    procedure InitControlData; override; 
    public 
    published 
    property TabStop; 
    property DragCursor; 
    property DragMode; 
    property ParentShowHint; 
    property PopupMenu; 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   433 


    property ShowHint; 
    property TabOrder; 
    property Visible; 
    property OnDragDrop; 
    property OnDragOver; 
    property OnEndDrag; 
    property OnEnter; 
    property OnExit; 
    property OnStartDrag; 
    property crPermitColor: TColor index 1 
    read GetColorProp 
    write SetColorProp stored Falser
    property crDenyColor: TColor index 2 
    read GetColorProp 
    write SetColorProp stored Falser
    property DateData; Variant index 3 
    read GetVariantProp 
    write SetVariantProp stored False; 
    end; 
    procedure Registers
    implementation 
    <$J+) 
    procedure THours.InitControlData; 
    const 
    CControlData: TControlData = ( 
    Class ID: (D1:$A44EA7AD;D2:$9D58;D3:$11CF;D4:($A3,$5F,$00,$AA,$00,$B6,$74,$3B)); 
    EventIID: (D1:$A44EA7AC;D2:$9D58;D3:$11CF;D4:($A3,$5F,$00,$AA,$00,$B6,$74,$3B)); 
    EventCount: 0; 
    EventDispIDs: nil; 
    LicenseKey: nil; 
    Flags: $00000000); 
    begin 
    ControlData := @CControlData; 
    end; 
    procedure Register; 
    begin 
    RegisterComponents('OCX', [THours]) ; 
    end; 
    end. 


    Использование элементов управления ActiveX в приложениях 

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

    Вызов методов 

    Вызывать методы компонента ActiveX довольно просто. В основном все 
разработчики элементов управления ActiveX вместе с библиотеками поставляют 
справочные файлы, в которых описано все, что можно делать с полученным 
объектом OLE. Список методов и их параметров можно получить через интерфейс 
IDispatch, но описание интерфейса IDispatch выходит за рамки этой главы. 
    'Чтобы вызвать метод установки соединения компонента ActiveX FTP, который 
поставляется вместе с Delphi, нужно просто вызвать его, как стандартный 
компонент Delphi. 
    Например, используя Internet Control Pack, можно вызвать метод Connect с 
помощью строки кода, показанной ниже. 
    FTP1.Connect(RemoteHost, RemotePort) ; 


    434                                           Часть V. Работа с OLE 


    Я создал демонстрационную программу, в которой показал, как использовать 
элемент ActivcX, проверяющий правописание. Этот элемент можно найти на 
странице ActiveX палитры компонентов Delphi. Программа хранит вопросы и ответы 
в таблице базы данных. Кроме того, в этой программе с помощью элемента Spell 
Checking выполняется проверка орфографии. Моя программа называется QA и ее 
можно найти на дополнительно распространяемой дискете в каталоге \UDELPHI\CHP18\QA. 
    В рассматриваемой программе реальную работу выполняет процедура 
SpellCheckDBMemo. Для передачи данных из элемента управления в форме и в него 
используется буфер. Сначала содержимое бу4>ера передается свойству text. 
используемому для передачи и получения проверяемого текста. Затем в свойстве 
CheckText отмечается текст, который нужно проверить, и запускается сеанс 
проверки орфографии. 
    После проверки свойство Text используется для получения проверенного 
текста, который сохраняется в таблице в поле типа Memo (листинг 18.8). 

    Листинг 18.8. \UDELPHI3\CHP18\QA\QAEditU. PAS. Процедура SpellCheckDBMemo 
procedure TDataChangeForm.SpellBtnClick(Sender: TObject); 

    procedure SpellCheckDBMemo(var TheDBMemo: TDBMemo); 
    var 
    buf: PChar; 
    SizeOfBuf: word; 
    begin 
    SizeOfBuf := succ(TheDBMemo.GetTextLen);  (add 1 for the null terminator} 
    buf := AllocMem(SizeOfBuf); 
    TheDBMemo.GetTextBuf(buf, SizeOfBuf) ; 
    VCSpellerl.Text:= Buf; 
    VCSpellerl.CheckText:= Buf; 
    TheDBMemo.SetTextBuf(PChar(VCSpellerl.Text)) ; 
    FreeMemfbuf, SizeOfBuf); 
    end; 
    ( MAIN SpellBtnClick } 
    begin 
    Forml.Tablel.Edit; 
    SpellCheckDBMemo(DBQues) ; 
    SpellCheckDBMemo(DBAns) ; 
    ShowMessage('Spell Check Complete.'); 
    end; // TDataChangeForm.SpellBtnClick 


    Передача необязательных параметров 

    Некоторые элементы ActiveX принимают переменное количество параметров. И 
хотя для элемента ActiveX Delphi создает оболочку на языке Pascal, который 
требует указания всех параметров, необязательные параметры использовать можнд; 
    Для этого ненужным параметрам присваивается значение Unassigned или 
значение VT_EMPTY типа Variant. Использование этих возможностей показано ниже. 

    var V: Variant; 
    begin 
    V = Unassigned; 
    OCX1.Method('Imagel.bmp', V, V, V, Read); 
    end; 

    Переменной типа Variant можно присвоить значение VT_EMPTY и вызвать метод 
компонента ActiveX, как показано ниже. 

    var V: Variant; 
    begin 


    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   435 


    V = VT_EMPTY; 
    OCX1.Method('Image 1.bmp', V, V, V, Read); 
    end; 

    Иногда объекты OLE вместо значений VT_EMPTY или Unassigned ожидают 
специальных значений типа Variant, например VT_ERROR. В таком случае можно 
воспользоваться следующим приемом. 

    33MG"Ky 
    var V: Variant; 
    begin TVarRec(V).VType := VT_ERROR; 
    OCX1.Method(21, V, V) ; 


    Использование свойства OleObject 

    Использование свойства OleObject задействует те же механизмы передачи 
параметров, которые используются для переменных типа Variant. Более подробную 
информацию о свойстве OleObject можно получить в разделах "Использование 
свойства OleObject для доступа к серверу автоматизации в составе сервера OLE" 
и "Позиционные и именованные аргументы". 

    procedure TFormI.ChartlClick; 
    var 
    V: Variant; 
    begin 
    V := SimpleActiveX.OleObject; 
    V. Method ('A' , , 'C' ) ; 
    end; // TForml.ChartlClick 

    Свойство OleObject возвращает интерфейс IDispatch сервера автоматизации. 
Этот интерфейс можно использовать для прямого вызова методов элемента ActiveX, 
что позволяет избежать строгой проверки типов в Delphi. 

    Распространение приложений с элементами ActiveX 

    На рынке существует множество продуктов, позволяющих легко распространять 
приложения с элементами управления ActiveX. Регистрация элементов ActiveX в 
реестре — это самая утомительная работа в процессе распространения таких программ. 

    Регистрация элементов управления ActiveX 

    Приложения Installshield и WISE могут значительно упростить 
распространение элементов управления ActiveX. Оба приложения являются 
коммерческими продуктами, но версия приложения Installshield входит в поставку 
Delphi. Это облегчит распространение ваших программ. 
    Для желающих знать, что же происходит при распространении программ с 
элементами управления ActiveX, ниже приведено краткое описание этого процесса. 
    Прежде всего, на выбранный для установки приложения компьютер нужно 
скопировать все необходимые файлы, включая связанные с приложением 
динамические библиотеки (DLL) и регистрационные файлы (REG). Заметьте, что на 
выбранный компьютер нужно скопировать и файлы соглашений об использовании 
элементов ActiveX (файл с расширением LIC). Файл соглашения об использовании 
содержит лицензионный ключ. Информацию об условиях использования элемента 
управления ActiveX можно получить через интерфейс IClassFactory2. Кроме того, 
для добавления информации об элементе ActiveX в реестр понадобится программа 
REGSVR32 . ЕХЕ. 

    Резюме 

    Как уже упоминалось, на дополнительно распространяемой дискете в каталоге 
\UDELPHI\CHP18\QA можнайти полный исходный код программы QA. Она демонстрирует 
применение элемента ActiveX, проверяющего правописание. 

    436                                           Часть V. Работа с OLE 


    Рис. 18.29. Приложение QA, демонстрирующее использование элементов ActiveX 

    Приложение QA — это простая программа вопросов и ответов. Сначала она 
показывает на экране вопрос, а затем (после щелчка на кнопке) — ответ (рис. 
18.29). Вы можете перемещаться по списку вопросов, а также добавлять новые 
вопросы и редактировать или удалять существующие. Команды Edit и Add меню Data 
выводят на экран вторую форму приложения, в которой можно создавать новые 
вопросы и ответы или редактировать существующие. Эта форма снабжена кнопкой 
Spell Check для проверки орфографии вопросов и ответов. Проверка выполняется с 
помощью элемента ActiveX для проверки правописания. 

    Глава 18. Работа с OLE, серверы документов и элементы управления ActiveX   437 
