    Глава 7. СОМ и создание клиентов ActiveX	153 

    Глава 7.   СОМ и создание клиентов ActiveX 

    Компонентная Объектная Модель (СОМ) — архитектура промышленного стандарта 
для объектно-ориентированной разработки приложений и основа для формирования 
компонентов ActiveX. Компонент ActiveX — физический файл (например, .exe, 
.dll, .ocx), который содержит классы, представляющие определения объектов. Эти 
объекты можно подключать и использовать в приложении Visual Basic. Компоненты 
ActiveX позволяют программистам объединять в приложении порции кода 
многократного использования. 
    Для решения общих задач, таких, как числовой анализ или формирование 
элементов пользовательского интерфейса, разработчик может создавать свои 
собственные компоненты ActiveX или использовать подключаемые компоненты 
Microsoft или сторонних разработчиков. При создании в приложении 
пользовательских решений можно объединять компоненты ActiveX с общими компонентами. 
    Эта глава — первая из четырех глав, в которых показывается, как 
реализовать ActiveX-компонентные приложения, используя встроенные возможности 
Visual Basic. В этой главе рассматривается сторона клиента, в следующих трех 
главах освещаются различные реали-' зации на сервере.	~" ~ 

    7.1. Компонентная Объектная Модель 

    Для формирования эффективных современных приложений-клиентов требуется 
иметь представление относительно компонентов сервера, используемых клиентом; 
требуется также понимание базовой технологии СОМ, посредством которой клиент 
соединяется с этими компонентами. С СОМ связаны два различных аспекта. 
Во-первых, спецификация СОМ обеспечивает определение (или модёль7для~объекта. 
Во-вторых, СОМ обеспечивает возможности для создания объектов и организации 
связи между клиентом и сервером. 
    В этом разделе предлагается краткий обзор СОМ — мощного дополнения к 
комплекту инструментальных средств разработчика. Здесь описываются 
умолчательные интерфейсы, обеспечиваемые объектами СОМ, показывается, как 
объекты поддерживают связь с клиентами и как использовать клиенты при создании 
и использовании экземпляра объекта. Для лучшего понимания СОМ полезно 
ознакомиться со следующими терминами и определениями: 
    Компонент — единица исполняемого кода, которая предоставляет некоторые 
функциональные возможности. Компоненты обеспечиваются серверами, которые 
представлены файлами .exe, .dll или .осх. Серверы могут быть 
построейьТйэГодного или больше компонентов; компоненты обеспечивают шаблоны, 
из которых^а^елмср^даюхдя^ объекты. Компонентная Объектная Модель определяет, 
как компоненты создаются и как приложения-клиенты соединяютсяГс компонентами. 
СОМ также обрабатывает запросы из приложений-клиентов на создание 
объектов.
    Объект — комбинация кода и данных, которые могут обрабатываться как 
единица. Объект имеет период существования, то есть он создается и разрушается. 
    Автоматика — часть спецификации СОМ, которая определяет стандартную 
методику создания компонентов и использования объектов. 
    Объект Автоматики — объект, который предоставлен другим приложением или 
инструментальным средством программирования через интерфейсы Автоматики. 
Объекты Автоматики также известны как программируемые объекты. Программируемый 
объект может управляться программным способом посредством его методов и 
свойств (интерфейс объекта). 


    154	Компонентная Объектная Модель! 

    Разработчику приложения-клиента объект предоставляет возможность ввода 
информации) или запроса и обеспечивает вывод, но внутренняя организация 
объекта разработчи недоступна. Разработчики должны лишь понимать, как 
использовать предоставляемы объектом функциональные возможности. Эти 
функциональные возможности предоставля-' ются через один или несколько 
интерфейсов. Интерфейсы — средства (свойства и мето ды), посредством которых 
приложения-клиенты сообщаются с компонентом. 

    7.1.1. Краткая история СОМ 

    Целью разработки идеологии СОМ было сделать приложения более 
настраиваемым/ и гибкими, причем главной задачей была поддержка концепции, 
известной как связыванием внедрение объектов. Идея состояла в том, чтобы 
получать документ-ориентированное приложение, работая в котором, например, 
можно было бы редактировать электронную таблицу из текстового процессора. 
Версия Microsoft технологии связывания и внедрения объектов называется OLE. В 
первой версией OLE для поддержания связи между клиентом и компонентом 
использовалось нечто, именуемое DDE (Dynamic Data Exchange — динами-е-ский 
обмен данными). В OLE 1 ни о какой СОМ "рТ5чи не шло. DDE был сформирован на 
верхнем уровне архитектуры передачи сообщений Windows. Технология DDE была 
далека от совершенства. DDE работает медленно и недостаточно гибко._К?Оме 
jorpjjByflHp написать код_для_ррЕ, который работает правильно. Эти серьезные 
недостатки свидетельство-"валй о том, что поиски должньГбыть продолжены. 
    Решением было СОМ. СОМ меньше по ресурсам, работает быстрее, значительно 
более устойчивая и гибкая чем DDE. Во второй версии OLE было модернизировано с 
использо&з-нием^СОМ вместо DDE. Однако OLE было первой системой, разработанной 
на базе СО'1 В OLE; нё^реализова1но"все то, что может обеспечить COM. OLJE 
имеет репутацию систег.-=1. "также работающей медленно и сложной в 
программировании. Впрочем, причина этих проблем — в реализации OLE, это не 
результат использования СОМ. 
    Все же следует помнить, что в OLE сделана попытка реализовать многие 
прежде недост. п-ные возможности. Посредством OLE можно помещать изображение 
из графической программы одного разработчика в текстовый процессор другого 
разработчика и редактировав его, не покидая текстовый процессор. Протокол OLE 
определяет многофункциональн ю связь между клиентом и компонентом. Компонент 
может многое, а приложение-клиент должно быть к этому готово. Это, однако, 
делает OLE очень трудным в программирован!';' 
    СОМ — не компьютерный язык и не конкурирует с ними. Рассуждения 
относительно то;о что лучше: C++ или СОМ или наоборот, не имеет никакого 
смысла, так как перед СОМ и С -->• стоят разные задачи. СОМ сообщает 
программисту, как строить компоненты, и программист ^свободен в выборе .языка, 
на котором он будет писать компоненты. Часто компоненты пишутся на C++. 
Сегодня это позволяет делать и Visual Basic. 

    7.1.2. Компонентные приложения 

    Исполняемая часть приложения часто состоит из единственного монолитного 
двоичного файла. После того как компилятор генерирует приложение, оно не 
изменяется, пока не будет скомпилирована следующая версия. Изменения в 
операционных системах, аппаратных средствах и желаниях заказчика вынуждают 
разработчика вносить изменения и перекомпилировать приложение. В этих условиях 
разработчики должны искать способы продлить период существования уже созданных 
приложений. Решение состоит в том, чтобы разбить монолитное приложение на 
отдельные части, или компоненты (см. рис. 7.1.). 
    По мере совершенствования технологий новые компоненты могут заменять 
существующие компоненты, формирующие приложение. Приложение — более не 
статичный объект, оно может развиваться с появлением более эффективных 
компонентов. Более того, из существующих компонентов может быть быстро 
построено полностью новое приложение. 


    Глава 7. СОМ и создание клиентов ActiveX 155 


    Монолитное приложение 
    Компонентное приложение 
    Компонент А		Компонент В 
    Компонент С		Компонент D 

    Рис. 7.1. Разбиение монолитного приложения на компоненты позволяет 
упростить модернизацию приложения. 

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

    Компонентное приложение 
    Компонент А		Компонент В 
    
    
    Компонент С		Новый  I Компонент D| 
    
    
    Рис. 7.2. Замена старого компонента новым, улучшенным компонентом. 


    7.1.3. Облегчение настройки приложения 

    Пользователи часто хотят иметь возможность настраивать приложение под свои 
потребности и вкусы. В случае монолитного приложения конечный пользователь 
должен все время общаться с программистом, давая ему заявки на реализацию того 
или иного пользовательского решения. Компонентные архитектуры облегчают 
настройку приложения, так как каждый компонент может быть заменен на другой, 
который лучше удовлетворяет потребностям пользователя. 
    Предположим, что имеются компоненты, основанные на графических редакторах 
Paint и Photo Shop. На рис. 7.3 Пользователь 1 сконфигурировал приложение, 
чтобы использовать Paint, в то время как Пользователь 2 предпочитает Photo 
Shop. Приложение может быть легко настроено добавлением новых компонентов или 
изменением существующих компонентов. 

    Пользователь 1 
    Пользователь 2 
    Компонент А	^	Компонент В Ь 
    
    Компонент С		Компонент D 
    |             Редактор Paint            | 
    : -*Э8 
    я 1 Компонент А		Компонент В 
    Компонент С		Компонент D 
    
    |       Редактор Photo Shop      | 

    Рис. 7.3. Формирование приложения из компонентов облегчает настройку. 


    156 Компонентная Объектная Modem 


    7.1.4. Библиотеки компонентов 

    Одно из больших преимуществ компонентной архитектуры — быстрая разработка 
приложи ния. СОМ позволяет выбирать компоненты из библиотеки компонентов и 
складывать вместе при формировании приложения, подобно строительным блокам. 

    Библиотека компонентов 
    Новое приложение 
    1 

    Рис. 7.4. Компоненты могут быть собраны в библиотеки, из которых 
разработчик может быстро создать приложение. 

    Построение приложений из стандартных частей долгое время было 
неосуществимой ме той разработчиков программного обеспечения. Однако с 
появлением элементов управ ния   ActiveX,   ранее   называвшихся   элементами  
 управления   OLE,   "процесс   пошел".| Программисты на Visual Basic, С, C++ 
и Java могут использовать преимущества элементов управления ActiveX для 
ускорения разработки своих приложений и Web-страниц. В прило жениях, конечно, 
потребуется создавать также некоторые пользовательские компонент-однако 
большая часть приложения может быть сформирована с использованием станд= тных компонентов. 

    7.1.5. Распределенные компоненты 

    С увеличением пропускной способности сетей и роли сетевых технологий 
потребность в приложениях, составленных из частей, доступных в сетевой 
системе, будет возрастать Компонентная архитектура помогает упростить процесс 
разработки таких распределенных приложений. Эта архитектура уже реализуется в 
приложениях клиент/сервер, которые разделяются на две части: часть клиента и 
часть сервера. 
    Создание распределенного приложения из существующего приложения 
упрощается, если существующее приложение сформировано из компонентов. 
Во-первых, приложение уже разделено на функциональные части, которые могут 
быть размещены дистанционно. Во-вторых, так как компоненты мобильны, можно 
заменить один компонент другим компонентом, который имеет единственную задачу 
— взаимодействовать с компонентом размещенным дистанционно. 
    Например, на рис. 7.5 Компонент С и Компонент D размещены на разных 
удаленных машинах сети. На локальной машине они были заменены двумя новыми 
компонентами: Транслятор С и Транслятор D. Эти новые компоненты адресуют 
запросы из других компонентов по сети к Компоненту С и Компоненту D. 
Приложение на локальной машине не заботит то, что реальные компоненты 
размещены дистанционно. Аналогично, сами удаленные компоненты также не 
беспокоит их дистанционное размещение. Если имеется транслирующий компонент, 
приложение может быть полностью не осведомлено о том, где фактически размещен компонент. 


    Глава 7. СОМ и создание клиентов ActiveX     157 


    Локальная машина 
    1 Компонент А		,., — ._.„..,, Транслятор С 
    
    
    Компонент В		Транслятор D 
    
    
    Компонент Е 
    Удаленная машина 1 

    Рис. 7.5. Компонентное приложение с удаленными компонентами. 


    7.1.6. Требования к компонентам 

    Преимущества использования компонентов непосредственно вытекают из их 
способности динамически подключаться и отключаться из приложения. Для 
достижения этой возможности компоненты должны отвечать двум требованиям. 
Во-первых, компоненты должны обеспечить возможность динамической компоновки. 
Во-вторых, компоненты должны скрывать (или инкапсулировать) подробности их 
реализации. Определить, какое требование является более важным, — значит 
решать проблему яйца и курицы. Каждое требование зависит от другого. Можно 
остановиться на таком определении: динамическая компоновка — определяющее 
требование для компонента, а скрывание информации — необходимое условие для 
динамической компоновки. Ниже эти два требования исследуются более подробно. 

    7.1.7. Динамическая компоновка 

    Для понимания важности динамической компоновки можно представить себе 
приложение, сформированное из компонентов, которые не могут связываться в 
период выполнения. Если нужно изменить один из компонентов в системе, 
потребуется статически повторно скомпоновать или перекомпилировать программу и 
затем перераспределить ее. Разработчик не может ожидать, что конечные 
пользователи его приложения смогут повторно скомпоновать и скомпилировать 
приложение самостоятельно. Даже если бы они знали, как это делать, у них, 
наиболее вероятно, He^pj^as^gc^bjj^e^yjjy^roj^M^Qi^jo^ Приложение, созданное 
из компонентов, которые должны стат11ч^|^ите^кр^щи/]иро_ваться каждый раз при 
необходимости внести изменения, эквивалентно монолитному приложеТшю. 

    7.1.8. Инкапсуляция 

    Почему динамическая компоновка требует инкапсуляции? При формировании 
приложения компоненты соединяются друг с другом. Если требуется заменить 
компонент на новый компонент, необходимо отключить старый компонент от системы 
и затем подключить новый. Новый компонент должен подключаться тем же самым 
способом, что и старый компонент, иначе потребуется переписать код, 
перекомпилировать или повторно скомпоновать эти компоненты. В данном случае не 
имеет значения, поддерживают ли компоненты и приложение динамическую связь. 
Если изменяется способ соединения компонента с другими компонентами, 
нарушается система компонентов и, по крайней мере, придется перекомпилировать, 
если не переписать приложение. 
    Для понимания, как все это связано с инкапсуляцией, нужно ввести некоторые 
определения. Программа или компонент, который использует другой компонент, 
называется клиентом. Клиент соединен с компонентом через интерфейс. Если 
компонент изменяется без изменения интерфейса, для клиента ничего не должно 
измениться. Аналогично, если изменяется клиент без изменения интерфейса, 
компонент не должен изменяться. Однако, если при изменении или компонента, или 
клиента изменяется интерфейс, другая сторона интерфейса также должна измениться. 


    158 Компонентная Объектная Модель      

    Следовательно, чтобы использовать преимущества динамической компоновки, 
компоненты и клиенты должны^стремиться не изменять их интерфейсы. Они должны 
быть скрыты. ПодробностйГотносительно того, как реализованы 'клиент и 
компонент, не должны быт отражены в интерфейсе. Чем больше интерфейс 
изолирован от подробностей реализации, тем меньше вероятность того, что в 
результате изменения клиента или компонента изм( нится интерфейс. Если 
интерфейс не изменяется, изменение компонента не будет име никакого эффекта 
для остальной части приложения. 
    Изоляция клиента от реализации компонента накладывает на компонент 
некоторые важные ограничения: 
    1. Компонент должен скрыть компыотерный_язык, используемый для его 
реализации. Любое приложение— клиент должно иметь возможность использовать 
любой компонент независимо OTjcoMnbioTepHoro языка, на котором написано 
приложение или компонент "Ориентация""на как^йТпй5о~языТГм6жет создать новые 
зависимости между клиентом ,< компонентом. Это также обусловит трудности в 
дальнейшей эксплуатации клиента / компонента в случае перехода разработчиков 
на новые языки программирования: новые компоненты нельзя будет подключить к 
приложению для его модернизации. 
    2. Компоненты должны поставляться в двоичной форме. Так как компоненты 
должны скрь-вать язык их реализации, они должны предоставляться в 
скомпилированном, скомпонованном и готовом к использованию виде. 
    3. Компоненты должны быть расширяемы без влияний на существующих 
пользователей Новые версии компонента должны работать как со старой, так и с 
новой версиями приложения-клиента.	".——.—.— ..---.., -._ 
    Установка новой версии компонента не должна нарушать приложение, которое 
использует старый компонент. Например, на рис. 7.6 старое приложение 
использует новь^ Компонент D точно так же, как новое приложение. 

    Старое приложение 
    я Старый Компонент А	I	Старый          ;, Компонент В | 
    
    
    Старый Компонент С		Новый Компонент D 
    Новое приложение 
    2 Новый В Компонент А		Новый Компонент В 
    Новый Компонент С		Новый Компонент D 

    Рис. 7.6. При модернизации приложения новые компоненты не должны нарушать 
работу старых компонентов. 

    Однако обратная совместимость не должна ограничивать расширение 
компонента. Дог жна быть обеспечена возможность радикально изменить поведение 
компонента дг> нового приложения при обеспечении работы старого приложения. 
    4. Расположение компонента в сети должно быть прозрачно (незаметно) для 
приложений клиентов. Компонент и программа, которая его использует, должны 
работать в одно!/ процессе, в разных процессах одной машины или на разных 
машинах. Клиент должен быть способен обработать удаленный компонент таким же 
образом, как он обрабатывает локальный компонент. Если удаленные компоненты 
должны обрабатываться иначе, чем локальные компоненты, клиент придется 
перекомпилировать всякий раз, когда локальный компонент перемещается в другое 
место в сети. 


    Глава 7. СОМ и создание клиентов ActiveX 159 


    7.1.9. Спецификация СОМ 

    Спецификация СОМ определяет общую схему для создания компонентов. В то 
время как спецификация диктует "обязанности" компонента и требования к нему, 
она не специфицирует, как эта функциональность должна быть реализована. Вместо 
этого спецификация СОМ определяет: 
    •	как из компонента создается^объект; 
    •	как клиещ обращается к возможностям, предоставляемым объектом; 
    •	ответственность объекта за^н^утожение_себя, когда он более не используется. 
    Все эти действия обрабатываются интерфейсами, которые существенно упрощают 
использование возможностей сервера. 
    До разработки кщушонентны^ технологий серверы часто предоставляли услуги 
клиентам 4eJ3e_3j^ji|2ajme,^3a^oQ6?a^ej^^UHM (не всегда должным образом 
организованных). Функции, которые экспортировались сервером, детализировались 
в больших массивах документации, на изучение_крторой .требовалось много 
времени и сил. 
    Это обусловливало три главные проблемы: 
    •   приложения-клиенты должны были строиться с учетом особенностей и 
преимуществ сервера; 
    •   когда изменялся сервер, должен был, соответственно, изменяться клиент; 
    •   в возможностях серверов было трудно разобраться, так как в 
обеспечиваемых ими функциях не имелось никакой логической структуры. 
    С помощью интерфейсов СОМ решает все эти проблемы. 

    7.1.10. Использование интерфейсов 

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

    Рис. 7.7. Взаимодействие клиента и компонентов сервера через интерфейсы. 

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


    160 Компонентная Объектная Модель, 

    На следующей иллюстрации показан объект для работы с кредитной карточкой с 
двумя! интерфейсами Розница и Кредит, которые обеспечивают различные 
возможности приложе-| нию розничной продажи и приложению менеджера кредита — соответственно. 

    База данных 

    Рис. 7.8. Два различных интерфейса объекта. 

    Интерфейс /Unknown 
    Спецификация СОМ требует обеспечения следующих функциональных возможностей 
всех объектов: 
    •   объект должен быть способен отслеживать установленные с ним 
соединения. Если объект больше не используется, он должен быть способен 
уничтожить себя; 
    •   объект должен допускать запросы от клиентов на дополнительные 
интерфейсы, которые он может поддерживать.	"" 
    Для обеспечения этих возможностей все объекты имеют встроенный интерфейс, 
именуемый IDnknown. Интерфейс lUnknown должен поддерживаться каждым объектом 
СОМ. Каждый следующий интерфейс объекта должен включать функциональные 
возможности обеспечиваемые (Unknown. 

    Функции интерфейса lUnknown 

    Интерфейс (Unknown имеет три функции — AddRef, Release и Querylnterface. 
Функции AddRef и Release следят за созданием и разрушением объекта, a 
Querylnterface позволяет клиентам запрашивать другие интерфейсы, 
обеспечиваемые объектом. 
    Функция AddRef, назначая указатель интерфейса, увеличивает счетчик 
использований объекта. Функция Release уменьшает счетчик, когда переменная, 
которая указывает на объект выходит из области определения. 
    AddRef вызывается, когда для инициализации объектной переменной вводится 
оператор Set. Release вызывается, когда объектная переменная устанавливается в 
Nothing или когда переменная выходит из области определения. Когда сче.тчик 
использований принимает нулевое значение (никакой клиент не имеет указателя на 
объектный интерфейс), объект уничтожает себя. 
    Дополнительную информацию относительно использования оператора Set см. 
далее, в разделе "Создание объектов". 


    Глава 7. СОМ и создание клиентов ActiveX 161 


    Запрос дополнительных интерфейсов 

    Когда клиент содержит объектную переменную, которая указывает на 
допустимый интерфейс СОМ, с помощью метода Querylnterface для него можно 
получать дополнительные интерфейсы, обеспечиваемые объектом. Visual Basic 
также автоматически обеспечивает эту возможность через оператор Set. 
    Информацию относительно доступа к дополнительным функциональным 
возможностям путем получения интерфейса см. в разделе "Доступ к дополнительным интерфейсам". 

    7.1.11. Взаимодействие клиента с сервером 

    В качестве промышленного стандарта СОМ встраивается^в несколько 
опе^ционньм систем и компиляторов, осуществляя связь между 
приложениями-клиентами и серверами, которые' предоставляют компоненты. 
    Ниже рассматриваются механизмы, которые обеспечивают взаимодействие между 
клиентами и серверами, а также роль системного реестра (Registry) в этом взаимодействии. 
    Взаимодействие между клиентом и сервером in-process 
    На уровне операционной системы быстродействие связи между клиентом и 
компонентами сервера изменяется в зависимости от типа сервера — in-process 
(DLL) или out-of-process (.ехе файл).
    Взаимодействие между клиентом и компонентом,in-process сервера 
обеспечивает наиболее эффективный обмен информацией. Так как клиент и 
компонент сервера совместно используют одно и то же адресное пространство, 
вызовы между ними передаются непосредственно. 

    Взаимодействие между клиентом и сервером'out-of-process 

    Схема взаимодействия между клиентом и компонентом out-of-process сервера 
более сложна, чем для сервера in-process, так как это соединение должно 
пересечь границы процесса. В особенности это касается связи с исполняемым 
файлом на удаленном компьютере; 
    Для управления этой связью СОМ-компилятор вставляет в приложение-клиент 
код полномочий (proxy), чтобы управлять вызовами сервера и их возвращаемыми 
значениями. При 1<ом"пил51"Ций~СОМ-сервера вставляется код фиктивного модуля, 
предназначенный для обработки вызовов от кода полномочий клиента и значений, 
возвращаемых клиенту. 
    Это управление параметрами и возвращаемыми значениями известно как 
маршаллинг. Маршаллинг — пакетирование всех параметров и возвращаемых значений 
и пересылка их через границу процесса. Иными словами, трансляция и передача 
параметров и возврат ^ёзупьтатов~пр\л передаче вызовов в другое адресное пространство. 
    На следующей иллюстрации показан поток информации от клиента к серверу 
через код полномочий и код фиктивного модуля. 

    Рис. 7.9. Поток информации от клиента к серверу. 

    6 Зак.   136 


    162	Реализация Автоматики 

    Эта реализация межпроцессной связи независима от платформы, так как она 
основана на спецификации Вызова Удаленной Процедуры в Распределенной 
Вычислительной Среде (bCE-RPC). Вызовы между СОМ-компонентами могут 
производиться между Windows 95 Windows NT, UNIX и Macintosh, а также другими 
средами, поддерживающими DCE-RPC 

    COM, GUID и системный реестр 

    При компиляции компонента для каждого public класса и интерфейса в 
компоненте создаются уникальные глобальные идентификаторы (GUID). Эти GUID — 
128-битовые числа которые_генерируются с использованием алгоритма, 
гарантирующего их уникальность. 
    Чтобы компонент стал доступным для клиентов, он должен зарегистрироваться 
в операционной системе. Компонент делает это, модифицируя раздел 
HKEY_CLASSES_ROOT системного реестра, внося туда информацию относительно себя. 
Информация включает программный идентификатор (ProgID), представляющий 
описательное имя компонента идентификатор класса (ClasslD), его расположение и 
расположение библиотеки типов. 
    При компиляции приложения-клиента, который обращается к компоненту 
сервера, иден-и-фикаторы классов и интерфейсов любого объекТаТТ^оТОрые создает 
компонент, включаются в исполняемый файл. В период выполнения клиент (вместе с 
СОМ) использует информацию в реестре для вызова компонента сервера. 
    Дополнительную информацию относительно реестра, отношений между 
приложениями-клиентами, СОМ и создания объектов см. ниже, в разделах 
"Библиотеки типов" и "Третий шаг: создание объектов". 

    7.2. Реализация Автоматики 

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

    7.2.1. Объекты Автоматики 

    Объект Автоматики — любой тип объекта, который предоставляет 
приложениям-клиентам доступ к своим свойствам и методам. 
    Свойства описывают характеристики объекта, такие, как имя, ширина или цвет 
фона. Свойства создаются с использованием public переменных или процедур Property. 
    Методы — запросы к объекту на выполнение некоторых действий. Например, 
чтобы добавить элемент к списку, используется метод Addltem списка. 
    События инициируют связь от объекта к клиенту. Вопросы событий 
рассматриваются в разделах "Уведомление клиентов" и "Сообщения сервера с 
использованием обратных вызовов". 

    7.2.2. Библиотеки типов 

    Клиенты получают информацию относительно объектов Автоматики от сервера, 
просматривая библиотеку типов компонента сервера. Библиотека типов может 
поставляться в одной из следующих форм: как ресурс в DLL; как ресурс в .ЕХЕ 
файле; как подфайл внутри 


    Глава 7. СОМ и создание клиентов ActiveX 163 

    файла составного документа или как автономный двоичный файл. Известные 
также как библиотеки объектных модулей, библиотеки типов обеспечивают 
следующую информацию: 
    •	определения интерфейсов, поддерживаемых объектом; 
    •	описания свойств, методов и событий, обеспечиваемых объектом; 
    •	возвращаемые типы и типы параметров методов и событий объекта; 
    •	ссылки на описания типов в других библиотеках типов; 
    •	имена файла помощи и тем помощи, связанные с объектом и его методами и свойствами. 
    Как и в случае с серверами, библиотеки типов регистрируются в операционной 
системе. Ключи для библиотеки типов размещены в папке ТурёШэ раздела 
HKEY_CLASSES_ROOT системного реестра.
    Библиотеки типов могут быть сохранены как часть .ехе или .dll файла, 
который они описывают, или как отдельные фaйльj^gjbJjJГllи_:tlb. Когда для 
создания компонента используется Visual Basic, библиотека типов встраивается в 
исполняемый файл. 

    Использование окна Object Browser 

    Object Browser— инструмент, который позволяет просматривать методы и 
свойства объекта Автоматики. 

    На рис. 1.7 показаны методы и свойства, доступные для объекта Projectl. 

    Список Проект/Библиотека показывает, что в данный момент в Object Browser 
просматривается библиотека типов Projectl В панели Классы видно, что имеется 
два объекта, доступных из Projectl: Class'1 и Form'1. В панели Компоненты 
класса видно, что Class'1 содержит два свойства (gsUser и User) и два метода 
(ShowDate и Squarelt). 

    7.2.3. Объектные модели 

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


    Рис. 7.10. Объектная модель Microsoft Excel. 


    164 Реализация Автома 

    При создании приложений-клиентов важно понимание отношений между 
составляю_.."w объектами (объектами, которые создаются автоматически с 
созданием другого объе ; как они используются. В то время как некоторые из 
объектов создаются явно (с пог/-_о>: ключевого слова New и метода CreateObject 
в VisuaiBasicX некоторые объекты созд; :тс; при вызове метода в другом 
объекте. Например, объект Application в Microsoft Excel'. ,:дэ-ется явно, в то 
время как содержащийся в нем объект Range — нет. 
    Информацию относительно того, как создавать объектную модель, см. в 
разделе "Соз^нке объектной модели" главы 8 "Создание программных компонентов ActiveX". 

    7.2.4. Интерфейс IDispatch 

    Диспетчерский интерфейс, IDispatch, является стандартным интерфейсом 
Автоматики, :.-,.;sa-ботанным специально для предоставления методов и свойств 
компонента клиенту. Этот :•---% фейс содержит четыре функции: 
GetTypelnfoCount, GetTypelnfo, GetlDsOfNames и Invoke 
    Функции GetTypelnfoCount и GetTypelnfo получают информацию из библиотеки 
типов компонента относительно интерфейсов, методов и свойств, которые он поддерживает. 
    GetlDsOfNames щмнимает одно или больше свойств и/или методов и 
возеращаецзна•-'-.-ю их идентификаторов (dispID), определенные в библиотеке 
шпов. Invoke принимает^;."jt, указатель на массив параметров и инициирует 
выполнение объектом ассоциирован-зго свойства или метода. 
    На следующей иллюстрации показаны функции, содержащиеся в IDispatch, а 
также до-л-нительные функции, поддерживаемые интерфейсом: 

    IDispatch 
    I	AddRef 
    Release 
    Querylnterface 
    GetTypelnfoCount 
    GetTypelnfo 
    GetlDsOfNames 
    Invoke 

    Рис. 7.11. Интерфейс Idispatch. 

    IDispatch позволяет клиенту выполнять следующее: 
    •   запрос объекта из библиотеки типов; 
    •   вызов имени свойства или метода в форме строки, чтобы получить 
ассоциированный идентификатор (dispID); 
    •  специфицирование значения идентификатора для вызова свойств и методов объекта. 
    .К^^други^унтерфе^сь^СОМ, IDispatch поддерживают все функциональные 
возможности интерфейса lUnknown. 

    На рис. 7.12 показано, как работает интерфейс IDispatch: 

    Дополнительную информацию относительно IDispatch и dispID см. в разделах 
"Введение в связывание" и "Использование интерфейсов". 


    Глава 7. СОМ и создание клиентов ActiveX 165 


    Рис. 7.12. Функционирование интерфейса IDispatch. 

    7.2.5. Двойные интерфейсы 

    Интерфейс IDispatch предоставляет возможности Автоматики, поэтому любой 
клиент, который может использовать IDispatch, может использовать 
поддерживающий его компонент. Однако вызов свойства или метода IDispatch может 
потребовать двух обращений ^функции — одно к GetlDsOfNames и одно к Invoke 
(см. "Введение в связывание"). 
    Метод Invoke должен определить, какой метод или свойство вызывается, и 
затем распаковать соответствующие параметры. Это не самый эффективный метод 
обеспечения Автоматики. Более эффективным является использование двойного интерфейса. 
    Двойной интерфейс — пользовательский интерфейс, определенный компонентом и 
получаемый через IDispatch. Двойной интерфейс содержит все функции, 
содержащиеся в Idispatch, а также пользовательские функции для каждого метода 
и свойства, определенного для объекта. Двойной интерфейс обеспечивает 
СОМ-клиентам наиболее эффективный доступ к методам и свойствам объектов Автоматики. 
    На следующей иллюстрации показано, как может выглядеть двойной интерфейс. 
Он содержит все функции IDispatch и все пользовательские функции для свойств и 
методов, которые поддерживают интерфейсы. 

    Функции IDispatch 

    Пользовательские функции 

    AddRef 
    Release 
    Querylnterface 
    GetTypelnfoCount 
    GetTypelnfo 
    GetlDsOfNames 
    Invoke 
    Property1_Get(...) 
    Property2_L8t(...) 
    Method1(...) 
    Method2(...) 

    Рис. 7.13. Двойной интерфейс. 


    166	Реализация Автоматики 

    Когда менее сложный клиент соединяется с объектом, который поддерживает 
двойной интерфейс, он использует стандартную реализацию IDispatch, вызывая 
Methodl и Method2 через функцию Invoke. 
    Более сложный клиент, например написанный на Visual Basic 5.0, может 
вызывать в интерфейсе, лепрсредственно функции Methodl и Method2. Это намного 
более эффективная форма доступа, известная как связывание vtable, которое 
освещается в следующем разделе. ] 

    7.2.6. Введение в связывание 

    Чтобы клиент мог использовать метод или свойство объекта, он должен быть 
связан с объектом. Связывание определяет, как клиент соединяется с конкретным объектом. 
    Форма связывания клиента с объектом прежде всего определяется тем, как 
разработчик приложения-клиента объявляет объектные переменные. 
    Связывание может происходить или в период выполнения или во время 
компиляции; исходя из этого, имеются два типа связывания: позднее и раннее. 

    Позднее связывание 

    Позднее связывание имеет место, когда компилятор до выполнения ничего не 
знает относительно объекта. 
    Когда используется позднее связывание, для обращения к методу или свойству 
объекта клиент должен делать два вызова. Первый вызов производится к методу 
GetlDsOfNames интерфейса IDispatch, чтобы отобрать имена доступных методов и 
свойств объекта. После этого производится вызов функции Invoke, чтобы 
выполнить требуемое действие. 

    Раннее связывание 

    С другой стороны, раннее связывание происходит, когда Visual Basic во 
время компиляции точно знает, какой интерфейс будет использоваться с объектной переменной. 
    Так как компилятор имеет доступ к библиотеке типов объекта, он может 
проконтролировать синтаксис любых вызовов, которые используют эту объектную 
переменную, и сообщить о любой ошибке синтаксиса во время разработки. 
    Компилятор может также изменять компилированный код для оптимизации по 
быстродействию выполнения доступа к объекту. J3ja оптимизация может быть 
выполнена одним из двух способов: связыванием dispID или связыванием vtable. 
    '$a 

    ^" Связывание dispID 

    При связывании dispID компилятор получает идентификатор dispID библиотеки 
типов объекта и изменяет все вызовы объекта вызовом Invoke с соответствующим 
параметром dispID. Следовательно, для каждого метода или свойства, к которому 
выполняется обращение, исполняемый модуль устраняет вызовы GetlDsOfNames. 

    Связывание vtable 

    Более быстрая форма раннего связывания известна как связывание vtable. 
Связывание vtable — более эффективная форма связывания, так как при ней не 
делается два вызова GetlDsOfNames и Invoke. 
    Visual Basic вообще не делает каких-либо обращений к функциям. Вместо 
этого для непосредственного доступа к методам и свойствам объекта он 
использует смещение (или указатель) на таблицу виртуальной функции (vtable). 
    В спецификации СОМ серверы обеспечивают связывание vtable по умолчанию. 
Если в приложении-клиенте переменные объявляются с использованием явных имен классов, 


    Глава 7. СОМ и создание клиентов ActiveX 167 

    Visual Basic всегда будет использовать связывание viable. При 
использовании связывания vtable вызов метода или свойства в in-process 
компоненте Visual Basic не требует каких-либо дополнительных затрат ресурсов, 
кроме вызова функции в DLL. 
    Дополнительную информацию относительно влияния различных типов связывания 
на производительность см. в разделах "Объявление объектных переменных" и 
"Создание объектов". 

    7.3. Характеристики компонентов сервера 

    При разработке приложения-сервера программист определяет, сколько 
экземпляров компонента сервера будет создано в период выполнения и где сервер 
будет выполняться. Эти решения могут оказывать существенное влияние на 
"п'р'ойзвЬдитёльн'сГсть" и' защиту клиента. 

    7.3.1. Установка свойства Instancing 

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

    Установка  Результат (Умолчание) 

Private. Другому приложению не разрешен доступ к 
информации 1          библиотеки типов класса, и оно не может создавать 
экземпляры этого класса. Объекты Private используются только внутри 
компонента. Применяется к компонентам ActiveX EXE, ActiveX DLL, ActiveX 
Control и Standard EXE. 

PublicNotCreatable. Другое приложение может 
использовать объекты этого класса, только если компонент перед этим сам 
создает объекты. Другое приложение не может использовать для создания 
объектов этого класса функцию CreateObject или операцию New. Это значение 
устанавливается для свойства Instancing, если требуется создать зависимые 
объекты. Применяется только к компонентам ActiveX E XE, ActiveX DLL и 
ActiveX Control. SingleUse. Позволяет другому приложению создавать объекты из 
класса. 3          Каждый объект этого класса, который создан клиентом, 
запускает новый экземпляр компонента. Применяется только к проектам 
ActiveXTEXE. 

GlobalSingleUse. Подобно установке SingleUse, за исключением 
того, что 4          свойства и методы класса могут вызываться, как если бы 
они были глобальными функциями. Применяется только к компонентам ActiveX 
"ЕХ"Е. 

MultiUse. Позволяет другому приложению создавать объекты из класса. 
Один  экземпляр компонента может обеспечивать любое количество 
объектов, созданных таким образом, независимо от того, сколько приложений их 
запрашивает. Применяется только к компонентам ActiveX EXE и ActiveX DLL. 

GlobalMultiUse. Подобно установке MultiUse, за исключением того, что свойства 
и методы класса могут вызываться, как если бы они были глобальными 6          
функциями. Предварительное явное создание экземпляра класса необязательно, так 
как он будет создан автоматическ и. Применяется только к компонентам ActiveX 
EXE и ActiveX DLL. 


    168 Характеристики компонентов сервера 


    Установка	Применяется к проекту типа 

    				ActiveX 	Exe	ActiveXDLL	ActiveXContol	Standard h 

    Private			X		X	X		X         --   I 
    PublicNotCreatable	X		X	X 
    SingleUse		X			=4 
    GlobalSingleUse	X 
    MultiUse		X		X		— 1 
    GlobalMultiUse	X		X		• 

    Свойство Instancing в Visual Basic 5.0 расширено и включает функциональные 
возмо: свойства Public из Visual Basic 4.0. 
    Когда допускается создание класса, создавать экземпляры класса из другого 
прило; можно любым из следующих способов: 
    •   с помощью функции CreateObject: 

    Set   Instancel   =  CreateObject ("Projectl.Classl") 

    •   используя оператор Dim внутри проекта (или вне проекта, если свойство 
Public установ-1 лено в True): 

    Dim   Instancel   As   New  Classl 

    Ключевое слово New указывает, что Instancel должно быть объявлено как 
новый экземгля Classl. 
    Если свойство Public — False, установка свойства Instancing игнорируется. 
Можно все создавать э!<земплярьГкласса' внутри проекта, который определяет 
класс. Если свойст Public — True, класс видим и, следовательно, если экземпляр 
класса существует, он мо» управляться другим приложением. 
    Хотя клиент не._им§ет какого-либо контроля над созданием экземпляра 
компонента, ус новка для свойства Instancing может существенно влиять на 
производительность клиен Например, если клиент должен совместно использовать 
экземпляр компонента, произвол тельность может снижаться. 

    7.3.2. Определение расположения компонентов сервера 

    В зависимости от назначения компоненты могут разрабатываться с целью 
предоставлени услуг из различных расположений. 
    Например, компонент пользовательского интерфейса, вероятно, лучше всего 
разместит возможно ближе к кшенту, в то время как компонент, который 
обеспечивает статистичес вычисления удаленных данных, эффективней будет 
расположить на отдельном компьюта| Рв'-ЕЗЙЙм Сланными, которыми компонент 
манипулирует в вычислениях. 
    Компоненты могут работать в^т|обом_из_трех мест: в том же адресном 
пространстве, что] клиент, в адресном пространстве, отдельном от 
приложения-клиента, или на удаленн компьютере. В следующей таблице видны 
различия между этими типами расположен компонентов: 


    Глава 7. СОМ и создание клиентов ActiveX 169 

    Как и в случае со свойством Instancing, клиент Visual Basic не имеет 
какого-либо контроля над расположением компонента. Однако расположение может 
существенно воздействовать на производительность клиента, в некоторых случаях 
расположение может также оказывать влияние на характер взаимодействия клиента 
с компонентом. 
    При работе с out-of-process и удаленными компонентами необходимо 
гарантировать, что клиент минимизирует количество вызовов объектов, созданных 
из компонента. 
    Например, если производятся повторные вызовы объекта с передачей данных, 
которые объект обрабатывает, желательно найти способ передавать данные 
крупными пакетами, сократив, насколько возможно, количество вызовов. 

    7.3.3. Уведомление клиентов 

    Еще одна черта компонентов, с которой разработчику стоит разобраться, — их 
способность поддерживать связь с клиентами асинхронно. В Visual Basic это 
новая возможность для компонентов: более ранние версии Visual Basic допускали 
только синхронную обработку. 
    Когда компонент используется лишь для отбора значений свойств и вызова 
методов, он немедленно возвращает значения клиенту. Однако, если компонент 
должен выполнить задачу, о которой известно, что она займет несколько секунд 
или минут, требуется обеспечить асинхронное сообщение клиенту, когда сервер 
завершит выполнение обработки. 
    В этой версии Visual Basic, когда компоненту требуется установить связь с 
клиентом, компонент использует исходящий инте^фейс^ Это означает, что 
компонент определяет унте?фе\лс^~э~~кг\иент'"его реализует. Сервер 
устанавливает связь с клиентом, отбирая указатель на возможный способ 
реализации клиентом этого интерфейса, и затем делает соответствующие вызовы. 

    Тип сервера    Расположение 

Компонент in-process обычно реализуется как библиотека динамической компоновки 
(DLL). Он выполняется в том же адресном пространстве (процессе), где и 
приложение-клиент. Это позволяет in~procsss реализовать наиболее эффективную 
связь между клиентом и компонентом, так как для получения требуемых функциональных 
возможностей требуется только вызвать нужную функцию DLL. Компонент  out-of-process  
обычно  реализуется   как  исполняемый файл и выполняется в собственном пространстве 
процесса. Связь между клиентом и компонентом будет медленнее, так как параметры Qtf                     и 
возвращаемые значения должны передаваться через границу процесса (маршаллинг). 
Однако единственный экземпляр компонента out-of-process может обслуживать 
много клиентов, разделять глобальные данные и изолировать другие 
приложения-клиенты от проблем, с которыми может столкнутьс я один из клиентов. 
Удаленные компоненты — также компоненты out-of-process, но они размещены на 
отдельном компьютере. Хотя время установления связи между клиентом и удаленным 
сервером существенно больше, чем на локальном 
сервере, удаленные серверы позволяют выполнять обра-6ojrKy^jHa, более мощном 
компьютере. Компонент можно также разместить ближе к выполняемой работе. 
Например, удаленный компонент может быть расположен рядом с удаленной базой 
данных, с которой он взаимодействует. 


    170 Создание клиента в Visual Basic 

    На следующей иллюстрации показана асинхронная связь между компонентом и клиентом 

    Рис. 7.14. Асинхронная связь между компонентом и клиентом. 

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

    7.4. Создание клиента в Visual Basic 

    В этом разделе показано, как создать компонент и как получить ссылки на 
дополнительные интерфейсы в компоненте. 
    Компоненты СОМ создаются с помощью таких инструментальных средств, как 
Visual Baste, Microsoft Visual С ++ и Microsoft Visual J ++. Visual Basic в 
этом плане предлагает богатый набор возможностей в дополнение к преимуществам 
своей среды быстрой разработки приложений 
    Создание компонентного приложения-клиента в Visual Basic требует четырех 
простых шагов: 
    1. Установить ссылку на библиотеку типов компонента. 
    2. Объявить объектную переменную. 
    3. Создать объект. 
    4. Использовать методы и свойства объекта. 

    7.4.1. Первый шаг: установление ссылок 

    При создании приложения-клиента необходимо соединить клиента с 
компонентом. Первый шаг при подключении клиента к компоненту — установить в 
проекте ссылку на библиотеку типов компонента. Для этого: "" "	-..-...~-..
    1. В меню Project выбрать References. 
    2. В окне диалога References выбрать библиотеку типов, которую требуется 
подключить, и заТём щелкнуть ОК (рис. 7^5)! Если ссылка не представлена в 
списке, но известно, что компонент доступен, щелкнуть кнопку Browse, чтобы 
добавить ссылку. 
    После того как на компонент установлена ссылка, можТю~открыть Object 
Browser для просмотра и выбора объектов, интерфейсов, методов, свойств, 
событий и констант, предоставляемых компонентом. 


    Глава 7. СОМ и создание клиентов ActiveX 171 

    Дополнительную информацию относительно библиотек типов см. в разделе 
"Реализация Автоматики". 

    Рис. 7.15. Окно диалога References. 

    7.4.2. Второй шаг: объявление объектных переменных 

    Объектные переменные содержат указатели объектов, которые требуется 
создать для клиента Автоматики. 
    Объектную переменную можно объявлять либо переменной общего объектного 
типа (As ObjectJ, либо конкретного типа, в зависимости от того, какТтМнируется 
использовать переменную и какое допускается воздействие объекта на 
производительность приложения. 

    Примечание: Для объектных переменных применяются те же правила области 
определения, что и для общих переменных. 

    Общие объектные переменные 

    Общие объектные переменные могут содержать указатели на любой тип объекта. 
Наиболее общая переменная имеет тип Variant. Переменная типа данного Variant 
содержит числовые Й"стр6к6вые данные и, кроме того, может также содержать 
указатель на объект любого типа. 
    Для общих объектных переменных желательно объявлять тип данных Object, как 
показано в следующем примере:

    Dim  x  As   Object 

    При использовании общих объектных переменных для соединения с объектом 
компилятор применяет позднее связывание. Объект или объекты, с которыми нужно 
установить связь, в этом случае не будут йз'вестны до выполнения приложения. 
Так как позднее связывание не использует библиотеку типов во время разработки, 
устанавливать ссылку на компонент в Visual Basic не требуется. 

    Объектные переменные конкретного типа 

    Объектные переменные конкретного типа относятся к дискретному объектному 
типу и могут содержать указатели только на объект этого типа. 


    172	Создание клиента в Visual Basic 

    Например, следующий код объявляет переменную ех, которая будет содержать 
указатель только на объект Microsoft Excel Application. 

    Dim  ex  As   Excel.Application 

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

    7.4.3. Третий шаг: создание объектов 

    Третий шаг построения приложения-клиента — создание объекта и назначение 
его объектной переменной, чтобы можно было использовать доступные методы и 
свойства компонента. 
    Создать объект в Visual Basic можно четырьмя способами: 
    •	функцией CreateObject; 
    •	оператором Set с ключевым словом New; 
    •	оператором As New в разделе Declaration модуля; 
    •	функцией GetObject. 
    Каждый из этих четырех методов имеет свои преимущества. Обычно выбираемый 
метод зависит от того, создается экземпляр объекта из другого компонента или 
экземпляр объекта, который уже принадлежит проекту Visual Basic. Какой бы 
способ ни был выбран, в течение выполнения имеют место два шага: 
    •   создание (или инициация) объекта; 
    •   назначение указателя на умолчательный интерфейс объекта объектной переменной. 
    Ниже приводится описание использования каждого метода создания объекта Автоматики 

    Использование функции CreateObject 

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

    Dim  objObjectl  As   Projectl.Classl 
    Set   objObjectl   =  CreateObject ( "Projectl.Classl") 


    Использование ключевого слова New с оператором Set 

    При создании с помощью ключевого слова New экземпляра класса, внешнего по 
отношению к приложению, привлекаются сервисы СОМ. 
    В этом случае между функцией CreateObject и ключевым словом New не 
существует никакой разницы. Однако, если ключевое слово New используется для 
создания объекта, который является частью проекта, Visual Basic применяет 
более эффективный метод создания внутреннего объекта. 


    Глава 7. СОМ и создание клиентов ActiveX	173 

    Для создания экземпляров классов в проекте рекомендуется следующий 
синтаксис: 

    Dim objObjectl As Project! .Classl Set objObjectl = New Project! .Classl 

    Примеры кода, в которых используется этот синтаксис, см. в разделе 
"Создание экземпляра Microsoft Excel". 

    Примечание: При создании объекта необходимо использовать °nejDamop_Sef, 
чтобы назначить объект к объектной переменной. Это объясняется тем, что объект 
должен иметь счетчик использования, который позволяет объекту уничтожить себя, 
когда он более не используется. Оператор Set гарантирует, что, когда 
возвращается указатель объектного интерфейса, вызывается метод AddRef. 
Внутренний счетчик использования объекта получает инкремент, и объект 
существует, пока не вызывается функция Release и счетчик использования не 
устанавливается в ноль. 

    Дополнительную информацию относительно AddRef и Release см. в разделе 
"Использование интерфейсов". 

    Использование оператора As New в разделе Declaration 

    Для создания объекта оператором As New используется следующий синтаксис: 

    Dim objObjectl as New Classl 

    Использование оператора As New для объявления объектной переменной 
откладывает создание объекта до тех пор, пока к объекту не будет фактического обращения. 
    Сгщдует избегать использования оператора As New, так как при этом 
создается менее эффективный код. Например, когда вводится следующий код: 

    Dim  ObjectVariablel   As   New  Classl If   Fund ()    Then 
    ObjectVariablel.Propl   =   5 End   if ObjectVariablel.Prop2   =   6 
    Visual Basic регенерирует код, как если бы'текст кода был следующий: 
    Dim  ObjectVariablel   As   New  Classl If  Fund ()   Then If  Not   
IsObject(ObjectVariablel)	'   Добавлено  компилятором 
    Set   ObjectVariablel   =  New  Classl	' ' End   if                        
    '   Добавлено   компилятором 
    ObjectVariablel.Propl   =  5 End  if If  Not   IsObject(ObjectVariablel)	' 
  Добавлено   компилятором 
    Set   ObjectVariablel   =  New  Classl 
    End  if	'   Добавлено   компилятором ObjectVariablel.Prop2   =   6 
    New или CreateObject? 

    При создании единственного объекта по производительности нет существенных 
различий между использованием ключевого слова New и функции CreateObject. 
Однако, когда создается несколько объектов, роль аспекта производительности 
возрастает. Функция CreateObject при создании экземпляра класса использует 
стандартные сервисы СОМ, в то время как в Set х = New Y и Dim x As New Y 
используется оптимизированная внутренняя версия сервисов создания объектов. 


    174	Создание клиента в Visual Ва 

    Когда используется CreateObject, код выполняет по крайней мере два 
просмотра инд ции в системном реестре. Сначала он ищет идентификатор ProgID 
для класса (наприм Excel.Application) и определяет ассоциированный ClasslD. 
    Затем он ищет этот ClasslD в разделе CIslD реестра и извлекает требуемую 
информации по данному серверу. Например, CIslD содержит данные по расположению 
сервера и ег: библиотеке типов. 
    Эти просмотры при создании единственного объекта на производительность 
заметно не воздействуют, но при создании нескольких объектов влияние будет 
значительным^ т'атгет код должен выполнить эти поиски для каждого вызова 
функции CreateObject. 
    С другой стороны, когда используется ключевое слово New, компилятор может 
оптимизировать код (применяя раннее_связывание), так как имеется только один 
просмотр для CIslD Вся информация сервера (например, расположение библиотеки 
типов) кэшируется в памяти и многократно используется для последующих вызовов. 
    Таким образом, при создании объектов нужно стараться вместо функции 
CreateObjec использовать ключевое слово New. 

    Использование функции GetObject 

    Основная причина для использования функции GetObject состоит в том, что 
иногда требуется создать экземпляр объекта, который уже содержит данные из 
файла. Например следующий код возвращает объект Workbook (рабочая книга) 
Microsoft Excel с уже открытый рабочим листом Finances.xls: 

    Dim  xl  As   Object 
    Set   xl   =   GetObject("с:\excel\finances.xls") 

    Так как в вызове нет какого-либо конкретно специфицированного класса, 
Visual Basic создает объект, используя компонент, ассоциированный с 
расширением файла .xls. 
    GetObject можно использовать также для определения, выполняется ли 
компонент в данны/ момент, или, если файл данных поддерживает это, для 
создания объекта специфицированного класса. 

    7.4.4. Четвертый шаг: использование объектов Автоматики 

    Четвертый и заключительный шаг в создании клиента Автоматики — 
использование метоа и свойствов созданного объекта. Синтаксис программного 
управления объектом с помошью его методов и свойств, включающий операцию 
"точка" (.), аналогичен управлению элементами управления. 
    Так как элементы управления — объекты Automation, следующий синтаксис 
применяется при управлении любым объектом Автоматики: 

    объект.[метод\ 


    Применение дополнительных интерфейсов 

    Большинство объектов обеспечивает поддержку более одного интерфейса. В 
компонентах часто реализуется несколько интерфейсов, каждый из которых 
обеспечивает свои функциональные возможности. 
    Для получения доступа к дополнительным интерфейсам необходимо объявить 
дополнительную переменную типа интерфейса и затем установить новую переменную, 
используя существующую объектную переменную. 
    Например, допустим, что компонент проверки орфографии, именуемый Speller, 
поддерживает два интерфейса: Check и IManage. Check — интерфейс Автоматики, 
используемый для 


    Глава 7. СОМ и создание клиентов ActiveX	175 

    контроля правописания и предложений по исправлению ошибок. IManage 
используется для добавления и удаления слов из словаря. Клиент обращается к 
обоим интерфейсам со следующим кодом: 

    Dim  check  as   Speller.Check Dim mng  as   IManage 
    Set   check  =  New   Speller.Check   '	Создается   новый  объект  и 
    "^•-С  увеличивается   счетчик	использования 
    Set  mng   = л-heck   '	Возвращается   интерфейс   IManage 
    '   счетчик  использования	увеличивается  до   2 

    7.5. Прием сообщений от серверов 

    Visual Basic версии 5.0 обеспечивает два способа управления асинхронными 
сообщениями клиенту: события и обратные вызовы. Оба способа выполняются через 
исходящие интерфейсы. Дополнительную информацию относительно выхода интерфейса 
см. в разделе "Уведомления клиентов". 
    В случае использования событий реализация исходящего интерфейса 
автоматически встраивается в приложение-клиент, и код, отвечающий на событие, 
писать не требуется. Для обратных вызовов разработчик приложения-клиента 
должен реализовать исходящий 'интерфейс явно. 
    Оба эти метода достигают одной цели, но требуют двух различных подходов в 
программировании. В большинстве случаев используемый метод определяется 
реализацией компонента сервера. 
    В этом разделе показано, как составлять код для обработки событий и 
обратных вызовов, с точки зрения клиента, и рассматриваются преимущества и 
недостатки обоих подходов к асинхронным сообщениям. 

    7.5.1. Сообщения сервера с использованием событий	'/ 

    Во время разработки автор компонента сервера может специфицировать набор 
сообщений, которые компонент передает в случае наступления некоторых событий. 
Так как эти сообще-   / ния видимы в библиотеке типов, они определяют 
исходящий интерфейс компонента. 
    При формировании компонента клиента требуется знать, какие события и 
ассоциированные параметры генерируются компонентом, и отреагировать на каждое 
событие в процедуре обработки события. 
    Процедура обработки события реализуется объявлением интерфейса события в 
Visual Basic. Это делается расширением объявления объектной переменной 
ключевым словом WithEvents, как показано в следующем примере: 

    Public  WithEvents   obj   As   Server.Object 

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

    Private   Sub   obj_Eventl() 
    ' Выполнение некоторого действия в ответ на событие Eventl End Sub 
    Private Sub obj_Event2(vNewValue As Variant) 
    ' Выполнение некоторого действия в ответ на событие Event2 End Sub 


    176	Прием сообщений от серверов 

    7.5.2. Сообщения сервера, использующие обратные вызовы 

    Обратные вызовы обеспечивают те же функциональные возможности, что и 
события, но они обеспечивают компоненту намного большую степень контроля над клиентами. 
    Прежде чем переходить к использованию функций обратного вызова, необходимо 
уяснить смысл ключевого слово Implements, которое введено в Visual Basic 5.0. 
Подпрограммы обратного вызова на стороне компонента создаются разработчиком 
компонента, создающим пустой шаблон интерфейса, который впоследствии будет 
реализован разработчиком клиента.	~ 

    Примечание: Стандартные интерфейсы создаются путем компиляции абстрактных 
классов (модули класса с объявлениями процедур, но без реализации) в проектах 
ActiveX DLL или EXE Visual Basic или с помощью K^njjn^m^a^icrosoft Interface^ 
Definition Language (MIDL), который находится е папке Tools Visual Basic.	" 

    Опытные пользователи Visual C++ для определения интерфейса, вероятно, 
предпочтут компилятор MIDL. Программистам BASIC, скорее, понравится создавать 
интерфейс, используя модули класса Visual Basic. 

    Использование ключевого слова Implements 

    Для реализации определения интерфейса компонента сначала необходимо 
установить ссылку на этот компонент. 
    После установления ссылки можно использовать Object Browser для просмотра 
определения интерфейса. Затем в модуле класса можно использовать ключевое 
слово Implements для объявления дополнительного интерфейса. 
    Предположим, например, что требуется реализовать интерфейс ISomelnterface 
с методами Method 1 и Method2. В следующем фрагменте показано, как можно 
добавить эти методы к модулю класса: 

    Implements   ISomelnterface   'Объявление  интерфейса 
    Public  Sub  ISomelnterfaceJxiethodl () 
    '   Некоторое   описание  метода  Methodl End  Sub 
    Public   Sub   ISomeInterface_Method2() 
    '   Некоторое   описание  метода  Method2 End  Sub 

    Использование возможностей обратного вызова 

    Сообщение обратного вызова требует, чтобы клиент реализовал явный 
интерфейс, определенный компонентом, и передал ссылку на этот интерфейс 
обратно к компоненту. 
    Компонент сервера обеспечивает следующие две части кода: 
    •   имя пользовательского интерфейса, функции которого будут действовать 
как обратные вызовы клиенту; 
    •   функция public (обычно это свойство, которое используют только для 
записи), через которую клиент будет передавать ссылку на интерфейс, содержащий 
обратные вызовы. 
    Чтобы получать сообщения обратного вызова из компонента, в 
приложении-клиенте должны быть проделаны следующие шаги: 
    1. Гарантировать, что исходящий интерфейс из компонента распознаваем. В 
Visual Basic должна быть установлена ссылка на компонент. 


    Глава 7. СОМ и создание клиентов ActiveX	177 

    2. BjTg^o^eHj^HKTMeHT добавить модуль класса, который реализует исходящий 
интерфейс сервера через_ключевое_слово Implements, и обеспечить реализацию для 
каждой из функций, определенных в интерфейсе. 
    3. В соответствующем модуле добавить код, в котором объявляется объектная 
переменная дляком понента и создается экземпляр этого компонента. 
    4. Добавить код, который объявляет объектную переменную класса, в котором 
реализуется исходящий интерфейс и создается экземпляр этого класса. 
    5. Передать объекту (используя соответствующий метод или свойство) ссылку 
на класс, который реализует исХбдящий интерфейсГЗто дает компоненту 
возможность передавать клиенту обратный вызов через интерфейс, реализованный в 
модуле класса. 
    В следующем коде модуля класса Cnotifyee реализуется исходящий интерфейс INotifyProc: 

    Option  Explicit 

    Implements   INotifyProc   '   Интерфейс,   определенный   сервером 
    Public   Sub   INotifyProc_SleepEntered() MsgBox   "Обратный  вызов  
инициирован" End  Sub 
    Public   Sub   INotifyProc_SleepEnded() 
    MsgBox   "Обратный  вызов   закончен" End  Sub 

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

    Option  Explicit 
    '   Объявить   объект   уведомления    (обратного   вызова) Dim  
objNotifyee  As   Notifyee         '"""" '   Объявить   объект-уведомитель Dim 
 objNotifier  As   CNotifier 
    Private   Sub   Form_Load() 
    Set objNotifier = New CNotifier 
    Set objNotifyee = New Notifyee 
    ' Передать ГРПВРПУ ПСЫ.ГТКУ^НЯ^ уйъ^^т П0гагг'нп^р ти-т^гта 
    orTjNotTfTer . Not if yProc = objNotifyee        -       ,;. .. End Sub 
    Private Sub cmdExit_Click() 
    Unload Me End Sub 
    Private Sub cmdSleep_Click() 
    objNotifier.Interval = txtlnterval 
    objNotifier.Wait ' Пользовательский метод перехода в ждущий режим End Sub 


    7.5.3. События или обратные вызовы? 

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


    178	Прием сообщений от серверов, 

приложений-клиентов, в то время как подпрограмме обратного вызова в 
компоненте известно о клиенте многое. 
    Ниже приводятся сравнительные характеристики событий и обратных вызовов. 
    Любой объект, который имеет ссылку на компонент, предоставляющий событие, 
сможет управлять событием, если к объявлению переменной объекта добавить 
WithEvents. Компонент, который содержит это событие, не знает о том, что 
другие объекты могут обрабатывать его события, так как он "ведет передачу" для 
неизвестной аудитории. 
    С другой стороны, компонент, который содержит подпрограммы обратного 
вызова, должен обеспечить ссылку на каждый объект, который он вызовет. 
Компонент точно знает, сколько объектов к нему обращаются. 
    Компонент, предоставляющий события, не имеет какого-либо контроля над 
порядком, в котором приложения-клиенты получают события. 
    С другой стороны, компонент, использующий обратные вызовы, может управлять 
порядком в котором вызывающие приложения-клиенты получают обратные вызовы. 
Например, компонент может управлять приоритетом некоторых клиентов. 
    Когда компонент устанавливает событие, все его клиенты обрабатывают 
событие прежде чем серверу возвращается управление. 
    С другой стороны, компонент, использующий обратные вызовы, восстанавливает 
управление после каждого вызова клиента. 
    Если событие содержит параметр ByRef, этот параметр может изменяться любым 
клиентом, который обрабатывает событие. Компонент будет видеть только 
последние изменения сделанные клиентом, так как компоненту не возвращается 
управление, пока все клиенты не обработают событие. 
    С другой стороны, компонент, который обеспечивает подпрограмму обратного 
вызова, может видеть любые изменения, сделанные с параметром ByRef после 
каждого вызова клиента, и может передать следующему клиенту новые значения для 
этих параметров. 
    Если возвращается ошибка в процедуре обработки события клиента, компонент, 
который передал событие, не будет знать об ошибке. 
    С другой стороны, компонент, который обеспечивает подпрограмму обратного 
вызова может получать ошибки, которые происходят в подпрограмме обратного 
вызова клиента, и может быть подготовлен к их обработке. 
    Таким образом, события, вместо подпрограмм обратного вызова, следует 
использовать, когда компонент, передающий уведомления: 
    •	может передавать их анонимно; 
    •	не заботится о порядке их получения клиентами; 
    •	компоненту не требуется получать управление обратно между вызовами клиентов; 
    •	может использовать последнее известное значение любого параметра ByRef; 
    •	не должен обрабатывать ошибки клиента. 
    Если любое из этих условий не выполняется, то компонент должен передавать 
уведомления, используя подпрограммы обратного вызова. 
    Когда критично важна производительность приложения, можно также 
использовать обратные вызовы вместо событий. Подпрограммы обратного вызова 
могут работать быстрее, чем события, так как для обратных вызовов, в отличие 
от событий, может применяться связывание viable. Эффект от этого намного более 
значим для компонентов In-process. 


    Глава 7. СОМ и создание клиентов ActiveX	179 


    7.6. Создание приложения-клиента, использующего Microsoft Excel 

    В этом разделе описывается, как использовать Visual Basic для создания 
приложения-клиента, использующего Microsoft Excel. Здесь дается краткий обзор 
объектов, предоставляемых Microsoft Excel, и показано, как: 
    •   использовать рабочие книги и диаграммы и вызывать процедуры Microsoft Excel; 
    •   использовать Автоматику для создания экземпляра Microsoft Excel и 
манипулировать некоторыми из методов и свойств объекта; 
    •   получать и устанавливать значения свойств для создания и 
манипулирования объектом-диаграммой; 
    •   выполнять процедуру Microsoft Excel; 
    •   преобразовать процедуру, созданную с помощью Visual Basic Macro 
Recorder, в функцию Microsoft Excel.

    7.6.1. Объектная модель Microsoft Excel 

    Microsoft Excel предоставляет более сотни объектов Автоматики, которые 
можно использовать в Visual Basic. Каждый из этих объектов обслуживает 
некоторый аспект Microsoft Excel, например составление диаграмм или рисование. 
    Некоторые из объектов объектной модели Microsoft Excel показаны на рис. 
7.10.
    В Visual Basic с помощью ключевого слова New или функции CreateObject 
можно создавать объекты Application, Chart и Sheet. Другие объекты в объектной 
модели Microsoft Excel — зависимые объекты, которые можно создавать, используя 
метод Add. 

    Примечание: Зависимые объекты могут быть доступны только через метод 
объекта более вь1сокого_уровня. Например, метод Cells объекта Worksheet 
Microsoft Excel возвращает объект Range. 

    Обращение к объектам осуществляется с использованием навигационной 
операции точка (.). Например, следующий код устанавливает значение ячейки А1 в 
рабочем листе Sheet'1 в рабочей книге BOOK1.XLS: 

    xl.Workbooks("BOOK1.XLS").Worksheets ("SHEET1")_ .Range("Al").Value  =   5 

    Для установления ссылки на объект, расположенный в объектной модели одним 
уровнем выше, можно использовать свойство Parent объекта, как в следующей строке: 

    xlwb.Parent   '   Обращение   к  объекту  Application 

    Для установления ссылок на неоднократно используемые объекты можно 
создавать объектные переменные. 
    В следующем примере кода в объектной переменной xlsheet устанавливается 
ссылка на лист Sheet'1 в рабочей книге Book1.xls: 

    Dim  xl   as   Excel.Application 
    Dim  xlSheet   as   Excel.Worksheet 
    Set   xl   =  CreateObject("Excel.Application") 
    Set   xlSheet   =   xl.Workbooks ("BOOK1.XLS") .Worksheets("SHEET1") 
    xlSheet.Range("Al").Value   =   5 

    Ссылку на объект можно установить по имени или индексу. В следующей строке 
устанавливается ссылка на рабочую книгу Book1.xls, часть группы, или 
семейства, рабочих книг: 

    set   xlwb  =  xl.Workbooks("BOOK1.XLS") 


    180	Создание приложения-клиента, использующего Microsoft Excel 

    Первый элемент в семействе имеет,, индекс 1. В следующем примере 
устанавливается ссылка на первую рабочую книгу в семействе Workbooks: 

    set xlwb = xl.Workbooks(1) 

    7.6.2. Создание экземпляра Microsoft Excel 

    В первом шаге при использовании Автоматики в проекте Visual Basic 
необходимо добавить ссылку на библиотеку типов требуемого компонента. 
Например, чтобы добавить ссылку на i библиотеку типов для Microsoft Excel, в 
окне References (команда Project | References) нужно установить флажок против 
элемента Microsoft Excel 8.0 Object Library. 
    Для создания или установления ссылок на экземпляры объектов Microsoft 
Excel можно использовать ключевое слово New Visual Basic или функции 
CreateObject или GetObject. Информацию относительно различий в использовании 
ключевого слова New и функции CreateObject см. в разделе "Создание объектов". 

    Использование ключевого слова New 

    Ключевое слово New инициирует создание нового экземпляра Microsoft Excel. 
При установке Microsoft Excel он регистрирует классы Excel.Application, 
Excel.Worksheet и Excel.Chart которые можно объявлять, как показано в 
следующем коде: 

    Dim  xl   as   Excel.Application Dim  xlchart   as   Excel.Chart Dim  
xlsheet   as   Excel.Worksheet 
    set   xl   =  New  Excel.Application set   xlchart   =  New  Excel.Chart 
set   xlsheet   =  New  Excel.Worksheet 

    Использование функции GetObject 

    Если требуется использовать экземпляр Microsoft Excel, котдр_ый_у_же 
выполняется, применяется функция GetObject.	r ~~ " " 
    Функция GetObject принимает два параметра. Первый — полный путь и имя 
файла, содер жащего требуемый объект. Второй параметр — строка, представляющая 
класс создаваемого объекта. Если первый параметр опущен, второй параметр обязателен. 
    Если первый параметр опущен, GetObject пытается соединиться с 
выполняющимся экзе»/ пляром Microsoft Excel. Если Microsoft Excel не активен, 
GetObject возвращает ошибк. выполнения. 
    Если в первом параметре указано имя файла, GetObject возвращает ссылку на 
первый лис рабочей книги. 

    Примечание: Когда запускается экземпляр объекта Microsoft Excel, он не 
становится) видимый автоматически. Чтобы его увидеть, необходимо установить в 
True свойство Visible объекта Application. Это — правило для большинства 
объектов Автоматики. 


    Правила области определения 

    Если установлена объектная ссылка на лист или диаграмму Microsoft Excel и 
объектная переменная выходит из области определения, лист или диаграмма 
автоматически закрываются. 
    Если установлена ссылка на объект Application и объектная переменная 
выходит из области определения, Microsoft Excel автоматически не закрывается. 
Закрыть его можно методом Quit объекта Application. 


    Глава 7. СОМ и создание клиентов ActiveX	181 


    7.6.3. Использование методов Microsoft Excel 

    Объекты, доступные в Microsoft Excel, обеспечивают ряд полезных методов и 
свойств. В этом разделе описываются некоторые из методов объекта Microsoft 
Excel Workbook и его семейства. 
    Для создания новых рабочих книг, открытия существующих рабочих книг и их 
закрытия используется семейство Workbooks. В следующем примере в семейство 
Workbooks добавляется новая рабочая книга: 

    xl.Workbooks.Add   () 

    Этот код открывает конкретную рабочую книгу: 

    xl.Workbooks.Open   "c:\bookl.xls   " 

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

    Dim  xl   as   Excel.Application 
    Dim  xlwb   as   Excel.WorkBook 
    On  Error  Resume  Next 
    set   xl   =  CreateObject("Excel.Application") 
    set   xlwb  =  xl.Workbooks.Open   ("c:\bookl.xls") 
    If  Err   <>   0   Then 
    Msgbox   "Ошибка   при  открытии  рабочей  книги" 
    Unload Me EndTf        "~~ 

    В следующем примере показано, как использовать оператор For...Each для 
выполнения итераций по объектам семейства Workbooks, чтобы определить, открыта 
ли определенная рабочая книга: 

    For  each  xlwb   in  xl.WorkBooks 
    if  xlwb.Name   =   "Bookl.xls"   Then bookfound =  True Exit   For End   
If Next   xlwb 

    Закрыть рабочую книгу можно с помощью метода Close объекта Workbook. Если 
для определения, была ли сохранена рабочая книга, не используется параметр 
SaveChanges, пользователю будет выведено приглашение перед закрытием сохранить 
изменения в рабочей книге. 
    В следующем примере закрывается активная рабочая книга: 

    xl.ActiveWorkbook.Close   SaveChanges   :=   False Эта строка закрывает 
рабочую книгу Bookl .xls 
    xl.Workbooks ("BOOKl.XLS") .Close   SaveChanges   :=False 

    7.6.4. Получение и установка значений 

    Для ввода значения в ячейку рабочего листа используется метод Range 
объекта Worksheet. Специфицировать интервал в рабочем листе можно установкой 
ссылки на ячейку, например А1, или использовать именованный интервал. 
    В следующем примере устанавливается объектная переменная Sheet'1. Затем 
устанавливается значение ячейки А1 и значение именованного интервала range"!: 


    182	Создание приложения-клиента, использующего Microsoft Excel; 

    set xlsheet = _     
    xlapp.Workbooks ("Bookl") .Worksheets ("Sheetl") xlsheet.Range("Al").Value 
= 5 xlsheet.Range("rangel").Value = 10 

    Метод Range возвращает объект Range. Объект Range — группа ячеек рабочего 
листа Ниже показаны различные способы установки значения интервала: 

    set xl = CreateObject("Excel.Application") 
    ' Явное описание точной иерархии 
    xl.Workbooks("x.xls").Worksheets("s").Range("Al").Value = 5 
    ' Текущая активная рабочая книга и рабочий лист xl .'Range ("A2") .Value = 5 
    ' Установка объектной переменной Set wb = xl.Workbooks("source.xls") Set 
ws = wb.Worksheets("sheetl") Set rg = ws.Range("Al") rg.Value = 5 

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

    Установить значения для группы ячеек можно с использованием массива. При 
этом сокращается количество вызовов Microsoft Excel и повышается эффективность 
приложения по сравнению с установкой одного значения за вызов. В следующем 
фрагменте заполняется массив значений, который передается Microsoft Excel за 
один вызов: 

    Dim  x(l   to   4,    1   to   2)   As   Integer 
    x(l,l)   =   5 
    x(l,2)   =  5 
    x(l,3)   =   6 
    ....'   Либо  добавить   другой  код  заполнения  массива 
    xl.Range("Al:B4").Value   =  х   '   Передать   весь   массив   значений 

    Можно отобрать интервал ячеек_в переменную типа Variant и заполнить 
Variant массивом: 

    '   Отобрать   интервал   значений 
    varl   =  xl.Range("Al:B4").Value 
    MsgBox  v(l,l)    '   Variant   содержит  массив 

    Можно также пройти в цикле через интервал ячеек, используя оператор For...Each: 

    Dim  r   as   Range 
    For each r in xl.Range("summary") ' Именованный массив 
    r.value = 25 Next r 


    7.6.5. Использование семейства Charts 

    С помощью Автоматики можно обратиться к возможностям составления диаграмм 
Microsoft Excel. Для создания, изменения или открытия существующих диаграмм, 
используя семейство Charts Microsoft Excel. В следующем коде в рабочем листе 
Microsoft Excel выбирается ряд ячеек и на базе выбора создается диаграмма: 

    xlsheet.Range("Al:D4").Select 
    set  xlc  =  xl.Charts.Add() 
    xlc.Type   =  xlSDColumn   '   Тип  диаграммы  -   ЗП-гистограмма 

    Этот код устанавливает ссылку на существующую диаграмму и затем изменяет 
тип диаграммы: 


    Глава 7. СОМ и создание клиентов ActiveX 183 


    set   xlc  =xl.workbooks("bkl.xls").Charts("mycht") xlc.Type   =   x!3DColumn 

    В следующем фрагменте (процедура ClickQ кнопки cmdCreateChart) открывается 
Microsoft Excel, устанавливаются значения в рабочем листе и на базе этих 
значений создается диаграмма: 

    Sub   cmdCreateChart_Click() 
    Dim  xl   As   Excel.Application 
    Dim  xlc  As   Excel.Chart 
    Set   xl   =   CreateObject("Excel.Application") 
    xl.Visible   =   True 
    xl.Workbooks.Add 
    xl.Range("Al").Value   =   3 
    xl.Range("A2").Value   =   2 
    xl.Range("A3").Value  =   6 
    xl.Range("A4").Value   =   4 
    xl.Range("A5").Value   =   8 '    ...   либо  другой  код   заполнения   ячеек 
    xl.Range("Al:A5").Select 
    Set  xlc   =  xl.Charts.Add() 
    xlc.Type   =  x!3DColumn End  Sub 
    X Microsoft Excel - Книга2 

    Рис. 7.16. Создание диаграммы в Microsoft Excel из Visual Basic. 


    184	Создание приложения-клиента, использующего Microsoft Excel 

    7.6.6. Запуск процедур Microsoft Excel 

    Если в Microsoft Excel создана процедура, посредством Автоматики можно 
выполнить з~; процедуру из Visual Basic. Для этого используется метод Run 
объекта Application. 
    Например, допустим, что в Microsoft Excel создана следующая процедура: 

    Sub ChangeNumbers () 
    For Each x In Worksheets("Sheetl").Range("Al:D10") x.Value = Rnd() * 100 
    Next x End Sub 
    Эту процедуру можно выполнить из Visual Basic: 
    Private Sub Commandl_Click() 
    set xl = CreateObject ("Excel.Application") 
    xl.Workbooks.Open ("c:\bookl.xls") 
    xl.Run "ChangeNumbers" End Sub 

    Ниже показана процедура Microsoft Excel, которая возвращает значение: 

    ' Перевод слов строки в регистр имен собственных Function MakeProper 
(MyString As String) As String 
    MakeProper = Application.Proper (MyString) End Function 
    Выполнение этой процедуры из Visual Basic: 
    Private Sub Commandl_Click() 
    s = xl.Run ("MakeProper", "процедура Microsoft excel") 
    ' Значение s будет выглядеть как "Процедура Microsoft Excel" 
    End Sub 


    Использование Microsoft Excel Macro Recorder 

    Если приложение Visual Basic передает несколько операторов Microsoft 
Excel, можно нэп сать процедуру Microsoft Excel, в которой для выполнения 
процедуры будет использовать^ Visual Basic. 
    Простой способ начать писать код Автоматики в Visual Basic — обратиться к 
Microsoft Exc Macro Recorder. Сгенерированный здесь код можно затем 
импортировать из Microsoft Ехк в приложение Visual Basic. 
    Однако, если используется этот подход, в импортируемый код потребуется 
внести_некотг рые изменения. Например, в Visual Basic нужно будет создать 
экземпляр Microsoft Exce добавив оператор с ключевым словом New. 
    Также операторы Visual Basic придется предварять объектной переменной, 
которая будь ссылаться на Microsoft Excel. 
    Ниже приводится пример кода, сгенерированного Microsoft Excel Macro Recorder: 

    Sub  Macrol 
    ActiveWorkbook.SaveAs Filename:="TERMPAPR.XLS", FileFormat:=xlNormal,_ 
Password:="", WriteResPassword:="", _ ReadOnlyRecommended:=False , CreateBackup:=False 
    End Sub 

    В этом коде показаны модификации, введенные для Visual Basic: 


    Глава 7. СОМ и создание клиентов ActiveX 185 

    f. 
    Dim xl As Excel .Application—~<v •..-.,> 
    Set xl = New Excel.Application^ 
    ,xl_^Workbooks -Acid   _...._,.....—-__—-^ 
    xl.ActiveWorkbook.SaveAs Filename:="TERMPAPR.XLS", FileFormat:=xlNormal,_ 
    Password:="", WriteResPassword:="", _ ReadOnlyRecommended:=False , CreateBackup:=False 


    7.6.7. Пример: Управление Microsoft Excel 

    В этом примере с помощью механизмов Автоматики осуществляется управление 
Microsoft Excel. На следующей иллюстрации показана часть рабочей книги с 
коммерческой информацией: 

    Е7	^J	= ! Ш7 
    А	в		с	D           | .	Е.        ! 
    4 
    5 .._ 
    7 
    Оценка роста Оценка инфляции 
    9 
    10" 
    И 
    12 
    13 
    14 
    15 
    16 
    | Финансовый период 1	Фактически  Фактически 1995       1996		Оценка 
    19971 
    „„._ ________ Й0ходы| Цена товаров	1 759 050 431 250	1 91 7 365 448 500	2 
089 927 466 440 
    Прибыль [ Маркетинг	1 327800 118125	1 468 865 1 22 850	1 623 487 127764 
    Транспорт ( Зарплата |	77800 315000	80912 327600	84148 340 704 
    Страхование) Расходы)	1 2 670 523595	13177 544539	1 3 704 566 320 
    Чистая прибыль Г	304 205	924 326	1 057 167 

    Рис. 7.17. Коммерческая информация в Microsoft Excel. 


    Создание проекта 

    1. Запустить новый проект Visual Basic. 
    2. Построить следующую форму: ii Управление Excel 
    Исходная информация Оценка роста 
    Оценка инфляции 
    |,|Д|.х Создать объект Excel 
    Оценить прибыль Диаграмма 

    Рис. 7.18. Форма для взаимодействия с Excel. 


    186	Создание приложения-клиента, использующего Microsoft Excel 

    Создание экземпляра объекта — приложения Microsoft Excel 
    1. Добавить к проекту ссылку на библиотеку Microsoft Excel 5.0 Object Library. 
    2. Добавить к проекту стандартный модуль, в котором объявить переменные xl 
и x(Chari: 

    Dim  xl  As   Excel.Application Dim xlc  As  Excel.Chart 

    3. В процедуре обработки события Click кнопки "Создать объект Excel", 
используя функцию CreateObject, создать экземпляр объекта Microsoft Excel 
Application и присвоить этот объект переменной, созданной в предыдущем шаге. 
Дополнительную информацию см. в разделе "Создание экземпляра Microsoft Excel". 
    4. Здесь же установить свойство Visible Microsoft Excel в True. 
    5. Используя метод Open Microsoft Excel, открыть рабочую книгу Market.xls. 
Примерный код процедуры Click(): 

    Private   Sub  cmdCreateXLObject_Click()    '   Кнопка   "Создать  объект  
Ex'-   " set   xl   =   CreateObject("Excel.Application") xl.Workbooks.Open  
App.Path   &   "c:\office\Market.xls" xl.Visible   =   True 
    End  Sub 

    6. Протестировать приложение. 

    Передача информации в Microsoft Excel 
    1. В процедуре обработки события Click для кнопки "Оценить прибыль" 
активировать рабочий лист "Доходы" и установить значения ячеек "Оценка роста" 
(Growth) и "Оценка инфляции" (Inflation) равными значениям текстовых полей 
"Оценка роста" (txtGrowth) и "Оценка инфляции" (txtlnflation) соответственно. 
    Примерный код процедуры кнопки: 

    Private   Sub   cmdEstimate^Click()    '   Кнопка   "Оценить   прибыль" xl.Worksheets("Доходы").Activate 
    xl.Worksheets("Доходы").Range("Growth").Value   =   
txtGrowth.Тех-xl.Worksheets("Доходы").Range("Inflation").Value   -  _ txtlnflation.Text 
    End   Sub 

    2. Протестировать приложение: 

    •   запустить приложение; 
    •   нажать кнопку "Создать объект Excel", чтобы запустить Microsoft Excel 
и открыт рабочую книгу; 
    •   перейти в Visual Basic, ввести проценты в текстовых полях и 
протестировать действ кнопки "Оценить прибыль". 
    Создание диаграммы 
    1. В процедуре обработки события Click кнопки "Диаграмма", если переменная 
xJCharl добавленная выше, установлена в Nothing, используя метод Select, 
выбрать именован-^ ный интервал "Чистая прибыль" (Net_Profit) рабочего листа "Доходы". 
    2. Используя метод Add объекта Chart, создать новую диаграмму в рабочей 
книге и иници-J ализировать переменную xlChart. 
    3. Установить для свойства Туре объекта Chart значение xlSDColumn. Это — 
константа i библиотеки объектных модулей Microsoft Excel. 


    :е/ Глава 7. СОМ и создание клиентов ActiveX 187 

    !Ю 
    эт в 
    4. Если переменная xlChart не установлена в Nothing, можно использовать 
метод Activate, чтобы сделать диаграмму активным листом. 
    Примерный код процедуры: 

    Private   Sub   cmdChart_Click()    '   Кнопка   "Диаграмма" If  xlc   Is  
Nothing  Then 
    xl.Worksheets("Доходы").Range("net_profit").Select set  xlc  =  
xl.Charts.Add() xlc. Type   =  xlSDColumn Else 
    xlc.Activate End   If End   Sub 

    5. Протестировать приложение: 
    •   запустить приложение; 
    •   нажать кнопку "Создать объект Excel", чтобы запустить Microsoft Excel 
и открыть рабочую книгу; 
    •   перейти в Visual Basic и нажать кнопку "Диаграмма". 

    Ряд1 
    Значение 1 098 724 (33л; 

    Рис. 7.19. Диаграммы Excel с разными значениями свойства Туре. 

