Обложка
Титульный
Аннотация
Предисловие
ГЛАВА 1. Введение в VISUAL BASIC
1.2. Редакции Visual Basic 5
1.3. Создание приложений в Visual Basic
1.3.2. Использование панели элементов
1.3.3. Работа со свойствами
1.3.4. Работа с меню
1.4. Написание программного кода
1.4.2. Область определения программного кода
1.4.3. Переменные, константы и типы данных
1.4.4. Использование типов данных
1.4.5. Область определения переменных
1.4.6. Период существования переменных
1.5. Обработка вводимой информации и управление ошибками
1.5.2. Обработка данных поля
1.5.3. Управление интерфейсом и информацией формы
1.5.4. Отключение обработки ошибок
1.6. Компиляция приложения и построение ЕХЕ-файла
ГЛАВА 2. РАБОТА С ДАННЫМИ ЧЕРЕЗ ЭЛЕМЕНТ УПРАВЛЕНИЯ DATA
2.1.2. Другие методы доступа к данным
2.2. Основы организации данных
2.3. Работа с элементом управления Data
2.3.2. Некоторые свойства и методы элемента управления Data
2.3.3. Объект Recordset
2.3.4. Свойства и методы объекта Recordset
2.3.5. Мастер Data Form Wizard
2.3.6. Пример использования мастера Data Form Wizard
2.4. События элемента управления Data
2.4.2. Событие Reposition
2.4.3. Событие Error
2.5. Использование связанных элементов управления ActiveX
2.5.2. Элемент управления MSFIexGrid
2.5.3. Элемент управления DBCombo
ГЛАВА 3. РАБОТА С ДАННЫМИ ЧЕРЕЗ ИНТЕРФЕЙС DAO
3.1.2. Открытие и закрытие базы данных
3.2. Работа с наборами записей
3.2.2. Типы объектов Recordset
3.2.3. Вывод записей в форме
3.2.4. Навигационные свойства
3.2.5. Пример создания и перемещения по набору записей
3.3. Работа с данными
3.3.2. Добавление записей
3.3.3. Удаление записей
3.4. Совместное использование DAO и элемента управления Data
3.5. Поиск записей
3.5.2. Поиск в наборах типа table
3.5.3. Пример поиска записей в наборе
3.6. Использование запросов и операторов SQL
3.6.2. Запросы действия
3.6.3. Компоненты языка SQL
3.6.4. Использование операторов SQL в коде Visual Basic
3.6.5. Пример использования запросов SQL
3.6.6. Пример использования параметрических запросов
ГЛАВА 4. РАСШИРЕННЫЕ ВОЗМОЖНОСТИ ПРОГРАММИРОВАНИЯ ДОСТУПА К ДАННЫМ
4.1.2. Ссылочная целостность
4.1.3. Транзакции
4.2. Вопросы многопользовательского доступа
4.2.2. Блокировка ядра базы данных Microsoft Jet
4.2.3. Обработка ошибок блокировки
4.3. Работа с внешними данными
4.3.2. Работа с базами данных ISAM
4.3.3. Работа с файлами данных
4.4. Работа с базами данных ODBC
4.4.2. Соединение с удаленным источником данных
4.4.3. Отбор удаленных данных
4.5. Вопросы производительности
ГЛАВА 5. СОЗДАНИЕ ОТЧЕТОВ С ПОМОЩЬЮ CRYSTAL REPORTS
5.1.2. Специфицирование типов баз данных, представленных в окне диалога Choose Database File
5.1.3. Специфицирование умолчательного представления, используемого при предварительном просмотре отчета
5.1.4. Специфицирование умолчательных шрифтов для разделов отчета
5.1.5. Специфицирование сервера SQL/ODBC как основного источника данных
5.1.6. Специфицирование шаблона отчета как основного источника данных
5.1.7. Специфицирование умолчательных установок форматирования полей
5.2. Построение отчетов
5.2.2. Выбор источника данных
5.2.3. Связывание таблиц базы данных
5.2.4. Режим Design
5.2.5. Выбор полей для отображения в отчете
5.2.6. Перемещение, изменение размера, форматирование и удаление полей
5.2.7. Сортировка данных отчета
5.2.8. Группирование данных отчета
5.2.9. Получение итогов и промежуточных сумм
5.2.10. Выбор записей
5.2.11. Добавление графика/диаграммы
5.2.12. Объекты OLE
5.2.13. Добавление заголовка отчета
5.2.14. Предварительный просмотр отчета
5.3. Работа с формулами
5.3.2. Значение поля группы
5.3.3. Комментарии формул
5.3.4. Синтаксис формул
5.3.5. Порядок вычислений в формулах
5.3.6. Удаление формул из отчета
5.3.7. Копирование формул из оперативной справки
5.3.8. Функции
5.3.9. Операции
5.3.10. Переменные
5.4. Элемент управления Crystal
5.4.2. Проектирование пользовательского интерфейса
5.4.3. Подключение элемента управления Crystal к проекту
5.4.4. Применение элемента управления Crystal
5.5. Свойства элемента управления Crystal
5.6. Методы элемента управления Crystal
ГЛАВА 6. РАБОТА С БИБЛИОТЕКАМИ ДИНАМИЧЕСКОЙ КОМПОНОВКИ
6.1.2. Библиотеки Windows API
6.1.3. Использование API Viewer
6.1.4. Загрузка объявления из базы данных
6.1.5. Использование DLL cVisual Basic
6.2. Объявление процедуры DLL
6.2.2. Гибкие типы параметров
6.2.3. Библиотеки ANSI и Unicode
6.3. Вызов DLL
6.3.2. Передача параметров по значению и по ссылке
6.3.3. Передача строковых значений
6.4. Дополнительная информация по DLL
6.4.2. Использование процедур-оболочек
6.4.3. Полезные DLL
6.4.4. Пример: Нахождение расположения папки Windows
6.4.5. Пример: Создание окна \
ГЛАВА 7. СОМ И СОЗДАНИЕ КЛИЕНТОВ ACTIVEX
7.1.2. Компонентные приложения
7.1.3. Облегчение настройки приложения
7.1.4. Библиотеки компонентов
7.1.5. Распределенные компоненты
7.1.6. Требования к компонентам
7.1.7. Динамическая компоновка
7.1.8. Инкапсуляция
7.1.9. Спецификация СОМ
7.1.10. Использование интерфейсов
7.1.11. Взаимодействие клиента с сервером
7.2. Реализация Автоматики
7.2.2. Библиотеки типов
7.2.3. Объектные модели
7.2.4. Интерфейс IDispatch
7.2.5. Двойные интерфейсы
7.2.6. Введение в связывание
7.3. Характеристики компонентов сервера
7.3.2. Определение расположения компонентов сервера
7.3.3. Уведомление клиентов
7.4. Создание клиента в Visual Basic
7.4.2. Второй шаг: объявление объектных переменных
7.4.3. Третий шаг: создание объектов
7.4.4. Четвертый шаг: использование объектов Автоматики
7.5. Прием сообщений от серверов
7.5.2. Сообщения сервера, использующие обратные вызовы
7.5.3. События или обратные вызовы
7.6. Создание приложения-клиента, использующего Microsoft Excel
7.6.2. Создание экземпляра Microsoft Excel
7.6.3. Использование методов Microsoft Excel
7.6.4. Получение и установка значений
7.6.5. Использование семейства Charts
7.6.6. Запуск процедур Microsoft Excel
7.6.7. Пример: Управление Microsoft Excel
ГЛАВА 8. СОЗДАНИЕ ПРОГРАММНЫХ КОМПОНЕНТОВ ACTIVEX
8.1.2. Документы ActiveX
8.1.3. Программные компоненты ActiveX
8.1.4. Преимущества использования компонентов ActiveX
8.2. Создание объектов в Visual Basic
8.2.2. Создание экземпляра класса
8.2.3. События модуля класса
8.2.4. Создание методов
8.2.5. Создание свойств
8.2.6. Использование процедур РгореИудпя создания свойств
8.2.7. Использование Class Builder
8.3. Работа с программными компонентами ActiveX
8.3.2. Установка свойств проекта
8.3.3. Установка свойств модуля класса
8.3.4. Компиляция компонента
8.3.5. Регистрация компонента
8.4. Тестирование программных компонентов ActiveX
8.4.2. Установка ссылки на библиотеку типов
8.4.3. Отладка компонента
8.4.4. Способы обработки ошибок
8.4.5. Инициирование ошибок выполнения
8.5. Использование событий
8.5.2. Обработка событий в приложении-клиенте
8.5.3. Выполнение с помощью событий асинхронных вызовов
8.6. Реализация интерфейса
8.7. Прочие аспекты программных компонентов
8.7.2. Информация о компоненте и Help
8.7.3. Глобальность данных
8.7.4. Объявление методов Friend
8.7.5. Создание объектной модели
8.7.6. Хранение объектов в семействах
8.7.7. Совместимость версий
8.7.8. Управление занятым компонентом
8.8. Пример: Создание программного компонента
8.8.2. Создание свойств и методов
8.8.3. Создание приложения-клиента
8.9. Пример: Определение и использование событий
ГЛАВА 9. СОЗДАНИЕ ЭЛЕМЕНТОВ УПРАВЛЕНИЯ ACTIVEX
9.1.2. Элементы управления — компоненты
9.1.3. Элементы управления ActiveX и программные компоненты
9.1.4. Объект UserControl
9.1.5. Тиражирование элементов управления ActiveX
9.1.6. Шаги создания элемента управления ActiveX
9.2. Создание пользовательского интерфейса элемента управления
9.2.2. Настройка размера элемента управления
9.2.3. Настройка пользовательского интерфейса
9.2.4. Создание элемента управления — контейнера
9.2.5. Добавление окна About
9.2.6. Специфицирование пиктограммы для панели элементов
9.3. Тестирование элемента управления
9.3.2. Отладка элемента управления и обработка ошибок
9.3.3. Экземпляры и события элементов управления
9.4. Предоставление свойств, методов и событий
9.4.2. Добавление методов
9.4.3. Использование общих свойств контейнера
9.4.4. Хранение и получение значений свойств
9.4.5. Использование именованных констант
9.4.6. Инициирование событий элемента управления
9.4.7. Использование мастера ActiveX Control Interface Wizard
9.5. Создание страниц свойств
9.5.2. Программирование поведения страниц свойств
9.5.3. Установление отношений страниц свойств
9.5.4. Использование стандартных страниц свойств
9.6. Тиражирование элемента управления
9.6.2. Создание программы установки элемента управления
ГЛАВА 10. СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ ДОКУМЕНТОВ ACTIVEX
10.1.2. Документы ActiveX и внедренные объекты
10.1.3. Преимущества документов ActiveX
10.1.4. Internet Explorer и Office Binder
10.1.5. Документы ActiveX в Visual Basic
10.2. Работа с проектами документов ActiveX
10.2.2. Создание проекта документа ActiveX
10.2.3. Компиляция проекта документа ActiveX
10.2.4. Размещение документа ActiveX в контейнере
10.2.5. События пользовательскогодокумента
10.2.6. Различия между контейнерами документов
10.2.7. Определение типа контейнера документа
10.3. Тестирование и отладка документов ActiveX
10.3.2. Тестирование документа ActiveX в контейнере
10.3.3. Определение среды периода выполнения
10.4. Многодокументные проекты
10.4.2. Использование глобальныхссылок
10.4.3. Создание свойств
10.5. Пользовательский интерфейс и пользовательский документ
10.5.2. Добавление меню к пользовательскому документу
ГЛАВА 11. СОЗДАНИЕ ПРИЛОЖЕНИЙ ДЛЯ INTERNET
11.1.2. Применения гнезд
11.1.3. Элемент управления Winsock
11.1.4. Базовые операции с элементом управления Winsock
11.1.5. Программирование сервера Winsock
11.1.6. Программирование клиента Winsock
11.1.7. Прием и передача данных
11.2. Установление соединений FTP и HTTP в Internet
11.2.2. Базовые операции с элементом управления Internet Transfer
11.2.3. Программирование асинхронных операций
11.2.4. Программирование синхронных операций
11.2.5. Использование элемента управления WebBrowser
11.2.6. Применение элемента управления WebBrowser
11.2.7. Основные операции с WebBrowser
11.2.8. Программирование навигации в WebBrowser
11.3. Использование Автоматики с Internet Explorer
11.4. Работа с Personal Web-Server
11.4.2. Запуск Personal Web-Server
11.5. Пример: Создание приложения для работы в Internet
11.5.2. Программирование приложения
ГЛАВА 12. СОЗДАНИЕ ПРОГРАММЫ SETUP И ОПТИМИЗАЦИЯ ПРИЛОЖЕНИЯ
12.1.2. Файлы установки
12.1.3. Использование пакета Visual Basic Setup Toolkit
12.1.4. Удаление приложения
12.2. Оптимизация приложения
12.2.2. Сохранение установок приложения
12.2.3. Аспекты оптимизации
12.2.4. Протокол событий
12.2.5. Повышение производительности разработки
12.2.6. Использование MicrosoftVisual SourceSafe
12.2.7. Установка Visual SourceSafe
12.2.8. Добавление проекта к Visual SourceSafe
12.2.9. Использование файлов ресурсов
Содержание
Текст
                    ActiveX,  DLL,  Internet  идругие...
Разработка  приложений  и  компонентов
 MICROSOFT
VISUAL  BASIC  5.0
 ВОРОНЦОВ  С.  И.,  ХРАМОВ  И.  А.


Воронцов С. И., Храмов И. А. Microsoft Visual Basic 5.0: ActiveX, DLL, Internet и другие ... "COJlOH" Москва 1998 год
Воронцов С. И., Храмов И. А. Microsoft Visual Basic 5.0: ActiveX, DLL, Internet и другие ... Microsoft Visual Basic — сегодня самая популярная в мире система проектирования прило¬ жений для Windows. В предлагаемой книге в первых главах дается обзор возможностей, которыми сегодня располагает разработчик в Visual Basic. Освещаются основные положения реализованной в Visual Basic модели событийно-управляемого программирования, кратко рассматривают¬ ся элементы языка Visual Basic, общие шаги процедур визуального проектирования, созда¬ ния интерфейса приложения и написания программного кода. Далее описываются простые и расширенные возможности доступа и работы с данными: работа с данными через элемент управления Data и через интерфейс DAO. Освещается объектная модель и реализованные в DAO возможности программирования доступа к данным. Подробно рассматривается в книге и такой важный раздел создания приложений (о котором часто "забывают"), как построение отчетов для распечатки твердых копий документов. Ряд глав книги адресуется достаточно искушенным разработчикам. Здесь подробно обсуждают¬ ся животрепещущие вопросы, волнующие сегодня программиста, но которые в значитель¬ ной мере обделены вниманием в литературе. Это такие темы, как: создание и работа с библиотеками динамической компоновки (DLL); применение прогрессивной технологии СОМ (Компонентная Объектная Модель); создание компонентов ActiveX — элементов управления, документов и программных компонентов; реализация в Visual Basic возможно¬ стей построения средств доступа и работы в Internet и внутренних сетях; инструментарий для создания дистрибутивных пакетов для тиражирования программ. Ответственный за выпуск С. Иванов Макет и верстка С. Тарасов Обложка А. Микляев ISBN 5-85954-072-8 ©"СОЛОН" 1998 © Воронцов С. И., Храмов И. А.
Предисловие 3 Предисловие Microsoft Visual Basic — сегодня самая популярная в мире система проектирования прило¬ жений для Windows. Среда Visual Basic может с успехом использоваться начинающими пользователями для познания секретов программирования и увлекательных занятий по созданию несложных (поначалу) приложений и, в то же время, предоставляет мощные инструменты разработки опытным программистам. Чрезвычайно развитые справочная сис¬ тема, средства обучения, мастера и программы-надстройки позволяют при построении приложения и работе в Visual Basic найти выход из любой ситуации и получить ответ на любой вопрос. Начинать работать с Visual Basic можно практически с любым уровнем подготовки. Шесть лет назад Microsoft Corporation совершила революцию в подходах к разработке приложений. Свершилось невероятное: начинающие программисты получили возможность писать программы для Windows! Как результат популярность профессии программиста возросла до небес и сегодня в мире только на Visual Basic работают, по оценке Microsoft, четыре миллиона программистов, с невиданной до этого производительностью создавая решения на любой вкус — от программ, обслуживающих рутинные операции ввода данных, до сложных информационных коммуникационных систем. Visual Basic версии 5.0 предоставляет широкую гамму инструментальных средств, среди которых все необходимое для себя найдет как начинающий программист, возможно, лишь недавно решивший попробовать что-то создать (для него есть редакции Standard и Lear¬ ning), так и "зубр" в программировании (редакции Professional и Enterprise). Новичок, напри¬ мер, сможет с помощью мастера Application Wizard для начала создать первую версию приложения, на примере которого затем можно будет изучить азы визуального программи¬ рования и подходы Visual Basic. Перед опытным мастером возможности в Visual Basic вообще безграничны: это и создание собственных компонентов ActiveX, и работа с широким диапазоном данных, и реализация технологий Internet, и, наконец, доступ к самым сокровен¬ ным возможностям Windows. В предлагаемой книге в первых главах дается обзор возможностей, которыми сегодня располагает разработчик в Visual Basic. Описываются основные положения реализованной в Visual Basic модели событийно-управляемого программирования, кратко рассматривают¬ ся элементы языка Visual Basic, общие шаги процедур визуального проектирования и создания интерфейса приложения и написания программного кода. Далее описываются простые и расширенные возможности доступа и работы с данными, а также подробно рассматривается такой важный раздел создания приложений, как построение отчетов для распечатки твердых копий документов. Главы с 6-ой по 12-ю адресуются достаточно искушенным разработчикам. Здесь подробно излагаются "животрепещущие" вопросы, волнующие сегодня программиста: создание и работа с библиотеками динамической компоновки (DLL); дается обзор прогрессивной тех¬ нологии СОМ (Компонентная Объектная Модель); подробно описываются шаги создания компонентов ActiveX — элементов управления, документов и программных компонентов; рассматриваются реализованные в Visual Basic возможности построения средств доступа и работы в Internet и внутренних сетях; описываются средства создания дистрибутивных пакетов для тиражирования разрабатываемых проектов Visual Basic.
4 Событийно-управляемое программирование Глава 1. Введение eVisual Basic В этой главе тезисно описываются некоторые из базовых концепций Visual Basic. В сравне¬ нии с процедурной моделью структурного программирования представлена реализованная в Visual Basic 5 событийно-управляемая модель. Далее рассматриваются общие шаги процедур визуального проектирования, создания интерфейса приложения, написания и отладки программного кода, компиляции приложения. Материал этой и следующей главы позволит читателю быстро начать строить простые приложения, которые в дальнейшем можно будет развивать и совершенствовать. 1.1. Событийно-управляемое программирование В традиционной, или процедурной, модели приложение управляет последовательностью, в которой выполняются части программного кода. Выполнение приложения начинается с первой строки кода и следует стандартным путем через приложение; программные проце¬ дуры вызываются по мере необходимости. Visual Basic происходит из языка структурного программирования BASIC. В нем, однако, реали¬ зуется событийно-управляемая модель программирования. В событийно-управляемом прило¬ жении выполнение не следует предопределенным путем. Вместо этого программа отрабатывает различные разделы кода в ответ на события. События могут быть вызваны действиями пользователя, сообщениями от системы или другого приложения или самим при¬ ложением. Последовательность выполнения кода определяется последовательностью собы¬ тий. Следовательно, поток выполнения кода приложения в каждом сеансе будет другим. Существенная часть событийно-управляемого программирования состоит в написании ко¬ да, призванного отвечать на возможные события, которые могут происходить в приложении. Visual Basic для реализации событийно-управляемой модели предоставляет все необходи¬ мые средства. На следующей иллюстрации показаны некоторые действия, генерирующие события, на которые можно отвечать, написав и ассоциировав с ними программный код. Эти события могут происходить в любом порядке. Ввод значенияв поле Рис. 1.1. Инициирование событий. Таким образом, событийно-управляемая модель программирования предполагает наличие в компиляторе (или процессоре системы программирования) некоего блока, реагирующего на события по схеме: IF Событие THEN Действие, где Действие — программная процедура, определенная разработчиком, либо некоторое умолчательное действие Visual Basic.
Гпава 1. Введение в Visual Basic 5 1.2. Редакции Visual Basic 5 Visual Basic версии 5 доступен в трех редакциях, каждая из которых обеспечивает опреде¬ ленный набор инструментов разработки. StandardEdition Visual Basic Standard Edition позволяет создавать достаточно мощные приложения для Microsoft Windows 95 и Windows NT. Эта редакция включает все встроенные элементы управления Visual Basic, включая связанные (data-bound) элементы управле¬ ния. Professional Edition Редакция Professional обеспечивает полно-функциональный на¬ бор инструментальных средств для разработки профессиональ¬ ных решений, предназначенных для тиражирования. Она включает все возможности Standard Edition плюс дополнитель¬ ные элементы управления ActiveX, включая элементы управле¬ ния для Internet и генератор отчетов Crystal Reports для Visual Basic (рассматривается в главе 5). Примечание: Элемент управления ActiveX — подключаемый объект, который можно помещать в форму, чтобы активировать или расши¬ рить взаимодействие пользователя с приложением. С элементами управления ActiveX ассоциируются события, и они могут быть вклю¬ чены в другие элементы управления. Эти элементы управления име¬ ют расширение имени файла .ocx. Enterprise Edition Редакция Enterprise позволяет создавать распределенные при¬ ложения силами группы разработчиков. Она обеспечивает все возможности редакции Professional и включает также дополни¬ тельные функции, такие, как Automation Manager, Component Ma¬ nager, инструментальные средства управления базами данных и Microsoft Visual SourceSafe — проект-ориентированная система управления версиями продуктов. 1.3. Создание приложений BVisual Basic Создание приложения в Visual Basic включает следующие два базовых шага: 1. Построение пользовательского интерфейса приложения. 2. Написание программного кода, который отвечает на действия, предпринимаемые в поль¬ зовательском интерфейсе. 1.3.1. Разработка интерфейса пользователя Первый шаг при создании приложения Visual Basic заключается в проектировании форм, которые будут использоваться в приложении, а также меню и панелей инструментов. Пользователи обычно требуют приложения, которые просты в освоении и позволяют быстро повысить продуктивность их труда. Поэтому проектировать формы как главный компонент интерфейса, следует тщательно, постоянно взаимодействуя с пользователями, отыскивая оптимальную компоновку. 1.3.2. Использование панели элементов Используя панель элементов, разработчик рисует или помещает в форму элементы управ¬ ления, создавая визуальные компоненты приложения. Панель элементов содержит встро¬
6 Создание приложений в Visual Basic енные элементы управления Visual Basic и подключенные элементы управления ActiveX или любые внедряемые объекты, которые разработчик добавил к проекту. Если панель элементов закрыта, ее можно открыть, щелкнув соответствующую кнопку панели инстру¬ ментов либо выбрав команду Toolbox в меню View. Панель элементов доступна только во время разработки. В панели элементов можно создать несколько вкладок элементов управления Рис. 1.2. Панель элементов Visual Basic (умолчательная компоновка изменена). Чтобы поместить элемент управления в форму, можно либо дважды щелкнуть кнопку элемента управления, либо щелкнуть ее один раз и обозначить элемент управления на полотне формы. Добавление элементов управления к панели элементов Панель элементов может быть расширена добавлением к ней элементов управления Acti¬ veX. Дополнительные элементы управления ActiveX доступны в редакциях Visual Basic Professional и Enterprise. Можно также подключать элементы управления ActiveX сторонних разработчиков или свои собственные. Чтобы добавить элемент управления ActiveX к панели элементов: 1. В меню Project выбрать команду Components или ввести <Ctrl + T>. Visual Basic выводит на экран окно диалога Components (рис. 1.3). 2. На вкладке Controls установить флажок элемента управления, который требуется под¬ ключить к проекту, и затем щелкнуть OK или Применить. Visual Basic добавляет элемент управления к панели элементов. Именование элементов управления При именовании элементов управления рекомендуется следовать стандартным соглашени¬ ям именования пользовательского интерфейса и элементов управления. Это позволяет упростить чтение и отладку программного кода. В именах элементов управления удобно проставлять префикс, однозначно указывающий на тип (класс) этого объекта. Ниже приве¬ дены рекомендуемые соглашения для некоторых элементов управления Visual Basic. Тип элемента управления Префикс Пример AniButton ani aniMailBox CheckBox chk chkReadOnly ComboBox cbo cboRussian CommandButton cmd cmdExit CommonDialog dlg dlgFileOpen Элемент управления (используется в процеду¬ рах, когда конкретный тип не определен) ctr ctrUnknown
Гпава 1. Введение в Visual Basic 7 Рис. 1.3. Окно диалога Components. Тип элемента управления Префикс Пример Data control dat datOrders Data-bound ComboBox dbcbo dbcboLanguage Data-bound Grid dbgrd dbgrdQueryResult Data-bound list box dblst dblstSchetType Directory ListBox dir dirSource Drive ListBox drv drvSource File ListBox ^ filSource Form frm frmSchet Frame fra fraLanguage Gauge gau gauStatus Grid grd grdTovar Horizontal ScrollBar hsb hsbVolume Image img imglcon Label Jb| lblHelp Line lin linVertical ListBox lst lstOrder MAPI message mpm mpmSentMessage
8 Создание приложений в Visual Basic Тип элемента управления Префикс Пример ~мс1 mci mciVideo MDI Child Form mdi mdiNote Menu mnu mnuFileOpen MS FlexGrid msg msgClients MS Tab mst mstFirst OLE ole oleWorksheet Outline out outOrgChart Picture pic picVGA PictureClip clp clpToolbar Shape shp shpCircle Spin spn spnPages TextBox b<t txtFIO Timer tmr tmrAlarm UpDown upd updDirection Vertical ScrollBar vsb vsbRate Slider sld sldScale lmageList ils ilsAlllcons Toolbar ~Ub tlbActions StatusBar sta staDateTime ListView lvw lvwHeadings ProgressBar prg prgLoadFile RichTextBox rtf rtfReport Работа с объектами и классами Объект — комбинация кода и данных, которая обрабатывается как единица. Объект может быть элементом приложения, таким как элемент управления или форма. Он может также представлять все приложение. Класс — шаблон для объекта, точно так же, как чертеж на синьке — шаблон для детали или дома. Все объекты создаются как идентичные копии, или экземпляры, их класса. После того, как они созданы и существуют как отдельные объекты, их свойства могут быть изменены, причем эти изменения никак не воздействуют ни на сам класс, ни на другие экземпляры. В Visual Basic каждый объект также определен классом. Элементы управления в панели элементов представляют классы. Когда элемент управления размещается на форме, созда¬ ется объект класса этого элемента управления. Использование свойств и методов объекта Все объекты имеют свойства и методы. Свойства — значения, которые устанавливаются для определения вида и поведения объекта. Методы — программные процедуры, обеспе¬ чивающие выполнение объектом некоторых предопределенныхдействий. Например, форма обеспечивает метод Show, который обусловливает вывод формы на экран. Главное преимущество работы с объектами в том, что объекты обеспечивают программный код, который уже не требуется писать разработчику. Ему просто нужно установить свойства объекта и вызвать методы объекта, чтобы побудить объект выполнить требуемые функции.
Гпава 1. Введение в Visual Basic 9 1.3.3. Работа со свойствами При формировании пользовательского интерфейса приложения Visual Basic для создавае¬ мых объектов необходимо установить свойства. Многие свойства могут быть установлены во время разработки. Чтобы установить эти свойства, можно использовать окно свойств или страницы свойств (окно Property Pages). Примечание: Информацию относительно создания страниц свойств см. в разделе "Создание стра¬ ниц свойств” в главе 9 "Создание элементов управления ActiveX”. Чтобы обратиться к окну свойств, нужно нажать кнопку Properties на панели инструментов либо щелкнуть правой кнопкой мыши объект и затем выбрать Properties, либо в меню View выбрать команду Properties Window, либо нажать клавишу <F4>. Если в форме выделено несколько объектов, в окне свойств выводятся только свойства, общие для всех выделен¬ ных элементов управления. Любые изменения, проведенные в свойстве, применяются ко всем элементам управления. На рис. 1.4 сравните количество свойств в категории Appea¬ rance, выводимых при выборе одного элемента управления (часть А) и группы элементов управления (часть Б). Рис. 1.4. Окно свойств при выборе одного и нескольких элементов управления.
10 Создание приложений в Visual Basic Чтобы выбрать несколько элементов управления, нужно щелкнуть на полотне формы и растянуть мышью область вокруг этих элементов управления. В период выполнения установить или отобрать значения свойств можно, написав соответ¬ ствующий программный код. В следующем фрагменте для текстового поля txtData устанав¬ ливается полужирный стиль шрифта. txtData.Font.Bold = True ' Устанавливает полужирный текст Этот оператор устанавливает значение свойства Text текстового поля txtData: txtData.Text = "Visual Basic 5" ' Установка значения свойства Если имя свойства опустить, устанавливается умолчательное свойство элемента управле¬ ния. Например, умолчательное свойство текстового поля — свойство Text, умолчательное свойство надписи (Label) — свойство Caption. В следующем фрагменте устанавливаются умолчательные свойства Text и Caption для текстового поля и надписи: txtData = "Установка свойства Text или текстового поля" lblData = "Установка свойства Caption надписи" Получение значений свойств в период выполнения Чтобы получить значение свойства в период выполнения, можно использовать примерно следующий код: Dim sName As String sName = txtName.Text 1.3.4. Работа с меню Функциональность приложения можно расширять, добавляя к нему систему меню. Меню обеспечивают пользователей удобным способом доступа и выполнения команд. Menu Editor — интерактивный инструмент, который позволяет создавать и изменять меню с минимумом программирования. С помощью Menu Editor можно добавлять новые команды к существующим меню, заменять существующие команды меню на команды разработчика, со¬ здавать новые меню и строки меню, изменять и удалять существующие меню и строки меню. Чтобы создать меню для формы: 1. Нажать кнопку Menu Editor на панели инструментов (или выбрать команду Menu Editor в меню Tools или ввести с клавиатуры <Ctrl + E>), чтобы вывести на экран окно диалога Menu Editor. 2. В поле Caption ввести имя меню или команды, которое должно появиться в строке меню. 3. Используя кнопки со стрелками вверх и вниз, можно изменять позицию элемента меню в списке. 4. Используя кнопки со стрелками влево и вправо, можно создавать уровни команд меню. Команда без многоточия (без смещения) — название меню в строке меню. 5. При установке флажка Checked команда меню получает пометку (то есть состояние по умолчанию — см. команду "С графикой" на рис. 1.5). 6. Установив или сняв флажок Enabled, можно включить или отключить команду (см. коман¬ ду "Отправить сообщение"). 7. Список Shortcut содержит выборы для назначения командам меню клавиш быстрого доступа.
Гпава 1. Введение в Visual Basic 11 Рис. 1.5. Окно Menu Editor и пользовательское меню. В период выполнения можно изменять вид и расположение меню и добавлять новые элементы меню. Можно также использовать метод PopupMenu для вывода меню на экран в виде контекстного меню. Например, следующая процедура раскрывает контекстное меню mnulnternet в позиции курсора, когда пользователь щелкает на площади формы правой кнопкой мыши. Этот код нужно поместить в раздел Declarations модуля формы: Private Sub Form MouseDown (Button As Integer, Shift As Integer, X As Single, Y As Single) If Button = 2 Then PopupMenu mnulnternet End If End Sub 1.4. Написание программного кода После разработки формы и установления свойств объектов можно переходить к добавле¬ нию программного кода приложения. Visual Basic — язык программирования, поддерживающий программные конструкции, при¬ сущие большинству других языков программирования.
12 Написание программного кода В этом разделе показано, как создавать процедуры обработки событий и общие процедуры, рассматривается область определения процедур и использование окна Object Browser. Здесь также обсуждаются различные типы данных, доступные в Visual Basic, объявление, область определения и период существования переменных. 1.4.1. Создание процедур В Visual Basic имеется два типа процедур: процедуры обработки событий и общие процедуры. Процедуры обработки событий Visual Basic автоматически вызывает процедуры обработки событий в ответ на действия с клавиатуры, мышью или системные действия. Например, командные кнопки имеют проце¬ дуру обработки события Click (щелчок мыши). Код, который помещается в процедуру обработки события Click, будет выполнен, когда пользователь щелкнет кнопку. Чтобы открыть окно редактирования кода, нужно дважды щелкнуть элемент управления или форму или выбрать команду Code в меню View. Каждый элемент управления имеет фиксированный набор процедур обработки событий (для каждого поддерживаемого объектом события). Эти процедуры для каждого элемента управления перечислены в раскрывающемся списке Procedure в окне кода. Рис. 1.6. Список Procedure для кнопки. Следующий фрагмент кода — процедура обработки события Click для командной кнопки cmdOK: Private Sub cmdOK_Click() MsgBox "Visual Basic" ' Открыть окно сообщения End Sub Общие процедуры Общие процедуры — процедуры Sub или Function, создаваемые для выполнения опреде¬ ленных задач. В отличие от процедур обработки событий, чтобы выполнить общую проце¬ дуру, ее нужно явно вызвать. Чтобы создать общую процедуру, следует открыть окно кода и выбрать Add Procedure в меню Tools. Можно также создать новую процедуру, печатая на пустой строке в окне кода заголовок процедуры Sub, сопровождаемый именем процедуры. Если в нескольких проце¬
Гпава 1. Введение в Visual Basic 13 дурах обработки события имеется дублирование кода, этот код можно поместить в общую процедуру и затем вызывать общую процедуру из процедур обработки событий. Процедуры Sub Процедуры Sub не возвращают значений — они только выполняют некоторую обработку или действие. Вызвать процедуру Sub можно, специфицируя только имя процедуры или используя оператор Call с именем процедуры и параметрами. Например: Call sortList("namel") Если используется оператор Call, список параметров следует заключить в круглые скобки. Если Call опускается, опустить нужно также скобки вокруг списка параметров. Процедуры Function Процедуры Function выполняют действие и возвращают значения. В следующем фрагменте процедура Function получает число и возвращает квадрат этого числа. Function Square(I As Integer) As Integer Square = I * I End Function Если требуется сохранить возвращаемое значение, при вызове функции необходимо ис¬ пользовать круглые скобки, как в следующем операторе: j = Square(5) Если круглые скобки опущены, возвращаемое значение можно игнорировать или не сохра¬ нять его в переменной. Это может быть полезно, если требуется лишь выполнить обработку, связанную с функцией. Например: Square 5 Примечание: Процедуры Sub и Function могут принимать и изменять параметры. Чтобы опреде¬ лить параметры как необязательные, можно использовать ключевое слово Optional. 1.4.2. Область определения программного кода Кроме добавления кода к модулю, ассоциированному с формой, можно также объявлять процедуры в стандартных модулях. Стандартные модули содержат только код Visual Basic; они предназначены для хранения кода, который не привязывается к определенной форме. Процедуры могут быть объявлены как Private или Public. Процедуры Private могут вызывать¬ ся только другими процедурами, размещенными в данной форме, модуле или классе. Процедуры Public в модуле форме становятся методами формы. Такую процедуру можно вызвать отовсюду в приложении, специфицируя имена процедуры и формы. Процедуры Public, описанные в стандартном модуле, доступны излюбого места в приложе¬ нии и могут вызываться специфицированием только имени процедуры. Ниже объявляется процедура Public: Public Sub Procl() End Sub Если эта процедура объявлена в модуле формы, вызывается она следующим образом: Forml.Procl
14 Написание программного кода Если процедура объявлена в стандартном модуле, вызывается она так: Procl Если процедура объявлена под одним именем в двух стандартных модулях, при вызове ее нужно квалифицировать именем модуля, как показано в следующем примере: Modulel.Procl Окно Object Browser После того, как к приложению добавлен некоторый программный код, в окне Object Browser можно увидеть все созданные процедуры, быстро перейти к определенной процедуре или вставить вызов процедуры в текст программы в окне кода. В окне Object Browser показаны классы, доступные из всех объектных библиотек, подклю¬ ченных к проекту. Чтобы вывести на экран Object Browser, нужно нажать <F2>, либо нажать кнопку Object Browser на панели инструментов, либо выбрать команду Object Browser в меню View. На следующей иллюстрации показаны компоненты Object Browser. Рис. 1.7. Окно Object Browser и контекстное меню Object Browser.
Гпава 1. Введение в Visual Basic 15 1.4.3. Переменные, константы и типы данных Объявление переменных Для объявления переменной используется оператор Dim. В следующем операторе объяв¬ ляется переменная iCounter типа lnteger. Dim iCounter As Integer Хотя Visual Basic позволяет использовать необъявленные переменные, текст кода будет проще в отладке и сопровождении, если все переменные объявлять явно. Чтобы не забы¬ вать делать объявления переменных, нужно в раздел General Declarations формы или модуля ввести оператор Option Explicit. После этого при попытке использовать необъявлен¬ ную переменную Visual Basic вернет ошибку компиляции. Чтобы оператор Option Explicit автоматически включался во всех новых проектах: 1. В меню Tools выбрать команду Options. 2. В окне диалога Options открыть вкладку Editor и установить флажок Require Variable Declaration. Нажать ОК. Объявление констант Константы объявляются оператором Const. Значение объявленной константы изменять нельзя. В следующем операторе объявляется константа Pl типа Single: Const PI As Single = 3.14 Visual Basic обеспечивает большой набор встроенных констант, которые можно применять с различными операторами. В следующем фрагменте кода с оператором MsgBox используются стандартные константы vbYesNo и vbYes: iResult = MsgBox ("Продолжить?", vbYesNo) If iResult = vbYes Then ' Некоторое действие End If 1.4.4. Использованиетипов данных Тип данного переменной определяет тип информации, которую может хранить переменная, и интервал возможных значений. Например, если требуется, чтобы переменная действова¬ ла как счетчикдля цикла, ей можно назначить тип данного lnteger. Visual Basic обеспечивает несколько числовых типов данных — lnteger (целое), Long (длинное целое), Single (число с плавающей точкой одинарной точности), Double (число с плавающей точкой двойной точности), Decimal (масштабируемое целое) и Currency (де¬ нежный тип). Использование числового типа данных обычно требует меньшего количества памяти, чем тип Variant. Числовые типы данных приведены в следующей таблице: Тип данных Описание Размер области памяти Currency Используется для денежных или фиксированных расчетов с десятичными дробями, при которых важна точность. Диа¬ пазон значений — от -922,337,203,685,477.5808 до 922,337,203,685,477.5807. 8 байт
16 Написание программного кода Тип данных Описание Размер области памяти Double Число с плавающей точкой двойной точности. Диапазон отрицательных значений — от -1.79769313486232E308 до -4.94065645841247E-324. По¬ ложительные значения варьируют в диапазоне от 4.94065645841247E-324 до 1.79769313486232E308. 8 байт lnteger Малые целые числа. Диапазон от -32,768 до 32,767. 2 байта Long Большие целые числа. Диапазон от -2,147,483,648 до 2,147,483,647. 4 байта Decimal (масштабируемое целое) ± 79 228 162 514 264 337 593 543 950 335 без дробной части; ±7,9228162514264337593543950335 с 28 знаками справа от запятой; минимальное ненулевое значение имеет вид ±0,0000000000000000000000000001. В настоящее время поддерживается использование типа данных Decimal толь¬ ко в пределах типа Variant, то есть описать переменную с типом Decimal невозможно. Пользователь, однако, имеет возможность создать переменную типа Variant с подтипом Decimal с помощью функции CDec. 14 байт Single Число с плавающей точкой одинарной точности. Диапазон отрицательных значений — от -3.402823E38 до -1.401298E-45. Диапазон положительных значений — от 1.401298E-45 до 3.402823E38. 4 байта Если переменная будет содержать двоичные данные, ее нужно объявить как массив типа данных Byte. Использование переменных Byte для хранения двоичных данных позволяет сохранить их во время преобразований формата. Например, когда переменные String преобразуются из формата ANSI в Unicode, любые двоичные данные в переменной разру¬ шаются. Visual Basic может автоматически преобразовывать данные из ANSI в Unicode при: • чтении из файлов; • записи в файлы; • вызовах DLL; • вызовах методов и свойств объектов. Все операции, которые работают с целыми числами, работают также с типом данных Byte, за исключением унарного минуса. Так как Byte — беззнаковый тип данных с интервалом 0 - 255, он не может представлять отрицательное число. Поэтому перед выполнением опера¬ ций с унарным минусом Visual Basic сначала переводит Byte в целое число со знаком. Если переменная всегда будет содержать только строковые данные, ее нужно объявить типа String: Private S As String После этого переменной можно присваивать строковые значения и манипулировать ею, используя строковые функции: S = "Database" S = Left(S, 4) Существует два типа строковых значений:
Гпава 1. Введение в Visual Basic 17 • строки переменной длины, которые могут содержать приблизительно до 2 миллиардов (2 1) символов; 1 fi • строки постоянной длины, которые могут содержать от 1 до приблизительно 64K (2 ) символов. Примечание: Не допускается использование в модулях класса строк постоянной длины, описанных с ключевым словом Public. По умолчанию, строковая переменная или параметр — строка переменной длины; строка увеличивается или сокращается по мере присвоения ей новых данных. Синтаксис объявления строки фиксированной длины следующий: String * размер Например, объявить строку, длина которой всегда будет 50 символов, можно следующим образом: Dim strName As String * 50 Если такой переменной присваивается меньше чем 50 символов, strName до 50 символов дополняется пробелами. Если переменной присваивается слишком длинная строка, Visual Basic просто усекает лишние символы. Так как строки фиксированной длины дополняются замыкающими пробелами, при работе с ними могут быть полезны функции Trim и RTrim, которые удаляют лишние пробелы. Строки фиксированной длины в стандартных модулях могут быть объявлены как Public или Private. В модулях форм, отчетов и классов такие переменные должны объявляться только как Private. Если имеется переменная, которая будет содержать только значения типа Истина/Ложь, Да/Нет или Вкл/Выкл, то для этой переменной можно объявить тип данных Boolean. Значе¬ ние по умолчанию для этого типа — False. В следующем примере переменная blnRunning типа Boolean сохраняет значение Да/Нет: Dim blnRunning As Boolean ' Проверить, проигрывается ли трек If CDPlayer.Direction = 1 Then blnRunning = True End if Значение даты и времени может содержаться как в специальном 8-байтовом типе данных Date, так и в переменных Variant. Приемы работы с датами одинаковы для дат, сохраненных в обоих типах данных. Диапазон представляемых дат — от 1 января 100 г. до 31 декабря 9999 г. При преобразованиях других числовых типов данных в Date значения слева от десятичного знака представляют информацию даты, в то время как значения справа представляют время. Полночь представляет число 0, полдень — 0.5. Отрицательные целые числа пред¬ ставляют даты до 30 декабря 1899 года. Объектные переменные хранятся как 32-разрядные (4-байтовые) адреса, указывающие на объекты внутри приложения или внутри некоторого другого приложения. С переменной, объявленной как Object, впоследствии может быть ассоциирован (с помощью оператора Set) адрес любого существующего объекта, распознаваемого приложением: ' Объявить объектную переменную Dim objDb As Object ' Ассоциировать переменную с объектом - базой данных Set objDb = OpenDatabase("c:\office\sample\dbl.mdb")
18 Написание программного кода При объявлении объектных переменных нужно стараться использовать определенные классы (такие, как TextBox вместо Control или, в предыдущем случае, Database вместо Object) вместо общего типа Object. Visual Basic может разрешать адресацию свойств и методов объектов с определенными типами еще до обращения к ним. Это позволяет приложению в период выполнения работать быстрее. Определенные классы объектов можно увидеть в окне Object Browser. При работе с объектами других приложений вместо использования типов Variant или Object лучше объявлять объекты под таким типом, как они приведены в списке Классы в окне Object Browser. Это гарантирует, что Visual Basic распознает определенный тип объекта, правильно разрешив адресацию в период выполнения. Переменная Variant способна хранить все определенные системой типы данных. Выполнять преобразования между этими типами данных нет необходимости — при взаимных присво¬ ениях переменных Variant Visual Basic автоматически выполняет любое необходимое пре¬ образование. Например: Dim VarVariant ' Variant по умолчанию VarVariant = "2" ' VarVariant содержит "2" (односимвольная строка). VarVariant = VarVariant + 3 ' VarVariant теперь содержит числовое значение 5 VarVariant = "Visual Basic " & VarVariant ' VarVariant теперь содержит ' "Visual Basic 5" (строка) Хотя с переменными Variant можно выполнять операции, не задумываясь о виде данных, который они содержат, с этим типом данных связаны некоторые нюансы, которые следует всегда иметь в виду: • при выполнении с данными Variant арифметических операций или функций переменные Variant должны содержать нечто, что может интерпретироваться как число; • при сцеплении строк нужно использовать операцию & вместо операции +. Если при объявлении переменной ее тип данного не указывается, переменная получает тип Variant. Однако, тип данного Variant требует большего количества памяти, нежели другие типы данных. Если требуется создать компактный и быстрый код, необходимо, где возмож¬ но, использовать явные типы данных. Каждую переменную рекомендуется описывать на отдельной строке, чтобы избежать пута¬ ницы, которая, например, будет иметь место в следующем фрагменте: ' sFname получит тип Variant, a sLname-String: Dim sFname, sLname As String ' Вместо этого лучше сделать так: Dim sFname As String Dim sLname As String Преобразование типов данных В случае необходимости Visual Basic подстраивает типы данных. Например, если строковая переменная используется в арифметическом выражении, Visual Basic, если возможно, преобразует строковую переменную в числовое значение. Если строка представляет числовое значение, ее можно присвоить числовой переменной. Точно также можно присвоить числовое значение строковой переменной. Например, в следу¬ ющей процедуре происходит неоднократное преобразование строки в число и наоборот: Private Sub Commandl Click() Dim intX As Integer Dim strY As String
Гпава 1. Введение в Visual Basic 19 strY = "100.23" intX = strY ' Присвоить строку числовой переменной Textl.Text = intX ' Напечатать значение целой ' переменной в первом поле Text3.Text = Cos(strY) ' Напечатать косинус числа в третьем поле strY = Cos(strY) ' Передать косинус в строковую ' переменную Text2.Text = strY ' Напечатать значение строковой ' переменной во втором поле End Sub Visual Basic автоматически преобразует переменные к соответствующему типу данных. Все же использовать обмен строк и чисел следует с осторожностью: пересылка нечислового строкового значения в числовую переменную обусловит ошибку. В случае присвоения строкового значения числовой переменной строковая переменная или константа в качестве десятичного разделителя должна содержать символ, указанный в настройке Язык и стан¬ дарты Панели управления Windows. Если в настройке указана запятая и вместо запятой ввести точку, последует ошибка периода выполнения (это легко проверить, поэксперимен¬ тировав со значением "100.23"). В следующем фрагменте кода показано, KaKVisual Ваэюдобавляет 1 кзначению в текстовом поле: Dim iNewRate As lnteger txtRate.Text = "5" iNewRate = txtRate.Text + 1 Visual Basic обеспечивает несколько функций, которые можно использовать для явного преобразования значений в определенный тип данного. Например, чтобы преобразовать значение в Currency, можно воспользоваться функцией CCur: Summa = CCur(Kol * Cena) Функция преобразования Преобразует выражение в Cbool Boolean CByte Byte CCur Currency CDate Date CDbl Double Cirrt Integer CLng Long CSng Single CStr String CVar Variant CVErr Error Значения, передаваемые в функцию преобразования, должны быть допустимы для типа данного адресата, иначе происходит ошибка. Например, при попытке преобразовать Long в lnteger значение Long должно быть внутри допустимого интервала для типа данных lnteger.
20 Написание программного кода 1.4.5. Область определения переменных Область определения и видимости переменной определяет, где и когда переменная может быть распознана. Область определения переменной зависит от того, где переменная объ¬ явлена (в процедуре, форме или модуле) и как переменная объявлена (как Public или Private). Переменные уровня процедуры Переменная, объявленная в процедуре, распознается только внутри этой процедуры. В следующем примере переменная описывается внутри процедуры с типом lnteger: Dim iTest As Integer Переменные уровня формы Переменные, объявленные внутри раздела General Declarations формы, могут быть Private или Public. Переменные Private доступны всем процедурам внутри формы, но невидимы для любой процедуры вне формы. Переменные Public доступны всему приложению как свойство формы. При доступе к Public переменной уровня формы вне формы ее необходимо квалифицировать именем формы. Например: Public fTotal As Integer ' Объявление в форме frm.fTotal = 4 ' Использование вне формы Переменные уровня стандартного модуля Переменные, объявленные внутри раздела General Declarations модуля, могут быть Private или Public. Переменные Private доступны только внутри модуля. Переменные Public доступны в любом месте приложения. К Public переменной уровня модуля можно обратиться, специфицируя только имя переменной. Например: ' Объявление переменной в модуле Public giTest As Integer ' Использование переменной вне модуля giTest = 5 ' Одно и то же имя переменной используется в нескольких модулях Modulel.giTest = 5 1.4.6. Период существования переменных Период существования переменной означает, как долго переменная является доступной. Определяется период существования переменной тем, где переменная объявлена (в про¬ цедуре или модуле) и как она объявлена (как Static или не Static). Переменные уровня процедуры Переменная уровня процедуры доступна, пока работает процедура. При повторном вызове процедуры переменная повторно инициализируется.
Гпава 1. Введение в Visual Basic 21 Если требуется, чтобы переменная сохраняла свое значение и повторно не инициализиро¬ валась, ее следует объявлять как Static. Переменные, объявленные как Static, все же доступны только данной процедуре; однако переменные сохраняют свои значения весь период выполнения приложения. В следующем фрагменте переменная iRetryCount сохраняет свое значение при каждом вызове процедуры Proc1. Переменная iValue каждый раз восстанавливается в 0: Sub Procl() Static iRetryCount As Integer Dim iValue As Integer iRetryCount = iRetryCount + 1 End Sub Переменные уровня формы Переменные, объявленные на уровне формы, поддерживаются до тех пор, пока объектная переменная формы не будет установлена в Nothing. Пока этого не произойдет, переменные уровня формы сохраняют свои значения даже при выгрузке формы. При установке переменной формы в Nothing переменные очищаются и выполняется собы¬ тие Terminate формы. В следующем операторе объектная переменная формы Form2 устанавливается в Nothing: Set Form2 = Nothing Переменные уровня стандартного модуля Переменные, объявленные на уровне модуля, доступны в течение всего времени выполне¬ ния приложения. 1.5. Обработка вводимой информации и управление ошибками При разработке приложения Visual Basic важными процедурами являются отладка написанного программного кода и обработка любой ошибки, которая может происходить. Также важно предотвратить как можно больше из этих ошибок, проверяя ввод данных в приложении. В этом разделе рассматривается отладка, предотвращение и перехват ошибок в приложении. 1.5.1. Средства отладки приложения Visual Basic обеспечивает интерактивные инструментальные средства для нахождения ошибок выполнения и ошибок в логике программы. Ко всем средствам отладки можно обратиться, используя меню Debug и View или панель инструментов Debug. Средства отладки Visual Basic включают:
22 Обработка вводимой информации и управление ошибками Рис. 1.8. Средства отладки Visual Basic. Инструмент отладки Назначение Точка останова (Toggle Breakpoint) Установка точки останова. Определяет строку в окне редактора кода, в которой Visual Basic приостанавливает выполнение при¬ ложения. Установить точку останова можно во время разработ¬ ки или в период выполнения, находясь в режиме останова (Break Mode). Шаг с заходом (Step lnto) Выполняет следующую исполняемую строку кода приложения с заходом в процедуры. Шаг с обходом (Step Over) Выполняет следующую исполняемую строку кода приложения без захода в процедуры. Шаг с выходом (Step Out) Выполняет остаток текущей процедуры и останавливает выполнение на следующей строке в вызывающей процедуре. Контрольное значение (Quick Watch) Выводит текущее значение выражения, в то время как приложение находится в режиме останова. Стек вызова (Call Stack) В режиме останова открывает окно диалога Стек вызова (Call Stack), в котором показаны все вызванные, но не завершенные (отложенные)процедуры.
Гпава 1. Введение в Visual Basic 23 Инструмент отладки Назначение Выражения наблюдения Выражения наблюдения (контрольные) используются для конт¬ роля в окне Watches отдельных переменных или выражений. Значение каждого выражения наблюдения в точках останова обновляется. Окно Immediate В режиме останова можно тестировать исполняемый оператор, печатая его непосредственно в окне Immediate. Visual Basic выполняет оператор немедленно. В это же окно направляется вывод оператора Debug.Print. Окно Locals В этом окне автоматически выводятся все объявленные в теку¬ щей процедуре переменные вместе с их значениями. 1.5.2. Обработка данных поля Некоторые ошибки ввода данных можно предотвращать и тем самым улучшать работу приложения, проверяя и подтверждая правильность информации по мере ее ввода в поля и другие элементы управления. Ограничение выборов с помощью элементов управления Один из способов гарантировать допустимый ввод состоит в ограничении количества опций, из которых пользователь может выбирать. Например, чтобы предоставить пользователям возможность выбирать наименования това¬ ров в форме, можно использовать простой список. Так как пользователи должны выбрать из стандартного списка, они не могут вводить недостоверное название. Для небольшого количества взаимноисключающих опций можно использовать переключа¬ тели, а для логических выборов — флажки. Свойство MaxLength Свойство MaxLength определяет максимальную длину строки в текстовом поле. Система подает звуковой сигнал, когда пользователь пробует ввести строку, которая пре¬ вышает максимальную длину. Если требуется вывести на экран сообщение об ошибке, следует обрабатывать нажатие клавиши в событии KeyPress (параметр KeyAscii). Свойства Locked Свойство Locked определяет, может ли пользователь изменять данные в текстовом поле. Если Locked — True, пользователи могут только просматривать и копировать данные поля. Использование события KeyPress для проверки данных Для проверки данных по мере их ввода пользователем можно использовать события KeyPress, KeyDown и KeyUp. В качестве реакции можно запрещать пользователю ввод некоторых символов (например, ограничивать ввод данных исключительно числовыми зна¬ чениями) либо изменять данные непосредственно при вводе (например, преобразовывать все символы в верхний регистр). Событие KeyPress происходит всякий раз, когда пользователь вводит стандартный символ ASCII. Событие не включает большинство специальных символов, таких, как функциональные клавиши, клавиши перемещения курсора или клавиша Delete. Чтобы отвечать на нажатие этих клавиш, нужно использовать события KeyDown и KeyUp.
24 Обработка вводимой информации и управление ошибками В следующем фрагменте вводимые пользователем символы переводятся в верхний регистр: Sub Textl KeyPress(KeyAscii As Integer) KeyAscii = Asc(UCase(Chr(KeyAscii))) End Sub Эта процедура события KeyPress запрещает пользователям вводить в текстовое поле любые символы, кроме числовых значений: Private Sub Textl KeyPress(KeyAscii As Integer) Sub Private Textl KeyPress (KeyAscii Как Integer) If KeyAscii <> 8 Then ' Допускается возврат на один символ ' либо ввод только цифр If Chr(KeyAscii) < "0" Or Chr(KeyAscii) > "9" Then KeyAscii = 0 ' Установить символ к пустому значению Beep End If End If End Sub 1.5.3. Управление интерфейсом и информацией формы В дополнение к использованию методов уровня поля для проверки данных непосредствен¬ но при вводе можно написать процедуры, которые будут проверять данные одновременно во всех полях формы. Ниже описываются поддерживаемые Visual Basic методы проверки правильности ввода уровня формы. Деактивация кнопки OK Один из подходов к обеспечению достоверности информации формы — гарантировать, что пользователь ввел данные во всех полях формы прежде, чем ему будет позволено дейст¬ вовать дальше. Это можно реализовать, деактивируя кнопку OK в форме, пока пользова¬ тель не заполнил все поля, как показано на следующей иллюстрации: Рис. 1.9. Отключение кнопки в форме. Чтобы тестировать каждое нажатие клавиши при вводе данных в форму, следует устано¬ вить в True свойство KeyPreview формы. После этого событие клавиатуры сначала будет получать форма, а затем уже элемент управления. В следующем фрагменте кода кнопка OK активируется, только если все текстовые поля имеют вхождения: Private Sub Form Load() Me.KeyPreview = True cmdOK.Enabled = False End Sub Private Sub Form KeyUp(KeyCode As Integer, Shift As Integer) ' Активирует кнопку OK, только если все поля имеют вхождения
Гпава 1. Введение в Visual Basic 25 Dim curControl As Control For Each curControl In Controls If TypeOf curControl Is TextBox Then If curControl.Text = "" Then ' Поле не заполнено cmdOK.Enabled = False ' Деактивировать кнопку 0K Exit Sub End If ' Если нужно, таким образом можно проконтролировать и другие типы ' элементов управления End If Next ' Во всех полях имеется информация cmdOK.Enabled = True End Sub Проверка всех полей в форме Простой способ проверить одновременно все поля в форме — поместить код проверки правильности ввода в событие Click кнопки ОК. В этом сценарии приложение позволяет пользователю закончить заполнение формы и затем проверяет все поля. Приложение устанавливает фокус на первое поле, которое содержит недостоверные данные. Например, в следующем фрагменте на наличие числового значения проверяются числовые поля в форме, содержащей номер отдела и номер сектора служащего: Private Sub cmdOK_Click() If Not (IsNumeric(txtOtdelNo.Text)) Then MsgBox "Неверный номер отдела" txtOtdelNo.SetFocus ElseIf Not (IsNumeric(txtSectorNo.Text)) Then MsgBox "Неверный номер сектора" txtSectorNo.SetFocus Else MsgBox "Данные верны" Unload Me End If End Sub Использование События QueryUnload Событие QueryUnload происходит непосредственно перед событием Unload, когда форма выгружается. Событие QueryUnload позволяет определить, как было инициировано событие Unload, и в случае необходимости отменять событие Unload. Это полезно, когда пользователь не завершил ввод данных на форме или когда требуется запросить пользователя сохранить изменения перед закрытием формы. Событие QueryUnload имеет следующие два параметра: • параметр UnloadMode указывает, как было инициировано событие Unload; • параметр Cancel отменяет событие Unload. Если Cancel установлено в True, приложение остается в состоянии, какое было перед инициированием выгрузки формы. В следующем фрагменте событие Unload отменяется, а пользователю перед закрытием формы выводится дополнительный запрос:
26 Обработка вводимой информации и управление ошибками Private Sub Form QueryUnload(Cancel As lnteger, UnloadMode As lnteger) Dim iResult As lnteger iResult = MsgBox("Bbi уверены, что хотите выйти?", vbYesNo) If iResult = vbNo Then Cancel = True End If End Sub Обработка ошибок выполнения Независимо от того, как хорошо спроектировано приложение, оно лишь теоретически может работать без ошибок. Пользователи забывают помещать диски в дисководы, системе может не хватать памяти, файлы случайно удаляются и не могут быть найдены. Добавляя в приложение эффективный код обработки ошибок, можно повысить устойчивость его работы. Понятие процесса управления ошибками Процесс обработки ошибок включает следующие три шага: 1. Установить код перехвата ошибки, который определит, куда поток обработки выполнит переход, когда будет возвращена ошибка. 2. Написать код обработки ошибок. 3. Выйти из процедуры обработки ошибок. Оператор On Error GoTo позволяет перехватить ошибку и определяет, где продолжить выполнение, когда возвращается ошибка. Если возвращается ошибка периода выполнения, поток обработки переходит к метке, обозначенной в операторе On Error GoTo. Процедура обработки ошибок выполняет код, содержащий оператор Resume, который указывает, где продолжить обработку. В следующем фрагменте показано, как использовать операторы On Error GoTo и Resume. Private Sub Commandl Click() Dim AppName As String On Error GoTo CheckError AppName = InputBox("BBeflHTe имя приложения") Shell AppName Exit Sub CheckError: I f Err.Number = 53 Then ' Файл не найден sgBox "Приложение не найдено" If МэдВохСПопытаться еще раз?", vbYesNo) = vbYes Then AppName = InputBox("BBeflHTe имя приложения") Resume ' Новая попытка Else Resume Next ' Выполнить следующий оператор End If Else MsgBox " Неизвестная ошибка " End If End Sub В коде обработки ошибок для контроля номера произошедшей ошибки, очистки значения ошибки или инициирования ошибки используются свойства и методы объекта Err.
Гпава 1. Введение в Visual Basic 27 Свойства объекта Err Свойство Number — целое число, которое указывает последнюю произошедшую ошибку. Для определения возвращаемых ошибок следует контролировать значение Err.Number. В некоторых случаях можно исправить ошибку и позволить пользователю продолжить работу, не прерывая обработку. В других случаях придется сообщить пользователю об ошибке и, основываясь на ответе пользователя, выполнить некоторое действие. Свойство Description — строка, которая содержит описание ошибки. Свойство Source содержит имя приложения, которое сгенерировало ошибку. Это полезно при использовании Автоматики. Например, если пользователь вызывает Microsoft Excel и он генерирует ошибку, Err.Number будет содержать правильный код ошибки, a Err.Source устанавливается равным Excel.Application. Методы объекта Err Метод Clear сбрасывает значение Err.Number в ноль. Метод Raise устанавливает ошибку. Этот метод используется для передачи ошибки обрат¬ но в вызывающую процедуру или тестирования кода обработки ошибок. Например: Err.Raise 53 ' Установить ошибку "Файл не найден" Опции Resume С помощью оператора Resume можно специфицировать, откуда приложение продолжит работу после обработки ошибки. В следующей таблице перечислены три типа операторов Resume, доступные в Visual Basic: Оператор Описание Resume Возврат коператору, который обусловил ошибку. Resume использует¬ ся для повторения операции после исправления ошибки. Resume Next Возврат к оператору, следующему непосредственно за оператором, который обусловил ошибку. Resume строка или метка Если не имеется никакого оператора Resume, процедура обработки ошибок завершается. При этом, если ошибка возникла в процедуре, содержащей подпрограмму обработки ошибок, выполнение продол¬ жается с оператора, вызвавшего ошибку. Если же ошибка возникла в вызывающей процедуре, выполнение продолжается с оператора, вы¬ звавшего процедуру, содержащую подпрограмму обработки ошибок. Примечание: Если оператор Resume используется где-либо кроме подпрограммы обработки оши¬ бок, возвращается ошибка компиляции. 1.5.4. Отключение обработки ошибок Активированные процедуры обработки ошибок могут мешать при отладке кода программ. Visual Basic позволяет отключать код обработки ошибок, обеспечивая при этом другие опции отладки приложения. Для изменения режима обработки ошибок: 1. В меню Tools выбрать команду Options. 2. Открыть вкладку General окна диалога Options, в разделе Error Trapping установить требуемую опцию и нажать ОК.
28 Компиляция приложения и построение ЕХЕ-файла В разделе ErrorTrapping вкладки General доступны следующие опции: Опция Описание Break on All Errors Если включить этот переключатель, то при возникновении любой ошибки выполнения Visual Basic игнорирует любые операторы On Error и вводит режим останова (Break). Break in Class Module Эту опцию следует устанавливать при отладке компонента ActiveX. При этом компонент ActiveX инициирует ввод режима останова вме¬ сто передачи ошибки обратно приложению-клиенту. Примечание: КомпонентАсйуеХ—физическийфайл(например, .exe, .dll, .ocx) Break on Unhandled Errors Visual Basic вводит режим останова при возникновении любой ошиб¬ ки, для которой не обеспечен определенный код обработки ошибок. 1.6. Компиляция приложения и построение ЕХЕ-файла После того как закончено построение интерфейса и написание и отладка программного кода приложения, можно создавать для пользователей исполняемый файл приложения. Создание исполняемого файла в Visual Basic — простой процесс. Для этого: 1. В меню File выбрать команду Make Имя проекта.ехе. 2. Ввести имя для исполняемого файла. 3. Чтобы добавить информацию по версии программы: в окне диалога Make EXE File нажать кнопку Options. Откроется окно диалога Project Properties. На вкладке Make ввести номе¬ ра версии и текст информация версии; щелкнуть ОК. На следующей иллюстрации показаны опции Version Number вкладки Make: Рис. 1.10. Вкладка Make окна диалога Project Properties. Примечание: Состав вкладок окна диалога Project Properties для компиляции отличается от окна, открываемого по команде меню Project \ Project Properties (см. рис. 1.11).
Гпава 1. Введение в Visual Basic 29 Создание исполняемого файла Visual Basic можно запускать также с подсказки MS-DOS. Это инструктирует генераторы кода создавать .exe файлы без вмешательства пользователя и позволяет разработчикам запускать большие задания компиляции программным способом. Следующий синтаксис иллюстрирует, как компилировать приложение из командной строки: vb32 /make имя_проекта имя_исполняемого_файла В дополнение к исполняемому файлу при тиражировании приложения необходимо обеспе¬ чить различные DLL и другие файлы. Следует также создать программу Setup, которая установит приложение на компьютер пользователя. Мастер Setup Wizard Visual Basic облегчает создание для приложения дистрибутивных дисков или дистрибутивной папки сервера. После этого для установки и регистрации требу¬ емых файлов приложения можно запустить результирующую программу Setup. Информацию относительно создания программы Setup см. в главе 12"Создание программы Setup и оптимизация приложения". 1.6.1. Компиляция во внутренний код Редакции Visual Basic Professional и Enterprise позволяют компилировать программный код либо в формат стандартного псевдокода Visual Basic (р-код), либо в формат внутреннего кода. При компиляции во внутренний код обеспечивается несколько опций для оптимизации и отладки, которые недоступны для р-кода. Р-код — промежуточный шаг между инструкциями высокого уровня приложения Visual Basic и внутренним кодом низкого уровня, которые выполняет процессор компьютера. В период выполнения Visual Basic транслирует каждый оператор р-кода во внутренний код. При компиляции программы непосредственно в формат внутреннего кода промежуточный шаг р-кода устраняется. Для компиляции проекта во внутренний код: 1. В окне Open Project или в окне Project Explorer выбрать проект, который требуется скомпилировать. 2. В меню Project выбрать команду Project Properties. 3. В окне диалога Project Properties открыть вкладку Compile. 4. Выбрать требуемые опции компиляции и нажать ОК. Чтобы получить дополнительные опции внутреннего кода, можно нажать кнопку Advanced Optimizations. На рис. 1.11 показаны опции внутреннего кода. Описание доступных опций компиляции во внутренний код приведено в таблице: Опция Описание Optimize For Fast Code Максимизирует быстродействие скомпилированных исполняемых файлов, "ин¬ структируя" компилятор, что скорость важнее размера. Когда компилятор транс¬ лирует операторы Visual Basic в машинный код, часто имеется выбор среди многих различных последовательностей машинного кода, которые могут пра¬ вильно представить данный оператор или конструкцию. Иногда эти различия позволяют достичь определенных целей компиляции. Выбор данной опции гарантирует, что, когда компилятор распознает такие варианты, он всегда будет генерировать самую быструю возможную последовательность кодов, даже ког¬ да это может увеличивать размер компилированной программы.
30 Компиляция приложения и построение ЕХЕ-файла Рис. 1.11. Опции компиляции во внутренний код. Опция Описание Optimize For Small Code Минимизирует размер скомпилированных исполняемых файлов, инструктируя компилятор, что размер важнее быстродействия. Выбор этой опции гарантиру¬ ет, что, когда компилятор распознает варианты последовательностей кодов, он всегда будет генерировать наименьшую возможную последовательность, даже когда это может снизить быстродействие выполнения компилированной про¬ граммы. N0 Optimizations Отключает всякие оптимизации. Если выбрана эта опция, компилятор генери¬ рует код, который будет значительно медленнее и больше по размеру, чем при выборе любого типа оптимизации. Favor Pentium Pro Оптимизирует генерацию объектного кода с учетом особенностей архитектуры процессора Pentium Pro (P6). Код, сгенерированный с этой опцией, будет рабо¬ тать также на более ранних процессорах, но менее эффективно. Некоторые стратегии генерации объектного кода, применимыедля Pentium Pro, не поддер¬ живаются на компьютерах с процессорами 80386, 80486 и Pentium. Следова¬ тельно, использовать эту опцию можно, только если на всех или большинстве машин, выполняющих программу, используется Pentium Pro. Create Symbolic Debug Info Генерирует в компилированном исполняемом файле символическую информа¬ цию отладки. Программы, компилированные во внутренний код с использова¬ нием этой опции, могут быть отлажены в Visual C++ 5.0 или другим совместимым отладчиком. Установка этой опции будет генерировать файл .pdb с требуемой информацией отладки. Asume N0 Aliasing Сообщает компилятору, что программа не использует совмещение имен (псев¬ донимы). Псевдоним — имя, которое относится к разделу памяти, уже адресу¬ емому другим именем. Псевдонимы используются при передаче параметров ByRef, которые ссылаются на одну переменную. Использование этой опции позволяет компилятору реализовать оптимизации, которые иначе выполнить невозможно, например хранение переменных в регистрах и оптимизации цик¬ лов. Однако это может обусловливать неправильное выполнение программы, поэтому, если параметры передаются по ссылке, использовать эту опцию сле¬ дует осторожно.
Гпава 1. Введение в Visual Basic 31 Опция Описание Remove Array Bounds Checks Выключает контроль ошибок допустимых индексов массива и количества раз¬ мерностей массива. По умолчанию, Visual Basic проводит контроль при каждом обращении к массиву, определяя, находится ли индекс внутри интервала мас¬ сива. Если индекс вне пределов массива, возвращается ошибка. Выбор этой опции отключает контроль этой ошибки, что может значительно ускорять мани¬ пулирование массивами. Однако, если программа обращается к массиву по индексу, который не попадает в пределы размерности, без предупреждений может осуществляться доступ к недостоверным разделам памяти. Это будет обусловливать непредвиденное поведение или сбои программы. Remove lnteger- Overvlow Checks Отключает вывод ошибок в случаях, когда числовые значения, присваиваемые целым переменным, располагаются вне правильного интервала для типа дан¬ ных. По умолчанию, Visual Basic выполняет проверку при каждом вычислении с переменной целочисленного типа данных (Byte, Integer, Long и Currency), чтобы гарантировать, что результирующее значение находится внутри требуемого интервала. Если значение имеет неправильную величину, выдается ошибка. Выбор данной опции отключает контроль этой ошибки, что может ускорять целочисленные вычисления. Однако в случае переполнения емкости типа дан¬ ного ошибка не будет возвращена, и могут иметь место неправильные резуль¬ таты. Remove Floating-Point Error Checks Отключает контроль ошибок, гарантирующий, что числовые значения, присва¬ иваемые переменным с плавающей запятой, находятся в правильном интерва¬ ле для типов данных и что не будет происходить деление на ноль или другие недопустимые операции. По умолчанию, Visual Basic выполняет проверку при каждом вычислении с переменной типа данных с плавающей запятой (Single и Double), чтобы гарантировать, что результирующее значение находится внутри требуемого интервала. Если значение имеет неправильную величину, выдает¬ ся ошибка. Выполняется также контроль на недопустимые операции. Выбор данной опции выключает этот контроль, что может ускорять вычисления с плавающей запятой. Однако в этом случае могут иметь место неправильные результаты без индикации ошибок. Remove Safe Pentium FDIV Checks Выключает генерацию специального кода, повышающего безопасность деле¬ ния с плавающей запятой (FDIV — floating-point division) на процессорах Pentium, имеющих ошибку по этой операции. Компилятор внутреннего кода автоматически добавляет дополнительный код для выполнения операции де¬ ления с плавающей запятой на процессорах Pentium, которые имеют ошибку FDIV. Выбор этой опции позволяет уменьшить и ускорить код, но в редких случаях может создавать на таких процессорах небольшие погрешности. Allow Unrounded Floating-Point Operations Позволяет компилятору сравнивать результаты выражений с плавающей запя¬ той без предварительного округления этих результатов к правильной точности. При вычислениях с плавающей запятой перед выполнением сравнения значе¬ ния обычно округляются к соответствующей степени точности (Single или Double). Выбор этой опции позволяет компилятору, когда это позволяет выпол¬ нить операцию более эффективно, производить сравнения с плавающей запя¬ той до округления. Это повышает быстродействие некоторых операций с плавающей запятой. Однако это может привести к тому, что вычисления будут производиться с более высокой точностью, чем ожидается, и два значения с плавающей запятой, которые могли бы считаться равными, не будут таковыми.
32 Способы доступа к данным в Visual Basic Глава 2. Работа с данными через элемент управления Data Элемент управления Data можно использовать для создания приложений, работающих с данными ряда форматов баз данных. Элемент управления Data взаимодействует с процессором базы данных Microsoft Jet и позволяет создавать в приложении механизмы доступа кданным с минимальным объемом программирования. В этой главе рассматривается использование элемента управления Data и нескольких специальных элементов управления для просмотра, редактирования и модификации ин¬ формации в базе данных. 2.1. Способы доступа кданным в Visual Basic Приступая к использованию функциональных возможностей Visual Basic по работе с базами данных, полезно рассмотреть различные механизмы доступа кданным, а также терминоло¬ гию баз данных. 2.1.1. Использование ядра базы данных Microsoft Jet Объекты Доступа к данным (DAO) и элемент управления Data для обращения к базам данных используют процессор базы данных Microsoft Jet. Процессор Jet позволяет обра¬ щаться к следующим трем типам баз данных: • базы данных формата Jet. Эти базы данных создаются и управляются непосредствен¬ но ядром Jet. Microsoft Access и Visual Basic используют один и тот же процессор базы данных Jet; • базы данных индексно-последовательного метода доступа (ISAM). Форматы этих базданных включают Btrieve, dBASE, MicrosoftVisual FoxPro, Paradox, а также текстовые файлы и HTML; • ODBC-совместимые базы данных. Эти базы данных включают базы данных кли¬ ент/сервер, которые соответствуют стандарту ODBC, такие, как Microsoft SQL Server. С помощью Visual Basic может быть доступно большинство баз данных, которые поддержи¬ вают ODBC. 2.1.2. Другие методы доступа кданным Другие методы доступа кданным, поддерживаемые Visual Basic, включают: • элемент управления Remote Data Source. Это — элемент управления, используемый для получения доступа к базам данных ODBC. Remote Data Source доступен только в редакции Enterprise; • библиотеки ODBC. Эти библиотеки позволяют вызывать непосредственно интерфейс программирования приложений (API) ODBC; они доступны как отдельный программный продукт; • библиотеки Visual Basic SQL (VBSQL). Эти библиотеки обеспечивают прямую связь с Microsoft SQL Server; они доступны как отдельный программный продукт.
Гпава 2. Работа с данными через элемент управления Data 33 2.2. Основы организации данных В большинстве систем баз данных используется реляционная модель организации базы данных. Реляционная модель базы данных представляет данные как семейство таблиц. Таблица — логическая группа связанной информации. Например, база данных может содержать табли¬ цу, в которой хранятся данные служащих, и другую таблицу, в которой хранятся заказы. На следующей иллюстрации показана структура примерной базы данных Nwind.mdb, по¬ ставляемой с Visual Basic (структура получена в окне Relationships (Схема данных) в Microsoft Access): Рис. 2.1. Реляционная структура базы данных. 2.2.1. Элементы таблицы База данных Nwind содержит ряд таблиц, группирующих информацию. Это, например, таблицы Orders (заказы), Customers (клиенты) и Employees (служащие). В базе данных Jet строки таблицы называются записями, а столбцы — полями. На рис. 2.2 приводится иллюстрация структуры таблицы Employees. Первичный ключ Каждая таблица включает первичный ключ, который является полем (или комбинация полей), уникальным для каждой строки в таблице. Например, для таблицы Employees первичный ключ — поле EmployeelD. Таблица может также содержать внешние ключи — поля, которые ссылаются на строку в другой таблице. Например, в базе данных Nwind таблица Orders содержит поле CustomerlD. Это поле — внешний ключ, так как оно ссылается на "внешнюю" таблицу Customer, а не на таблицу Orders. Вместо того чтобы дублировать всю информацию по заказчику для каждого заказа, для каждого заказа имеется только один заказчик, но, в то же время, один заказчик может иметь много заказов. В терминологии базданных отношение между информацией заказчика и таблицей Orders — отношение один-к-многим.
34 Работа с элементом управления Data Рис. 2.2. Структура таблицы (используется окно Table Structure надстройки Visual Data Manager). Записи Запись содержит информацию единственного вхождения в таблице. Обычно нежелательно иметь в таблице две записи, содержащие те же самые данные. Например, каждая запись в таблице Employees содержит информацию относительно одного служащего. Поля Каждое поле в таблице содержит отдельную порцию информации. Например, таблица Employees включает поля для номера служащего, фамилии, имени и такдалее. Индексы Индексы таблиц баз данных — сортированные списки, поиск информации в которых осуще¬ ствляется значительно быстрее, чем непосредственно в таблицах. С целью обеспечения более быстрого доступа к базе данных в большинстве баз данных используется один или больше индексов. Например, в таблице Employees может быть построен индекс для столбца EmployeelD. 2.3. Работа с элементом управления Data Элемент управления Data в Visual Basic обеспечивает возможность формировать мощные и разнообразные приложения базы данных с очень небольшим объемом программирования. В этом разделе описывается, как формировать приложение базы данных, используя эле¬ мент управления Data и ассоциированный объект Recordset. Также показано, какспомощью
Гпава 2. Работа с данными через элемент управления Data 35 мастера Data Form Wizard можно строить приложения базы данных, которые включают элемент управления Data. 2.3.1. Доступ кданным с помощью элемента управления Data Элемент управления Data реализует доступ к данным с использованием процессора базы данных MicrosoftJet. Эта технология обеспечиваетдоступ кбазамданных многихформатов. Процесс создания приложения базы данных с применением элемента управления Data включает следующие два шага: 1. Добавить элемент управления Data к форме и установить свойства, специфицирующие базу данных и таблицу, из которой будут отбираться данные. 2. Добавить к форме связанные элементы управления и установить их свойства, чтобы связать их с элементом управления Data; после этого в них могут отображаться данные. Использование связанных элементов управления После размещения связанного элемента управления в форме и установки его свойств в этом элементе управления автоматически отображаются данные из базы данных. Если пользователь изменяет данные в связанном элементе управления, эти изменения автома¬ тически фиксируются в базе данных, когда пользователь перемещается на другую запись. С данными может быть связан ряд встроенных элементов управления Visual Basic, включая флажок (CheckBox), образ (lmage), надпись (Label), изображение (PictureBox), тексто¬ вое поле (TextBox), простой список (ListBox), поле со списком (ComboBox) и OLE-кон- тейнер. На следующей иллюстрации показана примерная форма, которая содержит элемент управ¬ ления Data и два связанных элемента управления: Свойства попя: - DataSource = Data1 - DataField = Last Name Свойства элемента управления Data: - DatabaseName = NWIND.MDB - RecordSource = Employees Рис. 2.3. Форма с элементом управления Data и связанными элементами управления. Чтобы увидеть демонстрацию использования элемента управления Data, нужно, в соответствии с иллюстрацией, разместить на форме элементы управления, установить их свойства и запу¬ стить проект. С помощью такого простого приложения можно просматривать и редактировать информацию из базы данных Nwind (или какой-либо другой). Эти шаги описаны ниже. Установка свойств элемента управления Data Чтобы соединить элемент управления Data с базой данных: 1. Специфицировать базу данных, к которой требуется получить доступ, внеся имя базы данных в свойство DatabaseName. 2. Специфицировать записи, которые требуется отбирать, внеся в свойство RecordSource имя таблицы базы данных или строку SQL.
36 Работа с элементом управления Data Примечание: Чтобы соединиться с базой данных dBase, Paradox или Btrieve, нужно указать в свойстве DatabaseName папку, которая содержит файлы базы данных, и установить в свойстве Connect соответствующий тип базы данных. Связывание элементов управления После того как установлены свойства для элемента управления Data, нужно связать отдель¬ ные элементы управления с элементом управления Data и затем специфицировать, какое поле таблицы будет отображать каждый элемент управления. Чтобы связать элемент управления с элементом управления Data: 1. Во время разработки внести в свойство DataSource элемента управления имя элемента управления Data (в форме может быть несколько элементов управления Data). 2. Во время разработки или в период выполнения специфицировать поле, которое требует¬ ся связать с элементом управления, установив его свойство DataField. 2.3.2. Некоторые свойства и методы элемента управления Data Свойство Connect Свойство Connect определяет тип базы данных, которую требуется открыть. Это свойство может включать такие параметры домена защиты, как идентификатор пользователя и пароль. Свойство Exclusive Свойство Exclusive определяет, получит ли пользователь исключительное право доступа к базе данных. Если свойство Exclusive установлено в True и затем пользователь успешно открывает базу данных, никакое другое приложение не сможет открыть базу данных, пока она не будет закрыта данным пользователем. Свойство ReadOnly Свойство ReadOnly определяет, может ли пользователь модифицировать базу данных. Если модифицировать базу данных не планируется, более эффективно будет установить свойство ReadOnly в True. Свойство Recordset Свойство Recordset — объект, который содержит набор записей, возвращенных элементом управления Data. С этим свойством связаны свойства и методы, которые можно использо¬ вать при работе с возвращенными записями. Свойства BOFAction и EOFAction Эти свойства определяют, какое действие должен выполнить элемент управления Data, когда свойства BOF или EOF набора записей принимают значение True. Например, если свойство EOFAction элемента управления Data установлено в vbAc- tionAddNew и элемент управления Data используется для перемещения ниже последней записи набора записей, будет автоматически выполнен метод AddNew, позволяющий вводить новую запись. Метод Refresh Метод Refresh регенерирует объект Recordset. Если в период выполнения изменяется свойство RecordSource, необходимо вызвать метод Refresh, чтобы обновить набор записей. В следующем фрагменте показано, как использовать метод Refresh:
Гпава 2. Работа с данными через элемент управления Data 37 Datal.RecordSource = "SELECT * FROM Employees " & "WHERE [Employee ID] = " & txtEmpID.text Datal.Refresh 2.3.3. Объект Recordset В приложении базы данных пользователи перемещаются по записям базы данных, исполь¬ зуя кнопки элемента управления Data. Ниже показано, что "скрывается" за элементам управления Data и его кнопками. Что такое Recordset? Объект Recordset — весь набор записей, к которым обращается элемент управления Data. Набор записей хранится в памяти, в случае необходимости выгружаясь на диск. Для манипулирования набором записей используется свойство Recordset элемента управ¬ ления Data. Одна запись набора Recordset является текущей. Информация из текущей записи отображается в связанных элементах управления. Позицию текущей записи можно изменить, щелкнув кнопку элемента управления Data или программно в коде с помощью методов объекта Recordset. Определение границ набора записей Если для изменения позиции текущей записи используется программный код, необходимо определить начало и конец набора записей, контролируя свойства EOF и BOF объекта Recordset. При перемещении к записи EOF или BOF выполняется действие, установленное значением свойства BOFAction или EOFAction. Например, можно установить EOFAction таким образом, чтобы автоматически добавлялась новая запись. Если свойство EOFAction установлено к EOF, то при перемещении к записи EOF никакого действия выполняться не будет. В случае же перемещения на одну запись до BOF или после EOF возвращается ошибка выполнения. На следующей иллюстрации показано, как свойства BOF и EOF определяют границы объекта Recordset (набора записей). Использовать объект Recordset определенного элемента управления Data в программном коде можно через свойство Recordset3neMeHTa управления Data, как показано в следующем фрагменте: Datal.Recordset.MoveNext ' Перемещение на следующую запись набора If Datal.Recordset.EOF Then Datal.Recordset.MoveLast
38 Работа с элементом управления Data 2.3.4. Свойства и методы объекта Recordset Для отбора информации из набора записей используются свойства и методы объекта Recordset. Они позволяют перемещаться по записям, добавлять, модифицировать или удалять записи. Свойства BOF и EOF Свойства BOF и EOF объекта RecordsetyKa3biBaiOT, установленали позиция текущей записи в наборе перед первой записью или после последней записи. Если в наборе записей не имеется никаких записей, то и свойство BOF, и свойство EOF — True. Метод AddNew Добавить новую запись к набору записей можно методом AddNew. При выполнении метода AddNew Visual Basic очищает связанные элементы управления и устанавливает для свой¬ ства EditMode элемента управления Data значение dbEditAdd. Новая запись не будет добавлена к базе данных, пока не будет явно выполнен метод UpdateRecord или Update или пока пользователь не переместится на другую запись. В следующем фрагменте показано, как добавить новую запись к набору: Sub cmdAdd_Click () Datal.Recordset.AddNew Метод UpdateRecord элемента управления Data Для сохранения текущей записи в базе данных используется метод UpdateRecord. В следу¬ ющем фрагменте база данных модифицируется сохранением значений текущей записи: Sub cmdUpdate_Click () Datal.UpdateRecord Метод CancelUpdate элемента управления Data Чтобы отменить метод AddNew или Edit и обновить связанные элементы управления данными из текущего набора записей, можно использовать метод CancelUpdate. Например, если пользователь изменил поля на форме, но еще не модифицировал их и решил отменить изменения, метод CancelUpdate отменит операцию, обновит поля ориги¬ нальными данными из набора записей и выведет на экран текущую запись. Ниже показано, как отменить добавление или редактирование записи: Sub cmdCancel Click () Datal.CancelUpdate Метод Delete Для удаления записи из базы данных используется метод Delete. Удаленная запись остает¬ ся текущей, пока пользователь не перемещается на другую запись, как показано в следую¬ щем коде. Sub cmdDelete Click () Datal.Recordset.Delete Datal.Recordset.MoveNext If Datal.Recordset.EOF Then Datal.Recordset.MoveLast End If End Sub
Гпава 2. Работа с данными через элемент управления Data 39 Примечание: В базе данныхмогут быть установлены определенные правила ссылочной целостно¬ сти. Например, в базе данных Nwind установлены правила, запрещающие удаление служащих, с которыми связаны заказы. Информацию относительно управления нарушениями ссылочной цело¬ стности см. в разделе "Ссылочная целостность”главы 4 "Расширенные возможности программи¬ рования доступа к данным". 2.3.5. Мастер Data Form Wizard Data Form Wizard — служебная программа Visual Basic, которая генерирует простые формы для работы с базой данных с использованием элемента управления Data. Мастер Data Form Wizard можно использовать для быстрого формирования исходных (а возможно и оконча¬ тельных) вариантов форм в начале разработки приложения базы данных. Чтобы загрузить мастер Data Form Wizard, нужно выбрать команду Add-In Manager в меню Add-Ins и в окне Add-In Manager установить соответствующий флажок; нажать ОК. После этого элемент Data Form Wizard появляется в меню Add-Ins, откуда его можно запустить. Рис. 2.5. Окно Add-In Manager. 2.3.6. Пример использования мастера Data Form Wizard В следующем примере мастер Data Form Wizard используется для создания формы ввода данных для таблиц Orders (заказы) and Order Details (позиции заказа) базы данных Nwind.mdb. В форме отображается отношение "один-к-многим" между этими двумя табли¬ цами (см. рис. 2.1). 1. Создать новый проект Standard EXE. 2. Используя Add-In Manager, загрузить Data Form Wizard. 3. В меню Add-Ins выбрать Data Form Wizard. 4. Выбрать опции Data Form Wizard, как показано в следующей таблице: Опция Значение Database Format (Формат базы данных) Access Database Name (Имя базы данных) <Папка> \Nwind.mdb
40 Работа с элементом управления Data Опция Значение Form Layout (Компоновка формы) Master/Detail Master Record Source (Источник записей стороны "один") Таблица Orders Master Fields (Поля стороны стороны "один") OrderlD, CustomerlD, EmployeelD, OrderDate, ShipName Detail Record Source (Источникзаписей стороны "многие") Таблица Order Details Detail Fields (Поля стороны "многие") Все поля таблицы Order Details Record Source Relation (Поля для связывания таблиц) OrderlD Available Controls (Доступные элементы управления) Select All Form Name (Имя формы) frmOrders 5. В окне диалога Project Properties установить frmOrders для Startup Object. 6. Запустить приложение. Форма будет выглядеть примерно так (заголовки созданных мастером элементов управле¬ ния изменены): Рис. 2.6. Форма для работы сданными отношения "один-к-многим". Созданную таким образом форму в дальнейшем можно модернизировать и расширять, формируя на основе нее приложение базы данных. Полезно исследовать форму, созданную Data Form Wizard. Для этого нужно выйти из приложения и просмотреть следующие свойства и события формы: а) Свойства DatabaseName и RecordSource элемента управления Data. б) Процедуры обработки событий элемента управления Data, в особенности событие Reposition, которое гарантирует, что записи отношения "один-к-многим" будут синхро¬ низированы. в) Свойства DataSource и DataField каждого из текстовых полей.
Гпава 2. Работа с данными через элемент управления Data 41 г) Процедуру обработки события Click для каждой из командных кнопок. д) Свойство DataSource элемента управления DBGrid. 2.4. События элемента управления Data Элемент управления Data поддерживает три события, которые можно использовать для расширения приложения базы данных: Validate, Reposition и Error. Эти события позволяют переопределять некоторые моменты умолчательного поведения элемента управления Data. 2.4.1. Событие Validate Чтобы проверить данные до того, как запись будет сохранена в базе данных, можно использовать событие Validate. Это событие происходит непосредственно перед тем, как Visual Basic переносит изменения из связанных элементов управления в базу данных и перемещает указатель текущей записи на другую запись базы данных. Событие Validate можно использовать для вывода пользователям запроса на подтвержде¬ ние изменений. Объявление процедуры события Validate имеет следующий синтаксис: Private Sub Data1_Validate (ActionAs Integer, Save As lnteger) Параметр Action Параметр Action указывает операцию, которая обусловила событие Validate. Событие Validate может произойти в результате одной из следующих операций: • метод MoveFirst, MovePrevious, MoveNext, MoveLast; • MeTOflAddNew; • метод Update; • метод Delete; • метод Find; • установка свойства Bookmark; • закрытие базы данных; • вызгрузка формы. Чтобы отменить эти действия, нужно установить для параметра Action значение vbDataActionCancel. Параметр Save Параметр Save указывает, изменены ли связанные данные. Если Save — True, связанные данные были изменены. Чтобы отменить сохранение, можно установить Save в False. В следующем фрагменте кода у пользователя запрашивается подтверждение изменений в базе данных. Если пользователь отвечает Нет, изменения отменяются. Private Sub Datal Validate (Action As Integer, Save As Integer) Dim iResponse As Integer If Save = True Then iResponse = MsgBox ("Сохранить изменения?", vbYesNo) If iResponse = vbNo Then Save = False Datal.UpdateControls ' Восстановить значения полей End If End If End Sub
42 События элемента управления Data 2.4.2. Событие Reposition Событие Reposition используется для изменения вида формы или выполнения некоторых действий при перемещении к новой записи. Это событие происходит, когда Visual Basic перемещает указатель текущей записи на другую запись в базе данных либо при первоначальном открытии базы данных. В следующем фрагменте показано, как вывести на экран номер текущей записи с использо¬ ванием свойства AbsolutePosition объекта Recordset: Private Sub Datal Reposition() Datal.Caption = "Запись № " & _ Datal.Recordset.AbsolutePosition + 1 End Sub Когда пользователь перемещается на новую запись, используя элемент управления Data, может потребоваться отображать данные в формы по-разному, в зависимости от конкрет¬ ных значений текущей записи. Например, в форме для работы с записями служащих могут по-разному отображаться данные для постоянных служащих, подрядчиков, служащих со сдельной оплатой или слу¬ жащих с окладом. Чтобы задействовать выбор правильного режима отображения для каждой записи, можно поместить соответствующий код в событие Reposition. В следующем фрагменте событие Reposition используется для изменения состояния формы: Private Sub Datal Reposition() Datal.Caption=Datal.Recordset.AbsolutePosition If Datal.Recordset("EmployeeID") > 5 Then ' Если № служащего > 5 Optionl.Value = True ' Служащий - руководитель Else 0ption2.Value = True ' Иначе, служащий - подчиненный End If Datal.Caption = "Запись № " & _ Datal.Recordset.AbsolutePosition + 1 End Sub Форма, содержащая эту процедуру, выглядит следующим образом: Рис. 2.7. Использование события Reposition.
Гпава 2. Работа с данными через элемент управления Data 43 2.4.3. Событие Error Событие Error возникает, когда пользователь взаимодействует с элементом управления Data и происходит ошибка доступа к данным. Для добавления к элементу управления Data обработки ошибок можно использовать событие Error. Например, если пользователь изменяет поле и затем щелкает кнопку элемента управления Data, чтобы переместиться к следующей записи, элемент управления Data модифицирует текущую запись. Если в течение модификации имеет место ошибка доступа к данным, происходит событие Error. После того как произошла ошибка, значения в связанных полях не будут изменяться. Пользователь может исправить значения и затем щелкнуть элемент управления Data, чтобы попытаться модифицировать запись снова. Вывод на экран сообщения об ошибке Если к событию Error не добавлен код обработки ошибок и, когда пользователь взаимодей¬ ствует с элементом управления Data, возвращается ошибка, Visual Basic выведет на экран сообщение об ошибке и продолжит выполнение приложения. Если требуется подавить вывод стандартного сообщения об ошибке, можно установить параметр Response процедуры Error() в ноль и выводить на экран пользовательское сооб¬ щение об ошибке, как показано в следующем фрагменте: Private Sub Datal Error(DataErr As Integer, Response As Integer) If DataErr = 3022 Then ' Дублирование ключевого значения - ошибка MsgBox "Введите уникальный номер служащего" txtEmpID.SetFocus Response = 0 Else Response = 1 ' Вывести стандартное сообщение End If End Sub 2.5. Использование связанных элементов управления ActiveX В дополнение к встроенным связанным элементам управления, Visual Basic обеспечивает ряд подключаемых связанных элементов управления ActiveX. 2.5.1. Элементуправления DBGrid Элемент управления связанная сетка (DBGrid), в отличие от многих других связанных элементов управления, позволяет пользователям приложения базы данных просматривать и редактировать одновременно несколько записей. Вывод на экран нескольких записей DBGrid — элемент управления ActiveX, в котором на экран выводится ряд строк и столбцов, представляющих записи и поля из объекта Recordset. Когда свойство DataSource элемента управления DBGrid ассоциируется с элементом управления Data, элемент управления DBGrid автоматически заполняется данными; заголовки столбцов будут взяты из структуры полей набора записей. Иллюстрацию формы, в которой используется элемент управления DBGrid, см. на рис. 2.6, где в таблице в нижней части формы (DBGrid) представлены позиции заказа.
44 Использование связанных элементов управления ActiveX Чтобы подключить элемент управления DBGrid к проекту: 1. В меню Project выбрать Components. 2. Во вкладке Controls окна диалога Components (см. рис. 1.3) выбрать Microsoft Data Bound Grid Control и нажать OK или Apply. Пользователи могут установить фокус на отдельные ячейки и редактировать данные непос¬ редственно в ячейке. Можно также выбрать все строки или ячейки (щелкнув заголовок столбца). Во время разработки можно установить ширину столбца и высоту строки. Кроме того, для пользователей можно установить запрет изменять форматирование в период выполнения. В период выполнения текущую ячейку в сетке определяют свойства Row и Col. Текущую ячейку можно указать в программном коде, либо пользователь может изменить ее, исполь¬ зуя мышь или клавиши курсора. Когда пользователь изменяет текущую ячейку, указатель записи соответствующего элемента управления Data автоматически перемещается к запи¬ си, содержащей выбранную ячейку. Ячейки можно отредактировать в интерактивном режиме, вводя данные в ячейку либо программным способом, изменяя свойство Value текущего объекта Column (см. ниже). Будучи создан, элемент управления DBGrid содержит единственный столбец и единствен¬ ную строку. В нем также имеется пустая строка, обозначенная звездочкой (*), которая используется для добавления новых записей. Окно свойств содержит свойства элемента управления DBGrid в целом; элемент управле¬ ния можно перемещать и устанавливать по размеру. Чтобы установить свойства для от¬ дельных объектов Column, необходимо щелкнуть элемент управления правой кнопкой мыши и выбрать Edit из контекстного меню. Используя контекстное меню, можно вставлять или удалять столбцы или вырезать и вставлять их через буфер обмена. Можно также создать столбец и скрыть его, назначив для него нулевую ширину. Элемент управления DBGrid имеет несколько свойств, определяющих его поведение. Напри¬ мер, если в True установлено свойство AllowUpdate, пользователь может изменять данные в элементе управления. Свойства можно установить также для отдельных столбцов. Чтобы установить свойства столбца: 1. Щелкнутьэлементуправления DBGrid правой кнопкой мыши. 2. В контекстном меню выбрать Properties. 3. В окне диалога Property Pages открыть вкладку Columns. Здесь можно изменить заголовок столбца, назначить связанное поле данных, установить значение по умолчанию и так далее. Чтобы установить заголовки столбцов элемента управления DBGrid, нужно во время разра¬ ботки щелкнуть элемент управления правой кнопкой мыши и в контекстном меню выбрать Retrieve Fields. Получение и установка содержимого текущей ячейки Для получения значения выбранной ячейки в период выполнения используется семейство Columns элемента управления DBGrid. Например: MsgBox DBGridl.Columns(DBGridl.Col).Text Чтобы изменить информацию в элементе управления DBGrid, следует изменить ассоцииро¬ ванный объект Recordset. Например, если элемент управления DBGrid связан с набором записей элемента управления Data1, потребовалось бы выполнить следующий код:
Гпава 2. Работа с данными через элемент управления Data 45 Datal.Recordset.Edit Datal.Recordset.Fields("Product Name") = "Дискета" Datal.Recordset.Update Использование события BeforeUpdate Событие BeforeUpdate происходит перед тем, как данные перемещаются из элемента управления DBGrid в буфер элемента управления Data. В случае необходимости можно либо подтвердить, либо отменить модификациюданных. 2.5.2. Элемент управления MSFIexGrid Элемент управления MSFIexGrid обеспечивает дополнительные возможности при таблич¬ ном представлении данных. Он подобен элементу управления DBGrid; однако, будучи связан с элементом управления Data, элемент управления MSFIexGrid отображает на экране данные только для чтения. Элемент управления MSFIexGrid можно использовать для объединения строк или столбцов данных какспособ группирования связанной информации. На следующей иллюстрации показаны записи, которые сгруппированы по полю OrderlD (№ заказа) в таблице Order Details (позиции заказа). Рис. 2.8. Представление данных в элементе управления MSFIexGrid. Чтобы объединить ячейки: 1. Установить для свойства MergeCells значение константы, отличное от нуля. 2. Установить в True элементы массивов свойств MergeRow () и MergeCol () для строк и столбцов, которые требуется объединить. Например, чтобы объединить ячейки в таблице Order Details, нужно к форме, которая содержит элемент управления MSFIexGrid, добавить следующий код: Private Sub Form Load() MSFlexGridl.MergeCells = flexMergeFree MSFlexGridl.MergeCol(O) = True End Sub Подключить элемент управления MSFIexGrid к проекту можно через окно диалога Components (меню Project | Components).
46 Использование связанных элементов управления ActiveX 2.5.3. Элемент управления DBCombo Элементы управления связанное поле со списком (DBCombo) и связанный простой список (DBList) можно использовать для автоматического вывода на экран списка значений из набора записей. С помощью этих элементов управления списки можно ограничивать допу¬ стимыми значениями. Например, если пользователь должен ввести для заказа номер грузоотправителя, можно использовать элемент управления DBList для вывода на экран списка всех грузоотправите¬ лей из таблицы Shippers (база данных Nwind.mdb). Получение информации из подстановочной таблицы Эти элементы управления можно использовать также в приложениях с подстановочными данными. Например, можно вывести на экран списокдопустимых наименований групп (вместо номе¬ ров), но когда пользователь добавляет или изменяет данные, использовать для сохранения соответствующий числовой идентификатор. На следующей иллюстрации показана форма, в которой элемент управления DBCombo используется для вывода на экран названий групп для таблицы товаров Products, а также установка свойств: Отображать: RowSource=DatCategories /ListField=CategogyName Модифицировать: /DataSource=DatProducts DataField=Categoryld (из таблицы Products) BoundColumn=Categoryld (из таблицы Categories) Рис. 2.9. Использование DBCombo в приложении с подстановочными данными. Установка свойств элемента управления DBCombo Чтобы определить, какое значение должно быть показано в элементе управления DBCombo, нужно ассоциировать свойство RowSource с именем элемента управления Data, а в свойство ListField внести имя поля. Связанное поле со списком будет содержать все значения соответствующего поля. Чтобы указать, какое поле базы данных должно обновляться, когда пользователь изменяет значе¬ ние, нужно установить свойства DataSource и DataField. Установить отношение между таблицей, обеспечивающей подстановочные значения, и фактически редактируемой табли¬ цей можно назначением свойства BoundColumn. Обычно при работе с элементами управления DBList и DBCombo используются два элемен¬ та управления Data — один для заполнения списка, как определено свойствами ListField и RowSource, и другой — для модификации поля базы данных, специфицированного свойст¬ вами DataSource и DataField.
Гпава 2. Работа с данными через элемент управления Data 47 Таким образом: Свойство Описание DataSource Имя элемента управления Data, через который список или комбинирован¬ ный блок связан с базой данных. DataField Имя поля в наборе записей, специфицированном свойством DataSource. При выборе элемента в списке это поле будет обновлено при перемеще¬ нии к новой записи. RowSource Имя второго элемента управления Data, который будет использоваться для заполнения списка. BoundColumn Имя поля набора записей, специфицированного свойством RowSource. Это поле должно иметь тот же тип, что и DataField, и используется для заполнения списка другого элемента управления специфицированного свойством DataSource. ListField Имя поля в наборе записей, специфицированном RowSource, которое бу¬ дет использоваться для заполнения списка. Свойство ListField определяет поле, данными которого заполняется список. Второй элемент управления Data, определенный свойством DataSource, управляет набором записей, содер¬ жащим поле, обновляемые значения которого передаются в базу данных. Когда пользова¬ тель выбирает элемент списка, значение поля, специфицированного свойством BoundColumn, передается в поле элемента управления Data, определенного свойствами DataSource и DataField. Таким образом, можно определить одно поле (внешнее) для запол¬ нения списка (RowSource.ListField) и второе поле (RowSource.BoundColumn из того же набора записей) для передачи значения во второй набор записей для модификации поля DataSource.DataField в базе данных.
48 Обзор DAO Глава 3. Работа с данными через интерфейс DAO Объекты доступа к данным (DAO) — набор объектов, таких как Database, TableDef, Recordset и QueryDef, которые позволяют обращаться, организовывать и манипулировать программным способом данными в локальных или удаленных базах данных, включая объекты структуры базы данных. 3.1. Обзор DAO Порядок иерархии объектов DAO образует его объектную модель. Объектная модель DAO позволяет формировать программный интерфейс, предоставляющий обширный доступ к объектам этой иерархии и кфункциональным возможностям базы данных. Рис. 3.1. Объектная иерархия DAO. Вся объектная иерархия DAO подчинена ядру базы данных Jet (объект DBEngine). При создании или обращении к определенным объектам производится обращение к этой иерархии. Например, следующий код открывает базу данных: Set dbDbl = DBEngine.Workspaces(O) _ .OpenDatabase("Dbl.mdb") В следующей таблице представлены некоторые из объектов доступа кданным и их исполь¬ зование. Объект Описание Workspace Содержит открытые базы данных. Database Открытая база данных.
Гпава 3. Работа с данными через интерфейс DAO 49 Объект Описание Recordset Записи в таблице или записи, которые получены при выполнении запроса. QueryDef Сохраненное определение запроса. TableDef Сохраненное определение таблицы. Примечание: В этой главе описывается работа с данными готовой базы данных. Здесь не показы¬ вается, как использовать Visual Basic для создания новой базы данных или изменения структуры существующей базы данных. В большинстве случаев для определения или изменения структуры базы данных формата .mdb можно использовать такой инструмент, как MicrosoflAccess. 3.1.1. Объекты DBEngine и Workspace Чтобы с помощью DAO можно было обратиться кданным программным способом, сначала необходимо с помощью объекта DBEngine открыть рабочую область (см. ниже "Объект Workspace"). Объект DBEngine Объект DBEngine — объект высшего уровня в объектной модели DAO. Он содержит и управляет всеми остальными объектами иерархии DAO. Чтобы определить номер версии DAO, можно прочитать свойство Version объекта DBEngine. Для манипулирования базой данных можно также использовать методы RepairDatabase или CompactDatabase объекта DBEngine. В следующем фрагменте пока¬ зан пример использования свойства Version и метода RepairDatabase. MsgBox "Номер версии DAO - " & DBEngine.Version ' Сделать попытку восстановления базы данных DBEngine.RepairDatabase "С:\DB1.MDB" Объект Workspace Объект Workspace определяет сеанс пользователя (рабочую область) и устанавливает, как приложение будет взаимодействовать с данными. Если база данных открывается без специ¬ фицирования объекта Workspace, по умолчанию используется DBEngine.Workspaces(0). Примечание: Сеанс очерчивает последовательность операций, выполняемых процессором базы данных Microsoft Jet. Сеанс начинается, когда пользователь регистрируется, и заканчивается, когда пользователь выходит из приложения. Все операции, выполняемые в течение сеанса, форми¬ руют одну область определения транзакции, и подчинены разрешениям, определенным именем пользователя в системе и паролем. В DAO сеансы реализованы как объекты Workspace. В следующем фрагменте кода метод CreateWorkspace объекта DBEngine используется для создания новой рабочей области, в которой процессор базы данных Microsoft Jet использу¬ ется для взаимодействия с данными: Dim wspNew as Workspace Set wspNew = DBEngine.CreateWorkspace ("NewJetWorkspace", "Admin", "", dbUseJet) По мере необходимости можно открывать дополнительные объекты Workspace. Каждая рабочая область имеет ассоциированные с ней идентификатор пользователя и пароль. Примечание: Преимущество использования нескольких рабочих областей в том, что каждая рабочая область определяет отдельный сеанс и, следовательно, отдельный поток обработки. В каждом сеансе может быть установлен свой уровень защиты, и каждый сеанс может управ¬ лять транзакциями независимо от других сеансов. Если организовывать несколько уровней защиты или несколько областей определения транзакций не требуется, к объектам DBEngine
50 Обзор DAO или Workspace можно не обращаться. Visual Basic будет использовать умолчательный объект — DBEngine.Workspaces (0). 3.1.2. Открытие и закрытие базы данных Первый шаг в создании приложения базы данных — открыть базу данных. При этом объявляется объектная переменная как объект Database, и затем для открытия базы данных используется метод OpenDatabase. Объявление базы данных Объектная переменная Database описывает открываемую базу данных. Ассоциировать переменную с базой данных можно оператором Set. В следующем фрагменте база данных открывается в умолчательной рабочей области: Dim dbDbl As Database Set dbDbl = OpenDatabase ("С:\VB\Nwind.mdb") Метод OpenDatabase Синтаксис метода OpenDatabase: Set базаданных = рабочаяобласть.OpenDatabase (имя_базы_данных, опции, только_для_чтения, строкасоединения) Элементы метода OpenDatabase перечислены в следующей таблице: Элемент Назначение базаданных Объектная переменная, представляющая объект Database, кото¬ рый требуется открыть. рабочаяобласть Необязательный. Объектная переменная, представляющая суще¬ ствующий объект Workspace, который будет содержать объект Database. Если значение для рабочая область не указывается, используется умолчательная рабочая область. имя_ базы_ данных Строка, содержащая имя существующей базы данных. опции Для рабочей области базы данных Microsoft Jet — True или False. Если база данных открывается с опции = True, другой пользователь не сможет открыть эту же базу данных. Открывая базу данных для исключительного использования, можно повысить производитель¬ ность работы. Значение по умолчанию — False. только_для_чтения True или False. Если True, модификации не допускаются. Значение по умолчанию — False. строкасоединения Строка, содержащая различную информациюсоединения, включая пароли. Примечание: Если сеть это поддерживает, в имени базы данных можно использовать сетевой путь, например: Wserver1\dir1\Db1.mdb. Метод Close По завершении работы с базой данных ее нужно закрыть, используя метод Close, как в следующей строке: dbDbl.Close
Гпава 3. Работа с данными через интерфейс DAO 51 3.2. Работа с наборами записей Набор записей — совокупность записей из базы данных. Для отбора информацию из базы данных программным способом используется объект Recordset. После открытия базы данных манипулировать данными, сохраненными в базе данных, можно, создавая набор записей. Для создания набора записей вначале объявляется пере¬ менная как объект Recordset, и затем используется метод OpenRecordset. 3.2.1. Объявление объекта Recordset Объектная переменная Recordset ассоциируется с набором записей. Для привязки пере¬ менной к набору записей используется оператор Set. В следующем фрагменте кода открывается база данных и создается набор записей: Dim dbDbl As Database Dim recEmployees As Recordset Set dbDbl = OpenDatabase ( "С:\VB\Nwind.mdb") Set recEmployees = dbDbl.OpenRecordset ("Employees") Синтаксис метода OpenRecordset: Set o6beKm_Recordset = o6bemTrOpenRecordset (источник, тип, опции, блокировки) В следующей таблице перечислены элементы метода OpenRecordset: Элемент Описание o6beKm_Recordset Объектная переменная, представляющая объект Recordset, который требуется открыть. объект Объектная переменная, представляющая существующий объект (база данных, таблица, запрос, другой набор записей), на базе кото¬ рого создается новый Recordset. источник Определяет источник для набора записей. Источник — строка, со¬ держащая имя таблицы, имя запроса или оператор SQL. тип Тип создаваемого объекта набора записей — dbOpenTable, dbOpenDynaset или dbOpenSnapshot. опции Определяет, как будет открыт набор записей. Например, можно от¬ крыть набор записей и позволить листать его только вперед (опция dbForwardOnly). блокировки Определяет блокировку для набора записей. Например, если для параметра блокировки специфицируется dbPessimistic, набор запи¬ сей будет на время редактирования блокирован. Дополнительную информацию см. в разделе "Блокировка ядра базы данных Microsoft Jet" главы 4 "Расширенные возможности программирования доступа к данным". Например, следующий код создает набор записей только для чтения: Dim recOrders As Recordset Set recOrders = dbDbl.OpenRecordset ("Orders", dbOpenDynaset, dbForwardOnly) В следующем фрагменте кода для определения типа набора записей проверяется свойство Type объекта Recordset:
52 Работа с наборами записей Select Case recWhatType.Type Case dbOpenTable Msgbox "Это - набор записей типа table" Case dbOpenDynaset Msgbox "Это - набор записей типа dynaset" Case dbOpenSnapshot Msgbox "Это - набор записей типа snapshot" End Select 3.2.2. Типы объектов Recordset Для рабочей области базы данных Microsoft Jet имеется четыре типа наборов записей: table, dynaset, snapshot и forward-only. Table. Набор записей типа table соответствует единственной таблице и может изменяться. В память загружается только текущая запись. Порядок записей в наборе определяет стан¬ дартный индекс. Нельзя создавать набор записей типа table на базе присоединенной таблицы. Присоединенная таблица — таблица в другой базе данных, которая связана с базой данных Microsoft Jet. Данные присоединенной таблицы остаются во внешней базе данных. Информацию относительно присоединенных таблиц см. в главе 4 "Расширенные возможности программирования доступа к данным". Dynaset. Набор записей типа dynaset — динамический набор записей, которые могут содержать поля из одной или больше таблиц базы данных. Dynaset также позволяет изменять данные. Для каждой записи набора dynaset вместо фактических данных хранит первичный ключ. Фактические данные отбираются только при обращении к конкретной записи. Оупазе^тражает модификации всуществующихзаписяхдругими пользователями, но не отражает записи, которые добавлены другими пользователями. Если другой пользо¬ ватель удаляет запись после того, как dynaset полностью заполнен, набор будет содержать указатель на удаленную запись. При попытке обращения к удаленной записи будет возвра¬ щена ошибка выполнения. Snapshot. Набор записей типа snapshot может содержать поля из одной или больше таблиц базы данных. Он представляет фиксированную, или статическую, копию данных в состоя¬ нии на момент создания набора snapshot. Snapshot не может быть обновлен и не отражает изменения, проведенные в данных другими пользователями. Snapshot полностью не запол¬ няется, пока пользователь не переместится в конец набора записей. Forward-Only. Набор записей типа forward-only подобен набору записей типа snapshot, за исключением того, что записи можно листать только вперед. Сравнение типов объектов Recordset Тип используемого набора записей зависит от того, что требуется выполнять с данными в наборе записей. Если для упорядочения записей будут использоваться индексы, следует создать набор типа table. Поиск в таблице выполняется намного быстрее, чем в наборах типа dynaset или snapshot. Обычно table — самый быстрый тип наборов записей, в то время как dynaset — наиболее гибок в работе. Если используется dynaset, процессор базы данных Microsoft Jet отбирает только первич¬ ный ключ каждой записи в наборе. Если используется набор записей типа snapshot, процес¬ сор Jet отбирает всю запись. В обоих случаях результирующие наборы размещаются в памяти (выгружаясь, в случае необходимости, на диск), что позволяет прокручивать набор в любом направлении.
Гпава 3. Работа с данными через интерфейс DAO 53 Когда необходимо обработать запись, в snapshot данные доступны локально. В случае с dynaset, с другой стороны, чтобы отобрать полную запись, потребуется выполнить отдель¬ ный запрос. С целью сокращения времени запроса процессор Microsoft Jet запрашивает на сервере кластеры строк, специфицированных их закладками, вместо отбора по одной записи. Если предполагается сделать единственный проход через набор записей, лучше использо¬ вать набор forward-only. 3.2.3. Вывод записей в форме При работе через интерфейс DAO элементы управления не связаны с набором записей, как в случае с элементом управления Data. Необходимо явно копировать данные из набора записей в элементы управления в форме. В следующем фрагменте иллюстрируются два способа копирования данных из поля базы данных в текстовое поле формы: txtEmpID.Text = recEmployees("EmployeeID") ' Или альтернативный синтаксис txtEmpID.Text = recEmployees![EmployeeID] Для обращения к полям в текущей записи можно использовать семейство Fields. Ниже приводится образец кода, в котором печатаются данные из полей набора записей: ' Печать первого поля текущей строки набора записей Print recEmployees.Fields(0) ' Цикл через все поля текущей записи For Each fldCurrent In recEmployees.Fields Print fldCurrent.Value Next Управление данными Null При попытке назначить пустое значение для элемента управления в текстовое поле возвра¬ щается ошибка выполнения. В следующем фрагменте, чтобы избежать этой ошибки, ис¬ пользуется функция lsNull: If IsNull(recEmployees("Notes")) Then txtNotes.Text = "Примечаний по служащему нет" Else txtNotes.Text = recEmployees("Notes") End If Перемещение по набору записей Навигация по набору записей основана на понятии текущей записи. Текущую запись можно представить себе как запись списка, подсвеченную невидимым курсором. Для осуществления навигации по записям набора используются методы группы Move. Методы MoveFirst и MoveLast перемещают указатель текущей записи на первую и послед¬ нюю запись в наборе записей. Методы MoveNext и MovePrevious перемещают указатель на одну запись относительно текущей записи или закладки. Метод Move перемещает указатель на определенное количество строк вперед или назад.
54 Работа с наборами записей В следующем фрагменте показаны примеры использования метода Move: recEmployees.Move +5 ' На 5 строк вперед recEmployees.Move -6 ' На 6 строк назад 3.2.4. Навигационные свойства Объект Recordset обеспечивает ряд свойств, которые можно использовать при навигации в наборе записей. Например, свойство BOF можно использовать для недопущения ошибок выполнения при перемещении выше первой записи. Свойства BOF and EOF Свойства BOF и EOF указывают начало или конец набора записей. Если и BOF, и EOF — True, в наборе не имеется никаких записей. При использовании методов MoveNext или MovePrevious следует контролировать свойства BOF и EOF, чтобы быть уверенным, что указатель не перемещается вне набора записей. Свойства BOF или EOF устанавливаются в True при перемещении на одну запись до первой или после последней записи. При попытке перейти на запись выше BOF или после EOF возвращается ошибка выполнения (см. также рис. 2.4). Ниже приводится пример проверки свойства EOF: recEmployees.MoveNext If recEmployees.EOF Then recEmployees.MoveLast Beep End If Свойство RecordCount Свойство RecordCount набора записей типа table точно отражает количество записей в таблице и немедленно обновляется, когда пользователь добавляет или удаляет запись. Свойство RecordCount набора записей типа dynaset или snapshot возвращает количество записей, к которым имело место фактическое обращение. В этом случае свойство Record¬ Count не показывает, сколько записей содержится в dynaset или snapshot, пока набор записей не будет полностью заполнен. Чтобы заполнить набор записей типа dynaset или snapshot, следует воспользоваться мето¬ дом MoveLast, имитируя отбор последней записи. Однако использование метода MoveLast этим способом может отрицательно воздействовать на производительность приложения. Перед чтением свойства RecordCount лучше подождать, пока набор записей не будет заполнен по мере выполнения других разделов кода, за исключением случаев, когда требу¬ ется знать точное количество записей сразу при открытии набора. В следующем фрагменте кода в окне сообщения на экран выводится количество записей в наборе: MsgBox "В наборе записей - " & recEmployees.RecordCount & "записей" Примечание: Для определения количества записей в наборе можно также использовать функцию SQL Count. Например, строка SELECT Count(*) FROM Employees возвращает количество записей в таблице Employees.
Гпава 3. Работа с данными через интерфейс DAO 55 Свойство AbsolutePosition Свойство AbsolutePosition возвращает или устанавливает относительный номер текущей записи в наборе записей. AbsolutePosition отсчитывается от нуля (то есть, первая запись в наборе — запись 0). Если для свойства AbsolutePosition устанавливается значение 3, текущей становится четвертая запись. Следующий код выведет в надписи абсолютную позицию текущей записи: lblStatus.Caption = "Указатель находится на записи № " & rs.AbsolutePosition + 1 Свойство Bookmark Свойство AbsolutePosition записи может изменяться, по мере добавления и удаления запи¬ сей из набора. Для возвращения к определенной записи следует использовать свойство Bookmark (закладка). В следующем фрагменте закладка используется для сохранения позиции и возвращения к ней: Dim varBookmark As Variant varBookmark = recEmployees.Bookmark ' Сохранить позицию в наборе ' [Здесь - некоторый программный код] recEmployees.Bookmark = varBookmark ' Вернуться в сохраненную позицию 3.2.5. Пример создания и перемещения по набору записей В этом примере механизмы DAO используются для открытия базы данных и создания набора записей. Создание формы Группы товаров 1. Создать новый проект Standard EXE. 2. Назвать умолчательную форму frmCategories. 3. Добавить к форме элементы управления, как показано на следующей иллюстрации: щМ Рис. 3.2. Форма Группы товаров. Открытие базы данных и создание набора записей 1. В модуле формы объявить две переменные уровня модуля, как показано в следующем коде: Dim dbCurrent As Database Dim recCategories As Recordset 2. Установить ссылку на библиотеку объектных модулей Microsoft DAO 3.5 (команда меню Project | References).
56 Работа с наборами записей Примечание: Библиотека объектных модулей — данные, сохраненные в файле .olb или внутри исполняемого модуля (.exe, .dll или .ocx). Библиотека обеспечивает информацию, используемую контроллерамиАвтоматики (такими, как Visual Basic), относительно доступныхобъектовАвто- матики. Для исследования содержимого библиотеки объектных модулей и получения информации относительно обеспечиваемых объектов можно использовать окно Object Browser (см. рис. 1.7). 3. В процедуре обработки события Load формы Группы товаров проделать следующие шаги: а) Открыть базу данных WB\Nwind.mdb и сохранить результирующий объект базы дан¬ ных в переменной dbCurrent. б) Создать набор записей, используя таблицу, и фиксировать результирующий объект Recordset в переменной recCategories. в) Перейти к первой записи набора записей. г) Прочитать значения CategorylD, CategoryName и Description в соответствующие эле¬ менты управления. Программный код этих шагов будет выглядеть следующим обра¬ зом: Private Sub Form Load() Set dbCurrent = OpenDatabase("C:\VB\Nwind.mdb") Set recCategories = dbCurrent.OpenRecordset("Categories") recCategories.MoveFirst FillFields End Sub Sub FillFields() ' Эта процедура заполняет поля формы ' и будет вызываться из нескольких процедур txtCategoryID.Text = recCategories.Fields("CategoryID") txtCategoryName.Text = recCategories.Fields("CategoryName") txtDescription.Text = recCategories.Fields("Description") End Sub 4. В процедуре обработки события Unload формы закрыть базу данных: dbCurrent.Close 5. Протестировать правильность отображения первой записи набора. Добавление кода для кнопок навигации Добавить программный код, чтобы сделать командные кнопки функциональными: • после перемещения заполнить поля формы текущими данными; • протестировать на начало и конец набора записей. Текст кода кнопок должен выглядеть примерно следующим образом: Private Sub cmdPrevious Click() ' Кнопка "Назад" recCategories.MovePrevious If recCategories.BOF Then Beep recCategories.MoveFirst Else FillFields End If End Sub Private Sub cmdNext Click() ' Кнопка "Вперед" recCategories.MoveNext
Гпава 3. Работа с данными через интерфейс DAO 57 If recCategories.EOF Then Beep recCategories.MoveLast Else FillFields End If End Sub 3.3. Работа с данными После создания набора записей можно использовать методы объекта Recordset для моди¬ фикации, добавления или удаления записей. 3.3.1. Изменение записей Для модификации записи нужно вызвать метод Edit, заполнить поля записи соответствую¬ щими данными и затем вызвать метод Update: Private Sub cmdUpdate Click () recEmployees.Edit ' Текущая запись заносится в буфер редактирования recEmployees("LastName") = txtLName.Text recEmployees.Update End Sub Если метод Update вызывается без предварительного вызова метода Edit, возвращается ошибка выполнения. Свойство EditMode Для определения, вызывалисьли методы Edit nnnAddNew, можно контролировать свойство EditMode. Это может быть полезно при выполнении команды Save (Сохранить), когда метод Update вызывается немедленно после метода Add или выполняется метод Edit, сопровож¬ даемый методом Update, если пользователь редактирует текущую запись. В следующей таблице представлены константы, которые указывают состояние редактиро¬ вания текущей записи: Константа Описание dbEditNone Текущей операции редактирования нет. dbEditlnProgress Был вызван метод Edit и текущая запись находится в буфере редакти¬ рования. dbEditAdd Был вызван метод AddNew, и текущая запись в буфере редактирова¬ ния — новая запись, которая еще не была сохранена в базе данных. Ниже приводится пример кода, в котором проверяется текущее значение свойства EditMode, и, в случае необходимости, вызывается метод Edit: Private Sub cmdUpdate Click() If recEmployees.EditMode = dbEditNone Then recEmployees.Edit End If recEmployees("LastName") = txtLastName.Text recEmployees("FirstName") = txtFirstName.Text recEmployees.Update End Sub
58 Работа с данными 3.3.2. Добавление записей Для добавления новой записи к набору применяется метод AddNew. Запись физически не будет сохранена в базе данных, пока не будет вызван метод Update. Следующий код можно применить к командной кнопке "Новая запись", которая очищает форму и вызывает метод AddNew. Sub cmdAdd_Click () ClearFields recEmployees.AddNew End Sub Sub ClearFields () ' Очистка полей формы txtNamel.Text = "" End Sub Sub cmdUpdate Click () ' Кнопка "Сохранить" recEmployees("LastName") = txtLName.Text recEmployees.Update End Sub Пользователь может сформировать новую запись и затем щелкнуть кнопку "Сохранить". Код для этой кнопки копирует значения из полей формы в набор записей и сохраняет запись в базе данных. Отмена модификаций Методом CancelUpdate можно отменить действия методов AddNew или Edit, чтобы измене¬ ния не были перенесены в базу данных. Следующий код отменяет модификацию и регенерирует содержимое двух текстовых полей. Sub cmdCancel Click () recEmployees.CancelUpdate txtLastName.Text = recEmployees("LastName") txtFirstName.Text = recEmployees("FirstName") End Sub 3.3.3. Удаление записей Для удаления текущей записи из набора используется метод Delete. Важно! При удалении записи этим методом никаких предупреждений или подсказок не выводится. Предупрежда¬ ющее сообщение в случае необходимости можно добавить в подпрограмме удаления. Удаление записи не обусловливает автоматического перехода указателя текущей записи на следующую запись. Чтобы сделать следующую запись текущей, нужно вызвать метод MoveNext. В следующей процедуре текущая запись удаляется из набора, и указатель перемещается на следующую запись: Private Sub cmdDelete Click() recEmployees.Delete recEmployees.MoveNext If recEmployees.EOF Then recEmployees.MoveLast End If FillFields ' Пользовательская процедура End Sub
Гпава 3. Работа с данными через интерфейс DAO 59 Чтобы определить, удалены ли все записи в наборе, можно проверить свойство RecordCo- unt. После удаления последней записи значением свойства RecordCount становится ноль. 3.4. Совместное использование DAO и элемента управления Data В одном приложении могут "соседствовать" DAO и элемент управления Data. Это позволяет применять в приложении связанные элементы управления при одновременном использова¬ нии гибкости механизмов DAO. Свойство Recordset элемента управления Data возвращает объект Recordset. Свойство Recordset элемента управления Data можно ассоциировать с созданным объек¬ том Recordset, используя метод OpenRecordset, как показано в следующем примере: Dim recEmployees As Recordset Dim dbDbl As Database Set recEmployees = dbDbl.OpenRecordset ("Employees") Set datEmployees.Recordset = recEmployees Следует удостовериться, что свойство DataField связанных элементов управления соответ¬ ствует именам полей в объекте Recordset. 3.5. Поискзаписей Ниже показано, как использовать один из методов группы Find или метод Seek для поиска данных в наборе записей. 3.5.1. Поискзаписей в наборахтипа dynaset или snapshot В наборах записей типа dynaset или snapshot найти запись можно с использованием мето¬ дов FindFirst, FindLast, FindNext и FindPrevious. Специфицируемые критерии поиска должны быть эквивалентны оператору SQL WHERE без ключевого слова WHERE. Следующий оператор находит первую запись, которая содержит указанный номер служащего: recEmployees.FindFirst "[EmployeeeID] = 5" Если вызывается метод FindFirst или FindLast и никаких записей не найдено, указатель текущей записи перемещается, соответственно, на первую или последнююзапись в наборе. Чтобы сохранить текущую позицию записи перед вызовом метода Find и вернуться к этой позиции, если записей по критериям не найдено, можно использовать свойство Bookmark. В следующем примере кода выполняется поиск определенной записи и, если записей при поиске не найдено, указатель возвращается коригинальной позиции: Private Sub cmdFindFirst Click() Dim varBookmark as Variant varBookmark = recEmployees.BookMark ' Сохранить текущую позицию recEmployees.FindFirst "[EmployeeID] = 5" If recEmployees.NoMatch Then recEmployees.BookMark = varBookmark ' Вернуться ' к сохраненной позиции End If FillFields ' Пользовательская процедура заполнения полей End Sub
60 Поиск записей Здесь используется свойство NoMatch, позволяющее определить, нашел ли метод FindFirst запись. В следующем примере для нахождения первого служащего с фамилией, начинающейся с "А", используется символ подстановки (*). recEmployees.FindFirst "[LastName] Like 'А*'" В качестве альтернативы использованию методов FindFirst, FindLast, FindNext и FindPrevious для нахождения записей в наборах dynaset или snapshot можно приме¬ нять оператор SQL WHERE. В этом синтаксисе строковую переменную следует заключать в литеральные кавычки: strSQL = "SELECT * FROM Employees " & _ "WHERE [LastName] = " & _ "'" & txtLastName.text & "'" Set recEmployees = dbDbl.OpenRecordset (strSQL, dbOpenDynaset) В большинстве случаев при использовании методов Find создание набора записей выполня¬ ется медленнее, чем с помощью запроса SQL с предложением WHERE. Однако, если набор записей небольшой, метод Find может работать быстрее, чем обновление набора записей запросом, так как метод Find в данном случае выполняется на меньшем количестве записей. Например, нахождение записи в существующем наборе, который содержит только 10 запи¬ сей, будет быстрее, чем обновление набора запросом с предложением WHERE, при кото¬ ром придется искать среди, например, 20000 записей. 3.5.2. Поиск в наборах типа table Для поиска записи в наборе типа table используется метод Seek. Набор записей в этом случае должен иметь индекс, иначе использовать метод Seek нельзя. В следующей таблице приведены возможные операции сравнения, которые можно исполь¬ зовать с методом Seek: Операция сравнения Описание и и Равно специфицированному ключевому значению и^и Больше специфицированного ключевого значения n^ и Больше или равно специфицированному ключевому значению n^ и Меньше или равно специфицированному ключевому значению и^и Меньше специфицированного ключевого значения Для составных индексов специфицируется несколько значений. Например, если имеется индекс Name, который включает поля LastName и FirstName, можно было бы использовать метод Seek следующим образом: rs.Index = "Name" rs.Seek "=", "Степанков", "Сергей" Метод Seek позволяет находить записи в таблице быстрее, чем при использовании методов Find с наборами dynaset или snapshot. Однако методом Seek можно выполнять поисктолько при наличии индексов.
Гпава 3. Работа с данными через интерфейс DAO 61 3.5.3. Пример поиска записей в наборе В этом примере пользователю будет предоставлена возможность искать определенные записи в таблице Categories по критериям, вводимым в поле Описание формы Группы товаров. Для реализации примера нужно в форму добавить кнопку "Поиск". 1. Используя функцию lnputBox, запросить у пользователя строку, которая будет представ¬ лять часть поля Описание. 2. Используя значение, возвращенное из lnputBox, создать строку SQL, чтобы выбрать подходящие записи из таблицы Categories, как в следующем примере: "SELECT * FROM Categories WHERE [Description] LIKE '‘введенный текст*'" 3. Создать набор записей, основанный на запросе SQL, и присвоить результат переменной recCategories. Это позволит кнопкам "Вперед" и "Назад" работать с новым набором записей. 4. Если записей не найдено (recCategories.RecordCount = 0), вывести на экран сообщение об этом. Иначе — отобразить в форме первую запись нового набора записей. Текст кода кнопки "Поиск" будет выглядеть следующим образом: Private Sub cmdFind Click() Dim strSQL As String Dim strAnswer As String strAnswer = InputBox("BBeflMTe любую часть описания", "Поиск записей") ' Сформировать строку SQL strSQL = "SELECT * FROM Categories WHERE [Description] LIKE " & _ "'*" & strAnswer & "*'" Set recCategories = dbCurrent.OpenRecordset(strSQL) If recCategories.RecordCount = 0 Then ' Записей не найдено MsgBox "Подходящих записей не найдено. Выводятся все записи" Set recCategories = dbCurrent.OpenRecordset("Categories") Else ' Найдена, по крайней мере, одна запись recCategories.MoveFirst FillFields ' Заполнить поля формы End If End Sub 3.6. Использование запросов и операторов SQL В этом разделе обсуждается использование сохраненных запросов и операторов SQL для просмотра или изменения данных в базе данных. 3.6.1. Запрос на выборку Использовать сохраненный запрос на выборку (SELECT) можно, указав имя запроса при вызове метода OpenRecordset объекта Database. В следующей строке кода создается набор записей, основанный на сохраненном запросе типа SELECT Products1: Set recProducts = dbDbl.OpenRecordset("Productsl") Для отбора результатов запроса можно использовать также метод OpenRecordset объекта QueryDef. В следующем примере создается набор записей с помощью объекта QueryDef, основанного на сохраненном запросе SELECT: Dim qryProducts As QueryDef Set qryProducts = dbDbl.QueryDefs("Productsl") Set recProducts = qryProducts.OpenRecordset
62 Использование запросов и операторов SQL Установка параметров запроса Если сохраненный запрос требует параметров, установить эти параметры можно через семейство Parameters объекта QueryDef: Set qryProducts.Parameters("Ha4anbHaH дата") = CDate(txtBeginDate.text) Создание нового запроса Для создания в период выполнения нового запроса и сохранения его в базе данных исполь¬ зуется метод CreateQueryDef объекта Database: Set qryNewQuery = dbDbl.CreateQueryDef ("Queryl", "SELECT * FROM Employees") Здесь Query1 — имя сохраняемого запроса. 3.6.2. Запросы действия Запрос действия — оператор SQL, который модифицирует, удаляет или вставляет записи в базу данных. Запрос действия не возвращает каких-либо записей. Для выполнения запроса действия используется метод Execute объекта Database. В следующем фрагменте выполняется запрос действия и на экран выводится количество обработанных записей. dbDbl.Execute "Запрос действия", dbFailOnError Msgbox "Этот запрос изменил " & dbDbl.RecordsAffected & " записей" Здесь Запрос_действия — имя сохраненного запроса. Опция dbFailOnErroryKa3biBaeT методу Execute возвращать ошибку выполнения, если какая- либо из обрабатываемых записей блокирована или не может быть обновлена или удалена. Свойство RecordsAffected возвращает количество записей, которые были изменены, добав¬ лены или удалены. Для выполнения запроса действия можно также использовать объект QueryDef. Если запрос требует параметров, установить их можно через семейство Parameters объекта QueryDef, как показано в следующем примере: Dim qryUpdate As QueryDef Set qryUpdate = db.QueryDefs("Updatel") qryUpdate.Parameters ("Введите увеличение цены") = .10 qryUpdate.Execute dbFailOnerror Msgbox qryUpdate.RecordsAffected 3.6.3. Компоненты языка SQL Структурированный языкзапросов (SQL) можно использовать какдля получения подмноже¬ ства строк, так и для отбора информации одновременно из двух и более таблиц. SQL позволяет точно специфицировать, какие записи отобрать и в каком порядке. Если в операторе SQL имеется ошибка — например, если указано недостоверное имя поля — будет возвращено сообщение ошибки выполнения, подобное "Too few parameters. Expected 2 (Слишком мало параметров. Ожидалось 2)". Если получена эта ошибка, следует проверить строку SQL и также проверить правильность перечисленных в ней имен таблиц и полей.
Гпава 3. Работа с данными через интерфейс DAO 63 Оператор SELECT Оператор SQL SELECT используется для формирования запроса на выборку записей. Синтаксис SELECT: SELECT список_полей FROM списоктаблиц WHERE критерии ORDER BY список_полей В следующем примере в таблице Employees отбираются поля LastName (фамилия) и EmployeelD (номер служащего) только тех записей, где EmployeelD — больше 5. Записи отбираются в порядке убывания значений EmployeelD: SELECT [LastName], [EmployeeID] FROM Employees WHERE [EmployeelD] > 5 ORDER BY [EmployeelD] DESC Предложение WHERE Предложение WHERE используется для ограничения выбора записей. Знак номера (#) указывает значения литералов даты. Значения литералов даты, введенные в оператор SQL, должны быть в американском формате дат (например, 10 мая 1997 года записывается как 5/10/97). Ниже показаны различные примеры операторов SQL: ' Базовый синтаксис WHERE strSQL = "SELECT * FROM Employees WHERE [LastName] = " & _ "'" & txtLName.text & "'" ' Синтаксис WHERE IN strSQL = "SELECT Employees.[LastName] FROM Employees " & _ "WHERE Employees.Sity IN ('Иваново/Тверь' ) " ' Синтаксис WHERE BETWEEN strSQL = "SELECT [OrderID] FROM Orders WHERE " & _ "([OrderDate] BETWEEN #01/01/96# AND #12/31/96#)" strSQL = "SELECT [OrderID] FROM Orders WHERE " & _ "([OrderDate] BETWEEN #" & CDate(txtStartDate.TEXT) & _ "# AND #" & CDate(txtEndDate.TEXT) & "#)" Предложение ORDER BY Предложение ORDER BY используется для создания набора записей в специфицирован¬ ном порядке. Опция ASC указывает порядок возрастания, a DESC — порядок убывания. В следующем примере из таблицы Employees возвращаются все поля; записи набора сортируются по полю LastName (фамилия): SELECT * FROM Employees ORDER BY [LastName] DESC Использование оператора SELECT с несколькими таблицами Для объединения данных из нескольких таблиц можно использовать операцию соединения JOIN. Например, если требуется вывести на экран наименования групп товаров и названия товаров из различных таблиц, можно соединить записи из таблиц Categories и Products.
64 Использование запросов и операторов SQL Предложение INNER JOIN определяет, что, например, требуется получить записи, для которых номер группы (CategorylD) из таблицы Categories соответствует номеру группы из таблицы Products. В следующем примере соединяется информация из таблицы Categories и таблицы Products: strSQL = "SELECT Categories.[CategoryName], " & _ "Products.[ProductName] " & "FROM Categories " & _ "INNER JOIN Products ON " & _ "Products.[CategoryID] = Categories.[CategoryID]" На следующей иллюстрации показан примерный результат этой операции соединения: Рис. 3.3. Формирование и результаты операции соединения. 3.6.4. Использование операторов SQL в коде Visual Basic Для отбора или изменения информации в базе данных операторы SQL можно вводить в текст кода Visual Basic. Примечание: Обычно более эффективно использовать сохраненный запрос, нежели создавать оператор SQL в период выполнения. Создание оператора SELECT В период выполнения можно динамически формировать строку SQL и использовать метод OpenRecordset для создания набора записей, основанного на операторе SQL. Например: Dim stSQL As String strSQL = "SELECT * From Employees" Set recEmployees = dbDbl.OpenRecordset (strSQL) Создание оператора UPDATE Оператор SQL UPDATE изменяет существующие записи. Опция dbFailOnError обусловли¬ вает аннулирование модификации, если в течение модификации возвращается ошибка. Кроме того, будет вызвана процедура обработки ошибки. В следующем фрагменте показано использование оператора SQL UPDATE: strSQL = "UPDATE Products SET [Discount] = 1 " & _ "WHERE [Discount] = 0" dbDbl.Execute strSQL, dbFailOnError
Гпава 3. Работа с данными через интерфейс DAO 65 Создание оператора INSERT С помощью оператора INSERT можно вставить новую запись. В следующем примере формируется и вставляется запись в таблицу Employees: strSQL = "INSERT INTO Employees " & _ "([First Name], [Last Name]) " & _ "VALUES ('Сергей', 'Степанков')" dbDbl.Execute strSQL, dbFailOnError 3.6.5. Пример использования запросов SQL В этом примере для получения из базы данных Nwind.mdb информации по десяти наиболее дорогим товарам используется сохраненный запрос. 1. Создатьновуюформу. 2. Сохраненный запрос Ten Most Expensive Products в базе данных Nwind.mdb возвращает десять самыхдорогихтоваров. В процедуре обработки события Form_Load новой формы нужно создать набор записей, основанный на этом запросе, и вывести на экран резуль¬ таты в элементе управления DBGrid, как показано на следующей иллюстрации: Рис. 3.4. Запрос десяти самых дорогих товаров. Для справки: Оператор (свойство SQL) сохраненного запроса Ten Most Expensive Products: SELECT DISTINCTROW TOP 10 Products.ProductName AS TenMostExpensiveProducts, Products.UnitPrice FROM Products ORDER BY Products.UnitPrice DESC; Программный код процедуры Form_Load() должен выглядеть следующим образом: Private Sub Form Load() Dim dbCurrent As Database Dim recProducts As Recordset Set dbCurrent = DBEngine.Workspaces(0).OpenDatabase("C:\VB\Nwind.mdb") Set recProducts = dbCurrent.OpenRecordset("Ten Most Expensive Products") Set datProducts.Recordset = recProducts End Sub
66 Использование запросов и операторов SQL Или эквивалентный код (лишние и измененные строки закомментированы): Private Sub Form Load() Dim dbCurrent As Database 'Dim recProducts As Recordset Set dbCurrent = DBEngine.Workspaces(0).OpenDatabase("C:\VB\Nwind.mdb") 'Set recProducts = dbCurrent.OpenRecordset("Ten Most Expensive Products") Set datProducts.Recordset = dbCurrent.OpenRecordset("Ten Most Expensive Products") 'Set datProducts.Recordset = recProducts End Sub Примечание: В форму необходимо поместить скрытый элемент управления Data (свойство Visible = False) и ассоциировать свойство DataSource элемента управления DBGrid с элементом управления Data. Затем можно установить свойство Recordset элемента управления Data равным набору записей, возвращенным в соответствии с сохраненным запросом. Тестирование приложения 1. В меню Project выбрать Project Properties. 2. Изменить Startup Object (объект запуска) на новую форму. 3. Запустить приложение. В форме будут выведены десять наиболее дорогих товаров, как на рис. 3.4. 3.6.6. Пример использования параметрических запросов В этом примере для получения коммерческой информации из базы данных Nwind.mdb используется параметрический запрос. 1. Создать новую форму, в которой для получения данных по продажам по странам в интервале дат используется сохраненный в базе данных Nwind.mdb параметрический запрос Employee Sales by Country, как показано на следующей иллюстрации: Рис. 3.5. Форма со вводом параметров запроса.
Гпава 3. Работа с данными через интерфейс DAO 67 Имена параметров для запроса — Beginning Date и Ending Date. Для справки: Оператор SQL параметрического запроса Employee Sales by Country: PARAMETERS [Beginning Date] DateTime, [Ending Date] DateTime; SELECT DISTINCTROW Employees.Country, Employees.LastName, Employees.FirstName, Orders.ShippedDate, Orders.OrderID, [Order Subtotals].Subtotal AS SaleAmount FROM Employees INNER JOIN (Orders INNER JOIN [Order Subtotals] ON Orders.OrderID = [Order Subtotals].OrderID) ON Employees.EmployeeID = Orders.EmployeeID WHERE (((Orders.ShippedDate) Between [Beginning Date] And [Ending Date])); 2. Код кнопки "Выполнить запрос" должен выглядеть так: Private Sub cmdExecute Click() Dim strSQL As String Dim dbCurrent As Database Dim recSales As Recordset Dim qrySales As QueryDef Set dbCurrent = DBEngine.Workspaces(O).OpenDatabase ( "С:\VB\Nwind.mdb") Set qrySales = dbCurrent.QueryDefs("Employee Sales by Country") qrySales.Parameters("Beginning Date") = CDate(txtBegin) qrySales.Parameters("Ending Date") = CDate(txtEnd) Set recSales = qrySales.OpenRecordset() Set datSales.Recordset = recSales End Sub
68 Поддержание целостности данных Глава 4. Расширенные возможности программирования доступа к данным Элемент управления Data или Объекты доступа кданным можно использовать для быстро¬ го создания приложений базы данных с минимальным объемом программирования. Однако, если в приложении требуется управлять ошибками, управлять многопользователь¬ ским доступом к данным и контролировать ошибки целостности данных, без написания дополнительного программного кода не обойтись. В этой главе освещаются расширенные возможности построения приложений базы данных. 4.1. Поддержание целостности данных При создании приложения базы данных должно быть гарантировано, что в базу данных могут быть введены только достоверные данные. В Microsoft Access можно создавать правила и устанавливать ограничения ссылочной целостности в базе данных, гарантирующие целостность данных. Если эти ограничения нарушаются, возвращается ошибка выполнения. В приложении должны быть разделы кода, которые будут перехватывать эти ошибки и позволять пользователю исправить данные и продолжить выполнение. Ниже показывается, как гарантировать достоверность вводимой в базуданных информации. 4.1.1. Определение правил для обрабатываемой информации Используя базу данных Microsoft Jet, можно определять правила, в которых специфициру¬ ется, какие данные для поля или таблицы допустимы. Эти правила хранятся в базе данных и поддерживаются независимо от способа изменения данных. В базе данных Nwind имеется несколько определенных правил. Например, правило для поля Quantity (количество заказанного товара) в таблице Order Details (данные позиций заказа) определяет, что количество должно быть больше 0. Свойства, связанные с правилами Средствами Visual Basic можно создавать или просматривать правила базы данных. Объ¬ екты Field и Recordset имеют два свойства, которые связаны с правилами. Следующие свойства поддерживаются только в базах данных Microsoft Jet: ValidationRule Определяет критерии для правила. ValidationText Текст сообщения об ошибке, которое может быть выведено в случае нару¬ шения правила. В следующем примере кода в окне Immediate выводятся значения свойств ValidationRule и УаМайопТех1для поля Quantity: Sub DisplayRule() Set rstOrders = dbDbl.OpenRecordset("Order Details") ' Печатается ">0" Debug.Print rstOrders("Quantity").ValidationRule
Гпава 4. Расширенные возможности программирования доступа 69 ' Печатается "Quantity must be greater than 0" Debug.Print rstOrders("Quantity").ValidationText End Sub Примечание: Чтобы определить правило программным способом, можно установить свойство ValidationRule объекта Field. Ошибки, связанные с нарушениями правил Если при обновлении записи нарушается правило, возвращается ошибка выполнения. Свойство ValidateOnSet определяет момент, когда нарушение правила вызывает ошибку. Если ValidateOnSet — True, ошибка выполнения произойдет при установке значения поля, как показано в следующем примере: recOrders("Quantity").ValidateOnSet = True recOrders("Quantity").Value = 0 ' Здесь будет сгенерирована ошибка recOrders.Update Если ValidateOnSet — False, ошибка выполнения произойдет при вызове метода Update, как в следующем примере: recOrders("Quantity").ValidateOnSet = False recOrders("Quantity").Value = 0 recOrders.Update ' Здесь будет сгенерирована ошибка Обработка нарушений правил Обычно, если происходит нарушение правила, следует предоставить пользователю воз¬ можность исправить данные и повторить попытку модификации. Если используется эле¬ мент управления Data и имеет место нарушение правила, происходит событие Error. Элемент управления Data выводит на экран значение свойства ValidationText и отменяет модификацию. Пользователь может изменитьданные и щелкнутьэлементуправления Data снова, чтобы попытаться повторить модификацию. Чтобы предпринять различные действия в случае возвращения ошибки, можно добавить код к процедуре события Error. Например, можно вывести текст в заголовке формы, а не в окне сообщения, или подать звуковой сигнал и изменить свойство ForeColor полей (цвет литер), чтобы показать, что произошла ошибка. Если в момент нарушения правила используются объекты доступа кданным, возвращается ошибка выполнения. Эту ошибку необходимо предусмотреть, перехватить и сообщать о ней пользователю. В следующем примере кода, в случае нарушения правила, на экран выводится сообщение: Private Sub cmdUpdate Click() On Error GoTo Update err rs.Edit rs("OrderId") = txtOrder.Text rs.Update Exit Sub Update_err: If Err.Number = 3316 Then ' Нарушение правила lblError.Caption= Err.Description rs.CancelUpdate Exit Sub End If End Sub
70 Поддержание целостности данных Свойство Description объекта Err содержит значение свойства ValidationText. Отменить текущий метод Edit или AddNew и восстановить текущую запись можно с по¬ мощью метода CancelUpdate. Можно либо оставить в форме данные пользователя, либо вернуть в форму текущие данные из базы данных. 4.1.2. Ссылочная целостность Ссылочная целостность относится к ограничениям, которые накладываются на базуданных в целях сохранения определенных отношений между таблицами в случае добавления, изменения или удаления записей. Определение ограничений ссылочной целостности Процессор Microsoft Jet может устанавливать ссылочную целостность в базе данных фор¬ мата Jet. Например, в базе данных Nwind между таблицей Customers (клиенты) и таблицей Orders (заказы) определено отношение "один-к-многим" и установлена ссылочная целостность. При попытке ввести заказ для несуществующего клиента (CustomerlD) или удалить запись клиента, с которой связаны записи заказов, возвращается ошибка выполнения. Примечание: Отношения между таблицами можно определять или программным способом, исполь¬ зуя метод CreateRelation Visual Basic, или вручную, используя Microsoft Access. Метод CreateRelation Метод CreateRelation создает новый объект Relation (отношение). Синтаксис метода: Set отношение = база бэннь/x.CreateRelation (имя, таблица, _внешняя_таблица, атрибуты) Элементы синтаксиса: Элемент Описание отношение Объектная переменная, представляющая создаваемый объект Relation. базаданных Объектная переменная, представляющая объект Database, для ко¬ торого создается новый объект Relation. имя Необязательный. String Variant, уникально именующий новый объект Relation. таблица Необязательный. String Variant, содержащий имя таблицы первично¬ го ключа в отношении. Если в момент создания объекта Relation такой таблицы не существует, возвращается ошибка выполнения. внешняятаблица Необязательный. String Variant, содержащий имя таблицы внешнего ключа в отношении. Если в момент создания объекта Relation такой таблицы не существует, возвращается ошибка выполнения. атрибуты Необязательный. Константа или комбинация констант, содержащая информацию относительно типа отношения. Объект Relation предоставляет ядру Microsoft Jet информацию относительно отношения между полями двух объектов TableDef или QueryDef. Значение атрибуты содержится и устанавливается также в свойстве Attributes объектов Field, Relation или TableDef.
Гпава 4. Расширенные возможности программирования доступа 71 Каскадные модификации и удаления При установлении ссылочной целостности в параметре атрибуты можно специфицировать значение dbRelationUpdateCascade или dbRelationDeleteCascade. Если устанавливаются эти опции, процессор базы данных Microsoft Jet позволяет пользователю изменять и уда¬ лять записи и при этом автоматически изменяет или удаляет связанные записи в связанных таблицах. Например, допустим, что создается отношение между таблицами Customers и Orders. Если выбирается опция dbRelationDeleteCascad, процессор Microsoft Jet будет удалять все свя¬ занные записи в таблице Orders всякий раз, когда пользователь удаляет запись клиента в таблице Customers. Примечание: Процессор Microsoft Jet при удалении связанных записей не выводит на экран никаких предупреждений. Чтобы избежать потерь данных при удалении записей, следует четко представ¬ лять себе отношения между таблицами, определенные в базе данных. Обработка нарушений ссылочной целостности При попытке нарушений ограничений ссылочной целостности возвращается ошибка выпол¬ нения. Эту ошибку необходимо обработать и сообщить о ней пользователю. В следующем фрагменте кода, если пользователь пытается удалить запись клиента, у которого имеются заказы, на экран выводится сообщение об ошибке: Private Sub cmdDelete Click() On Error GoTo Del Err rs.Delete rs.MoveNext FillFields ' Процедура заполнения данными полей формы Exit Sub Del Err: ' Нарушения ограничений целостности If Err.Number = 3200 Then lblError.Caption = "Удалять клиента с заказами нельзя" Exit Sub Else ' Обработка других ошибок ... End If End Sub Обратите внимание, что запись не удаляется и указатель текущей записи не смещается. Текстовые поля в форме остаются заполненными текущими данными. 4.1.3. Транзакции Транзакция — ряд операторов-действий, проделанных по отношению к базе данных. Внутри транзакции можно сгруппировать проведение нескольких изменений в базе данных. Если все операции успешны, производится фиксация транзакции. Если любая из операций терпит неудачу, вся транзакция должна быть аннулирована. Методы транзакций Методы, связанные с транзакциями, относятсякобъектуУУогкзрасе. ВызовметодаВедт- Trans означает начало транзакции. Если на любой из последующих модификаций происхо¬ дит сбой, нужно использовать метод Rollback для отмены всех модификаций транзакции.
72 Вопросы многопользовательского доступа Если все модификации успешны, вызовом метода CommitTrans нужно зафиксировать изме¬ нения в базе данных. В следующем примере транзакция создается для добавления вхож¬ дения в таблицы Orders и Order Details: Sub cmdAddOrder_Click () On Error GoTo AddOrder Err DBEngine.WorkSpaces(0).BeginTrans db.Execute "INSERT INTO Orders... .", dbFailOnError db.Execute "INSERT INTO [Order Details]...." , dbFailOnError DBEngine.WorkSpaces(0).CommitTrans lblStatus.Caption = "Модификации завершены" Exit Sub AddOrder Err: lblStatus.Caption = Err.Description Msgbox "He все модификации прошли успешно" DBEngine.Workspaces(0).Rollback Exit Sub End Sub Использование транзакций для повышения производительности В дополнение к использованию транзакций для поддержания целостности данных, заклю¬ чая в транзакцию оператор SQL UPDATE, можно повышать производительность обработки данных. Операции транзакции буферизуются и не записываются на диск, пока транзакция не будет фиксирована. В следующем примере оператор SQL UPDATE заключается в транзакцию: DBEngine.Workspaces(0).BeginTrans ' Увеличить цену единицы на 10% stSQL = "UPDATE Products SET [Unit Price] = [Unit Price] * 0.1" db.Execute strSQL, dbFailOnError DBEngine.Workspaces(0).CommitTrans Примечание: Внутри объекта Workspace транзакции могут быть вложенными. Прежде чем фикси¬ ровать или аннулировать транзакцию на более высоком уровне, необходимо проделать данную операцию для текущей транзакции. Если требуется, чтобы транзакции перекрывались, но были независимы от друг друга, нужно создать второй объект Workspace. 4.2. Вопросы многопользовательского доступа Когда нескольким пользователям позволяется одновременно обращаться к базе данных, приложение базы данных становится более сложным. В этом случае придется предусмот¬ реть обработку нескольких новых ошибок. Например: • два пользователя пытаются редактировать одни и те же данные. Ядро базы данных Microsoft Jet автоматически блокирует данные, чтобы предотвратить одновременное редактирование записи двумя пользователями. Если пользователь пытается модифици¬ ровать блокированную запись, он получит ошибку выполнения; • пользователь изменяет запись, которую другой пользователь в этот момент про¬ сматривает. Если пользователь пытается модифицировать запись, а данные с момента выполнения метода Edit изменились, ядро базы данных Microsoft Jet вернет ошибку; • пользователь удаляет запись, которую другой пользователь просматривает. Если пользователь пытается обратиться к удаленной записи, Microsoft Jet вернет ошибку. Ниже описываются эти и другие вопросы многопользовательской работы с данными.
Гпава 4. Расширенные возможности программирования доступа 73 4.2.1. Открытие таблицы в исключительном режиме Чтобы избежать проблем, которые могут возникать, когда несколько пользователей имеют возможность обращаться к базе данных, можно открывать таблицы для исключительного использования. Открытие таблицы таким образом запрещает другим пользователям рабо¬ тать с этой таблицей. Это хотя и довольно ограничительное, но в ряде ситуаций — наилуч¬ шее решение. Каким образом открывается набор записей, определяет параметр опции метода OpenRecordset. В следующем фрагменте таблица Orders открывается для исключительного доступа. Теку¬ щий пользователь может изменять таблицу, но другие пользователи не могут ни просмат¬ ривать, ни изменять данные в таблице: Set recOrders = dbDbl.OpenRecordset ("Orders", dbOpenTable, dbDenyRead + dbDenyWrite) В следующем коде таблица Orders открывается для исключительного доступа для записи. Текущий пользователь может изменять и просматривать таблицу; другие пользователи могут только просматривать данные в таблице, но не могут изменять их: Set recOrders = dbDbl.OpenRecordset ("Orders", dbOpenTable, dbDenyWrite) В следующем коде набор записей открывается в режиме только для чтения. Текущий пользователь может читать данные в таблице, но не может изменять их. На других пользо¬ вателей данная установка не воздействует. Set recOrders = dbDbl.OpenRecordset ("Orders", dbOpenTable, dbReadOnly) В следующем примере набор записей открывается в режиме добавления. Текущий пользо¬ ватель может только добавлять записи, но не может просматривать или изменять любые существующие записи. На других пользователей данная установка не воздействует. Set recOrders = dbDbl.OpenRecordset ("Orders", dbOpenDynaset, dbAppendOnly) Если предполагается только добавлять записи к таблице, для получения наивысшей произ¬ водительности следует использовать опцию dbAppendOnly. Опция dbDenyRead доступна только в наборах записей типа table. 4.2.2. Блокировка ядра базы данных Microsoft Jet Все системы управления базами данных обеспечивают некоторый механизм блокировки, предотвращающий одновременное обновление данных двумя пользователями. Процессор базы данных Microsoft Jet обеспечивает блокировку уровня страницы. Страницы — блоки записей размером 2048 байт (2K). Когда Visual Basic блокирует страницу, содержащую редактируемую запись, все остальные записи этой страницы также будут блокированы. Примечание: Информация в этом разделе касается баз данных, для управления которыми исполь¬ зуется процессор Microsoft Jet. При обращении к базам данных через ODBC применяются механизмы блокировки соответствующей системы управления базами данных. Пессимистическая и оптимистическая блокировки Значение свойства LockEdits объекта Recordset определяет, когда устанавливается блоки¬ ровка записи в наборе записей.
74 Вопросы многопользовательского доступа Если свойство LockEdits — True, устанавливается пессимистическая блокировка. Это означает, что страница, содержащая текущую запись, блокируется, как только выполняется метод Edit. Страница разблокируется, когда выполняется метод Update. Умолчательная стратегия блокировки предполагает блокирование записи на более продол¬ жительный период времени и гарантирует, что, после того как выполнен метод Edit, другой пользователь не может изменить данные. Если свойство LockEdits — False, устанавливается оптимистическая блокировка. Страни¬ ца, содержащая запись, блокируется только на время модификации записи. Блокировки в этом случае удерживаются более короткий период времени, и несколько пользователей смогут использовать метод Edit без блокирования страницы. Однако, если используется оптимистическая блокировка, усложняются механизмы управления возмож¬ ными ошибками, когда пользователь выполняет метод Update. Если частых попыток изменения одной записи несколькими пользователями не предвидит¬ ся, рекомендуется установить LockEdits в False. Разблокирование Ядро базы данных Microsoft Jet отмечает страницу, которую нужно разблокировать, как только модификация будет закончена. Однако, блокировки не удаляются, пока полностью не выполнены другие действия. Используя метод ldle объекта DBEngine с опцией dbFreeLocks, можно приостановить обра¬ ботку и позволить процессору Microsoft Jet освободить блокировки и подхватить в фоновом режиме другие задачи. Это делается следующим образом: DBEngine.Idle dbFreeLocks 4.2.3. Обработка ошибок блокировки Когда несколько пользователей модифицируют базу данных, необходимо предусмотреть код обработки следующих ошибок: 3260 Couldn’t update; currently locked (модификация невозможна по причине блокировки). Происходит при вызове метода Edit, когда текущая запись уже блокирована. В коде следует на короткое время сделать паузу и затем вызвать Edit снова или сообщить пользователю относительно ошибки. 3186 Couldn’t save; currently locked (сохранение невозможно по причине блокировки). Про¬ исходит при оптимистической блокировке при вызове метода Update, когда текущая запись блокирована. В коде следует на короткое время сделать паузу и затем вызвать Update снова или сообщить пользователю относительно ошибки. 3197 Data has changed; operation stopped (данные изменились; операция остановлена). Происходит при вызове метода Edit или Update, если другой пользователь изменил данные с момента последнего обращения к ним текущего пользователя. В коде следует обновить форму последними данными или информировать пользователя относительно ошибки. Обработка ошибок при выполнении метода Edit В следующем примере обрабатываются ошибки блокировки, которые могут происходить при выполнении метода Edit: Private Sub cmdEdit_Click() On Error GoTo HandleError rs.Edit
Гпава 4. Расширенные возможности программирования доступа 75 ButtonEditAddMode Exit Sub HandleError: Select Case Err.Number Err Select Case .Number Case 32 60 ' Текущая страница блокирована MsgBox "Запись в данный момент блокирована. Попытайтесь еще раз" Case 3197 ' Данные изменились MsgBox "Данные изменились и будут обновлены" rs.Bookmark = rs.Bookmark ' Получить обновленные данные FillFields ' Заполнить поля данными rs.Edit Case Else MsgBox Err.Number & ": " & Err.Description End Select End Sub В вышеприведенном примере, если запись блокирована, когда пользователь выполняет метод Edit, выводится сообщение. Если данные изменились, код регенерирует форму последними данными. Оператор recOrders.bookmark = recOrders.bookmark регенерирует текущую запись в наборе записей последними данными из базы данных. Обработка ошибок при выполнении метода Update В следующем примере обрабатываются ошибки, которые могут происходить при выполне¬ нии оператора Update: Private Sub cmdSave Click() Dim answer As Integer On Error GoTo HandleError rs.Fields("Category Name") = txtCategoryName.Text rs.Fields("Description") = txtDescription.Text rs.Update rs.Bookmark = rs.LastModified FillFields ButtonNavigateMode Exit Sub HandleError: Select Case Err.Number Case 3260 MsgBox " Текущая запись блокирована. " & "Попытайтесь сохранить еще раз позже или отмените изменения." Case 3197 answer = MsgBox ("Данные были изменены другим пользователем. " & " Перезаписать изменения? ", vbYesNo) If answer = vbYes Then Resume Else rs.Bookmark = rs.Bookmark ' Обновить запись изменениями ' других пользователей cmdCancel Click End If Case Else
76 Работа с внешними данными MsgBox Err.Number & ": " & Err.Description End Select End Sub Обработка ошибок при удалении записей другими пользователями Если другой пользователь удаляет запись из базы данных и набор записей типа dynaset полностью заполнен, указатель на запись не будет удален из набора. Однако удаленной записи больше нет в базе данных — ее нельзя просмотреть, и при попытке обращения к данным этой записи произойдет ошибка. Самый простой способ обработать эту ошибку — удалить вхождение, которое указывает на удаленную запись набора dynaset. В следующем фрагменте показано, как управлять ошибкой, сгенерированной попыткой обратиться к удаленной записи: Private Sub cmdMoveFirst Click() On Error GoTo Err Movefirst: retry MoveFirst: rs.MoveFirst txtLName.Text = rs("Last Name") ' Может произойти ошибка Exit Sub Err Movefirst: If Err.Number = 3167 Then ' Запись удалена, значит нужно ' удалить вхождение из dynaset rs.Delete Resume retry MoveFirst Else MsgBox Err.Description Exit Sub End If End Sub 4.3. Работа с внешними данными Visual Basic позволяет обращаться к нескольким базам данных индексно-последовательно- го представления (ISAM), таким, как dBASE, Paradox и Microsoft Visual FoxPro. Для таких баз данных Visual Basic обеспечивает драйверы ISAM. Visual Basic можно также использовать для обращений к стандартным файлам данных, например к текстовым файлам с разделителями. Примечание: Базы данных, для управления которыми используется процессор базы данных Microsoft Jet, рассматриваются как внутренние базы данных Visual Basic. В этом разделе описывается, как обратиться с помощью Visual Basic к внешним данным, включая базы данных ISAM и стандартные файлы данных. 4.3.1. Способы доступа кданным К данным во внешней базе данных можно обратиться либо присоединяя внешнюю базу данных, либо открывая ее непосредственно.
Гпава 4. Расширенные возможности программирования доступа 77 Присоединение таблицы базы данных Microsoft Jet Когда внешняя база данных присоединена к базе данных Microsoft Jet, данные таблицы остаются во внешней базе данных. Однако информация соединения и определение табли¬ цы сохраняются в базе данных Microsoft Jet. Таблицу можно использовать, как если бы это была любая другая таблица базы данных Microsoft Jet, за исключением того, что для присоединенной таблицы нельзя создавать набор записей типа table. Присоединение таблицы к базе данных Microsoft Jet можно выполнить с помощью простой процедуры в MicrosoftAccess. Присоединить таблицу можно также программным способом, используя метод CreateTableDefVisual Basic. Синтаксис метода Сгеа1еТаЫеОе^ледующий: Set o6beKm_TableDef= 6a3a_daHHb/x.CreateTableDef (имя, атрибуты, источник, соединение) Элементы метода: Элемент Описание o6beKm_TableDef Объектная переменная, представляющая создаваемый объект TableDef. базаданных Объектная переменная, представляющая объект Database, использу¬ емый для создания нового объекта TableDef. имя Необязательный. Значение String Variant, уникально именующее но¬ вый объект TableDef. атрибуты Необязательный. Константа или комбинация констант, представляю¬ щая одну или больше характеристик нового объекта TableDef. источник Необязательный. Значение String Variant, содержащее имя таблицы внешней базы данных — оригинального источника данных. Строка источник становится установкой свойства нового объекта TableDef. соединение Необязательный. Значение String Variant, содержащее информацию о внешней базе данных или присоединенной таблице. Примечание: Обычно обращение к данным в таблицах ODBC, присоединенных к базе данных Micro¬ soft Jet, выполняется более быстро, чем при их непосредственном открытии, так как информация соединения кэшируется при открытии базы данных Microsoft Jet. По этой причине, когда возможно, следует присоединять внешние таблицы вместо их непосредственного открытия. Открытие таблицы При непосредственном открытии внешней таблицы необходимо специфицировать инфор¬ мацию соединения, используя параметры метода OpenDatabase или свойство Connect элемента управления Data. В следующем фрагменте для открытия таблицы используются методы OpenDatabase и OpenRecordset: Sub OpenTable() Dim wspCurrent As Workspace Dim dbCurrent As Database Dim rstProducts As Recordset Set wspCurrent = CreateWorkspace("New Workspace", "Admin", "", dbUseJet) Set dbCurrent = wspCurrent.OpenDatabase("C:\VB\Nwind.mdb") Set rstProducts = dbCurrent.OpenRecordset("Products", dbOpenTable)
78 Работа с внешними данными rstProducts.MoveLast MsgBox "В таблице " & rstProducts.RecordCount & " записей" rstProducts.Close dbCurrent.Close wspCurrent.Close End Sub 4.3.2. Работа с базами данных ISAM Чтобы непосредственно открыть базуданных ISAM, нужно установить в качестве параметра базаданных метода OpenDatabase (или свойства DatabaseName элемента управления Data) имя папки, которая содержит таблицы ISAM. Для имени базы данных можно исполь¬ зовать также сетевой путь (например, \\server1\share1). В свойстве Connect объекта Database или элемента управления Data нужно указать тип открываемой базы данных. Список возможных значений свойства Connect для внешних баз данных ISAM приводится в следующей таблице: Тип базы данных Спецификатор Пример База данных Microsoft Jet [база_данных]; диск:\путь\имя_файла.гт^Ь dBASE III dBASE III; дискЛпуть dBASE IV dBASE IV; дискЛпуть dBASE 5 dBASE 5.0; дискЛпуть Paradox З.х Paradox 3.x; дискЛпуть Paradox 4.x Paradox 4.x; дискЛпуть Paradox 5.x Paradox 5.х;,диск:\путь, FoxPro 2.0 FoxPro 2.0; дискЛпуть FoxPro 2.5 FoxPro 2.5; дискЛпуть FoxPro 2.6 FoxPro 2.6; дискЛпуть Excel 3.0 Excel 3.0; диск:\путь\имя_файла.х1з Excel 4.0 Excel 4.0; диск:\путь\имя_файла.х1з Excel 5.0 or Excel 95 Excel 5.0; диск:\путь\ имя_файла.х1з Excel 97 Excel 97; диск:\путь\ имя_файла.х1э HTML Import HTML Import; диск:\путь\ имя_файла HTML Export HTML Export; дискЛпуть Text Text; дискЛпуть В следующем примере открывается база данных MicrosoftVisual FoxPro: Public Sub OpenFoxProTable() Dim dbFox As Database Dim recAccounts As Recordset Set dbFox = OpenDatabase _ ("\\FoxPro\Data\AP", False, False, _ "FoxPro 5 . 0;") Set recAccounts = dbFox.OpenRecordset("Accounts") End Sub
Гпава 4. Расширенные возможности программирования доступа 79 Чтобы присоединить базу данных ISAM к существующей базе данных .mdb, необходимо создать новый объект TableDefn установить свойства Connect и SourceTableName объекта TableDef. В следующем примере к базе данных Microsoft Jet присоединяется таблица Visual FoxPro. Можно либо создать новую базу данных Microsoft Jet, либо использовать существующую: Dim tbdAttach as TableDef Set dbDbl=OpenDatabase ("Dbl.mdb") Set tbdAttach = dbDbl.CreateTableDef ("Attached FoxPro Table") tbdAttach.Connect = "FoxPro 5.0;DATABASE=\\FoxPro\AP" tbdAttach.SourceTableName = "Accounts" dbDbl.TableDefs.Append tbdAttach После присоединения таблицы к базе данных Microsoft Jet ее можно открыть, используя следующий код: Set dbDbl = OpenDatabase ("Dbl.mdb") Set recAttach = dbDbl.OpenRecordset ("Attached FoxPro Table") 4.3.3. Работа с файлами данных Приложение Visual Basic, кроме информации базы данных, может работать с данными из стандартных файлов. При работе с информацией из стандартных файлов данных можно использовать следую¬ щие механизмы: • операторы файлового ввода-вывода — Open, Get, Put, Input #, Print #, Write #; • импорт данных в базу данных вручную. Импортировать текстовый файл в базу данных можно с помощью Microsoft Access. Microsoft Access поддерживает различные форматы файлов, такие, как файлы фиксированной длины, разграниченные запятой и так далее; • импорт данных в базу данных программным способом. Можно создать программный код, который будет читать текстовый файл и затем добавлять данные в базу данных. В следующем фрагменте показаны базовые шаги использования файлового ввода-вывода для чтения файла и сохранения информации в базе данных: Private Sub Commandl Click() Dim fhandle As Integer fhandle = FreeFile() Open "TextFilel" For Input As fhandle Do ' Прочитать файл одним из операторов ввода ' Сформировать строку SQL ' Выполнить оператор SQL INSERT Loop Until EOF(fhandle) End Sub 4.4. Работа с базами данных ODBC В DAO версии 3.5 представлена новая технология доступа клиент/сервер — ODBCDirect. С помощью этой технологии соединение с источником данных ODBC устанавливается с использованием механизмов объектов доступа к данным без привлечения процессора Microsoft Jet.
80 Работа с базами данных ODBC 4.4.1. Определение рабочей области ODBCDirect Первый шаг при использовании ODBCDirect состоит в определении типа рабочей области. Здесь имеется две возможности: установить умолчательный тип рабочей области либо определить рабочую область ODBCDirect. Установка умолчательной рабочей области Чтобы установить умолчательный тип рабочей области как ODBCDirect, следует использо¬ вать свойство DefaultType объекта DBEngine. Для этого свойства нужно определить значе¬ ние dbUseODBC. Этот тип рабочей области будет затем использоваться всякий раз при создании объекта Workspace. Эта установка предотвращает загрузку в память ядра базы данных Microsoft Jet (при условии, что до этого еще не была создана рабочая область базы данных Microsoft Jet). В следующем примере устанавливается умолчательный тип рабочей области ODBCDirect: DBEngine.DefaultType = dbUseODBC Создание конкретной рабочей области Умолчательную рабочую область можно переопределять, используя параметр тип метода CreateWorkspace. Например, ниже создается рабочая область ODBCDirect: Dim wspODBC As Workspace Set wspODBC = DBEngine.CreateWorkspace ("NewODBCWorkspace", "Admin", "", dbUseODBC) 4.4.2. Соединение с удаленным источником данных Соединение с удаленным источником данных подобно открытию базы данных Microsoft Jet. Сначала создается рабочая область (например, рабочая область ODBCDirect), а затем открывается источник данных. Для открытия удаленного источника данных создается объект Connection, точно также, как для открытия базы данных Microsoft Jet создается объект Database. После создания соеди¬ нения из удаленного источника данных можно отбирать информацию. Объявление соединения Объектная переменная типа Connection содержит информацию соединения. Открыть сое¬ динение можно с помощью оператора Set. В следующем примере соединение открывается в умолчательной рабочей области: Dim conNewConnection As Connection Set conNewConnection = OpenConnection ("New", dbDriverPrompt, false, "ODBC;DATABASE=pubs;UID=sa;PWD;DSN=SQLServer") Синтаксис метода OpenConnection: Set соединение = рабочая область.OpenConnection (имя, опции, только_для_чтения, строкасоединения) В следующей таблице описывается использование элементов метода OpenConnection: Элемент Описание соединение Объектная переменная типа Connection, ассоциированная с новым соединением.
Гпава 4. Расширенные возможности программирования доступа 81 Элемент Описание Рабочаяобласть Необязательный. Объектная переменная типа Workspace, указы¬ вающая на существующий объект Workspace, который будет со¬ держать новое соединение. Имя Любая строка, если зарегистрированное имя источника данных ODBC (DSN) специфицируется в параметре строка соединения. Это имя будет также свойством Name объекта Connection. Если допустимое имя DSN не включено в параметр строка соедине- ния, имя должно содержать допустимое ODBC DSN, которое будет также свойством Name объекта Connection. опции Устанавливает различные опции для соединения. Определяет, запросить ли и когда запросить пользователя установить соедине¬ ние и открыть ли соединение асинхронно. только_для_чтения True или False. Если True, модификации при работе в соединении не допускаются. Значение по умолчанию — False. строкасоединения Строка соединения ODBC. В следующей таблице перечисляются значения и использование параметра опции: Константа Результат dbDriverNoPrompt ODBC Driver Manager использует строку соединения, обеспечиваемую в параметре строка соединения. dbDriverPrompt ODBC Driver Manager выводит на экран окно диалога ODBC Data Sources, в котором представлена информация из параметра строка соединения. Строка соединения формируется из выбираемо¬ го пользователем DSN или, если пользователь не специфицирует DSN, будет использоваться умолчательное имя DSN. dbDriverComplete Если параметр строка соединения включает всю необходимую ин¬ формацию для установления соединения, ODBC Driver Manager ис¬ пользует строку в параметре строка соединения. Иначе он ведет себя так, как если бы была специфицирована умолчательная констан¬ та dbDriverPrompt. Это — значение по умолчанию. dbDriverComplete- Required Эта опция ведет себя подобно константе dbDriverComplete, за исклю¬ чением того, что драйвер ODBC деактивирует подсказки для любой информации, не требуемой для установки соединения. dbRunAsync Выполнение метода асинхронно. Эта константа может использоваться с любой другой константой опции. 4.4.3. Отбор удаленных данных Процедура получения удаленных данных с использованием ODBCDirect подобна отбору данных из базы данных Microsoft Jet. После установления с помощью ODBCDirect соедине¬ ния с базой данных ODBC методом OpenRecordset необходимо создать объект Recordset — точно так же, как это делается при получении записей из базы данных Microsoft Jet. В следующем примере создается рабочая область ODBCDirect и далее в ней создается набор записей для данных из базы данных SQL Server: Sub OpenODBCDirectRecordset() Dim wspODBC As Workspace Dim conODBC As Connection
82 Вопросы производительности Dim rstODBC As Recordset Set wspODBC = CreateWorkspace ("", "sa", "", dbUseODBC) Set conODBC = wspODBC.OpenConnection ("NewConncetion", dbDriverNoPrompt, False, "ODBC;DATABASE=pubs;UID=sa;PWD=;DSN=SQLServer") Set rstODBC = conODBC.OpenRecordset _ ("SELECT * FROM authors WHERE au_lname = 'Green'", _ dbOpenSnapshot, 0, dbReadOnly) rstODBC.MoveLast MsgBox " Этот удаленный набор записей содержит " & rstODBC.RecordCount & " записей." rstODBC.Close conODBC.Close wspODBC.Close End Sub Набор записей, отбираемый из удаленного источника данных может управляться тем же способом, что и наборы записей, создаваемые через DAO процессором Microsoft Jet. Дополнительную информацию см. в главе 3. Метод OpenRecordset в рабочей области ODBCDirect Ниже приводятся параметры метода OpenRecordset, доступные при использовании рабо¬ чей области ODBCDirect: Тип dbOpenDynamic Открывает набор записей типа dynamic, который можно использо¬ вать для добавления, изменения или удаления записей из исходной таблицы или таблиц базы данных. Набор типа dynamic может содер¬ жать поля из одной или больше таблиц базы данных. Опции dbRunAsync Выполняет асинхронный запрос. Примечание: Асинхронный запрос — тип запроса, при выполнении которо¬ го результаты запроса возвращаются немедленно, без перехода запроса в отложенное состояние. Это позволяет приложению продолжать парал¬ лельно другую обработку. Блокировки dbOptimisticValue Используется оптимистический параллелизм, основанный на значе¬ ниях записей. dbOptimisticBatch Активирует пакетное оптимистическое обновление. Примечание: Умолчательная рабочая область ODBCDirect — только для чтения. Чтобы дать возможность пользователям читать и записывать данные в рабочей области ODBCDirect, необхо¬ димо специфицировать тип блокировки dbOptimistic. 4.5. Вопросы производительности Структура и содержание кода доступа к данным приложения существенно влияет на произ¬ водительность. При создании приложения базы данных рекомендуется учитывать следую¬ щие рекомендации:
Гпава 4. Расширенные возможности программирования доступа 83 • знать организацию запрашиваемых данных. Некоторые запросы SQL более эффек¬ тивны, нежели другие. Например, сортировка по полю, которое содержит индекс, выпол¬ няется быстрее, чем по полю, для которого индекс не создан; • запрашивать только необходимые данные. Следует избегать создавать наборы запи¬ сей типа dynaset и snapshot для полной таблицы. В проекте приложения должны быть предусмотрены запросы к пользователю на ввод критериев поиска. В этом случае будут возвращаться ограниченные наборы записей и приложение будет работать быстрее; • вместо выбора всех столбцов в записи отбирать только необходимые столбцы. В следующем фрагменте создается набор записей, основанный на значении, введенном пользователем. Например, если пользователь вводит "А", создается набор записей всех служащих, фамилия которых начинается с "А": strSQL = "SELECT [LastName], [FirstName] FROM Employees " & _ "WHERE [LastName] Like " & _ "'" & txtName.text & "'" & "*" ' Критерий берется из поля формы Set recEmployees = dbDbl.OpenRecordset (strSQL,dbOpenDynaset) • использовать только требуемые функциональные возможности. Если модифици¬ ровать базу данных не предполагается, ее следует открывать только для чтения. Это повышает производительность, так как в этом случае процессор базы данных Microsoft Jet не должен управлять блокировками. Если не требуется изменять набор записей, его также нужно открывать только для чтения. Если предполагается только добавлять записи к набору, следует открывать его с опцией dbAppendOnly; • использование транзакций. Использование транзакций уменьшает интенсивность дис¬ кового доступа — ввод-вывод выполняется, в среднем, один раз на транзакцию, вместо одного раза на запись. Это может значительно повысить производительность приложе¬ ния; • использование сохраненных запросов. Обычно лучше создавать сохраненные запро¬ сы, нежели использовать операторы SQL в тексте. Сохраненный запрос прекомпилиру- ется, что исключает фазу компиляции в период выполнения. Кроме того, часто проще сопровождать запросы, которые сохранены в файле .mdb, а не описаны в тексте кода. Если возможно, следует использовать сохраненные запросы или операторы SQL для пакетных операций, таких, как модификация группы записей, вместо модификации запи¬ сей по одной методом Update; • присоединение таблиц. Рекомендуется, когда возможно, присоединять таблицы базы данных ODBC к локальной базе данных .mdb. Определение данных и информация соединения поддерживаются в файле .mdb, что, следовательно, повышает производи¬ тельность приложения.
84 Конфигурирование Crystal Reports Главаб. Созданиеотчетовспомощью Crystal Reports Конечной целью многих приложений является получение твердых копий документов, в том или ином виде отображающих данные. Это могут быть таблицы, формы данных, рабочие или стандартные документы — счета-фактуры, ведомости, инвентарные листы и т. д.. Получать такие документы позволяют специальные программы — генераторы отчетов. В том или ином виде функции генератора отчетов реализованы во всех инструментальных средствах, предназначенных для работы с данными. Имеется такой инструмент и в Visual Basic. В KOMnneKTecVisual Basic 5.0 поставляется процессор отчетов Crystal Reports 4.6 разработ¬ ки Seagate Software. Тот факт, что эта программа уже на протяжении нескольких версий включается в комплект поставки Microsoft Visual Basic (а также продуктов других производи¬ телей, например Borland Visual dBase и др.), говорит о ее несомненном качестве и широких возможностях. Crystal Reports для Visual Basic — полнофункциональная среда, позволяющая создавать отчеты многих стилей и любой сложности из данных локальных файлов .mdb и сетевых баз данных SQL/ODBC, с широкими возможностями форматирования представляемой инфор¬ мации — как вручную, так и программным способом в коде Visual Basic. Рис. 5.1. Рабочий экран Crystal Reports. 5.1. Конфигурирование Crystal Reports Crystal Reports позволяет настраивать многие из умолчательных установок программы, наилучшим образом конфигурируя ее под потребности разработчика. Эти установки воздей¬ ствуют на такие аспекты:
Гпава 5. Создание отчетов с помощью Crystal Reports 85 • рабочая среда; • способ выбора базы данных; • доступ SQL и ODBC; • параметры форматирования различных типов данных; • используемые шрифты для полей и текста. Для изменения умолчательных установок нужно выбрать команду Options в меню File. Открывается окно диалога File Options. Далее — открыть соответствующую вкладку с опциями, которые требуется изменить (см. примеры ниже). Рис. 5.2. Вкладка Layout окна диалога File Options. 5.1.1. Специфицированиеумолчательного каталога данных При конфигурировании Crystal Reports может потребоваться специфицировать умолчатель¬ ный каталог данных, который будет использоваться при создании новых отчетов, а также какие виды баз данныхдолжны быть представлены вокнедиалога Choose Database File при его открытии. Для этого: 1. Открыть вкладку Database в окне диалога File Options. 2. Для установки умолчательного каталога можно использовать один из следующих методов: ввести полный путь в окне Data Directory (например C:\Crw) или щелкнуть кнопку Browse и сделать выбор в окне Set Directory. 3. По завершении нажать OK, чтобы вернуться к вкладке Database.
86 Конфигурирование Crystal Reports 5.1.2. Специфицирование типов баз данных, представленных в окне диалога Choose Database File При специфицировании типов баз данных, которые должны быть перечислены в окне диалога Choose Database File (это окно открывается при выборе команды меню Database | Add Database to Report или при установке параметров нового отчета), можно ограничить количество типов файлов. В списке File Name будут представлены доступные базы данных только указанных типов. Для этого: 1. Открыть вкладку Database в окне диалога File Options. 2. В поле редактирования Database Selector ввести расширения имен файлов для типов баз данных, которые должны быть перечислены в окне диалога Choose Database File. 3. Нажать OK для возвращения к вкладке Database. Рис. 5.3. Вкладка Database окна диалога File Options. Примечание: При вводе типов имен файлов (*.db; *.dbf; *.ovd и т. д.) перед расширением необходимо поместить звездочку, а типы файлов разделять точкой с запятой. 5.1.3. Специфицирование умолчательного представления, используемого при предварительном просмотре отчета Открыв отчет в окне Preview, в случае необходимости можно изменить умолчательное отображение информации при предварительном просмотре. Для этого: 1. В окне диалога File Options открыть вкладку Layout (см. рис. 5.2).
Гпава 5. Создание отчетов с помощью Crystal Reports 87 2. В нижнем левом углу вкладки расположен раздел Preview Pages опций предварительного просмотра: Full Size (полный размер страницы), Fit Width (подогнать страницу по ширине окна) и Fit Page (подогнать страницу по окну). Выбрать одну из трех опций. 3. Нажать OK для возвращения к программе. После этого при просмотре в окне Preview отчет будет выводиться в выбранном режиме. 5.1.4. Специфицирование умолчательных шрифтов дпя разделов отчета 1. В окне диалога File Options открыть вкладку Font. 2. Во вкладке Font имеется две вертикальные колонки кнопок; одна колонка — для измене¬ ния умолчательных шрифтов полей разделов отчета (Default Field Fonts), и другая — для изменения умолчательных шрифтов текста (Default Text Fonts). Нажать кнопку соответствующего раздела, для которого требуется изменить умолчатель¬ ный шрифт. Открывается окно диалога Font. 3. Выбрать требуемый тип, стиль и размер шрифта, который нужно использовать в качестве умолчательного, и нажать ОК. Повторить процедуру для каждого нужного раздела. 4. Нажать OK снова, чтобы вернуться к программе. После этого в качестве умолчательных для разделов отчета будут использоваться уста¬ новленные шрифты. Рис. 5.4. Вкладка Font окна диалога File Options. 5.1.5. Специфицирование сервера SQL/ODBC как основного источника данных Процедура специфицирования сервера SQL/ODBC как основного источника данных пред¬ полагает выполнение четырех шагов в двух вкладках окна диалога File Options — New Report и SQL:
88 Конфигурирование Crystal Reports 1. Открыть вкладку New Report и в разделе Prefer to create new reports from: выбрать опцию SQL Tables. 2. Открыть вкладку SQL и в раскрывающемся списке ServerType выбрать соответствующий тип сервера. 3. Чтобы в дальнейшем при формировании нового отчета не открывалось окно диалога Server Type, нужно во вкладке SQL установить флажок Skip ServerType dialog. 4. Ввести имя сервера, имя базы данных и идентификатор пользователя в поля Server Name, Database и User ID соответственно. 5. Нажать OK для возвращения к программе. Примечание: Если после специфицирования сервера SQL/ODBC как основного источника данных снять флажок Use Report Gallery for new reports, при открытии нового отчета окно диалога Report Gallery будет пропущено и сразу открыто окно диалога SQL, где для регистрации на сервере нужно будет ввести правильный идентификатор пользователя и пароль. Рис. 5.5. Вкладка SQL окна диалога File Options. 5.1.6. Специфицирование шаблона отчета как основного источника данных 1. В окне диалога File Options открыть вкладку New Report. 2. В разделе Prefer to create new reports from: включить опцию Other Reports. Нажать ОК.
Гпава 5. Создание отчетов с помощью Crystal Reports 89 После этого при выборе команды New Report из меню File или при нажатии кнопки New Report на панели инструментов появляется окно диалога Create New Report, в котором представлены доступные шаблоны отчетов. Рис. 5.6. Окно диалога Create New Report с шаблонами отчетов. 5.1.7. Специфицирование умолчательных установок форматирования полей Умолчательные установки используются для форматирования полей при запуске нового отчета. 1. В окне диалога File Options открыть вкладку Fields. 2. Выбрать тип поля, для которого требуется изменить опции форматирования. Появляется окно диалога с опциями форматирования для данного типа поля. 3. Внести изменения кумолчательным установкам и нажать ОКдля возвращение ко вклад¬ ке Fields. Повторить процедуру для каждого типа поля. 4. Нажать OK для возвращения к программе. После этого установленные опции форматирования полей будут автоматически приме¬ няться при печати отчета (рис. 5.7). 5.2. Построение отчетов Ниже приводятся пошаговые инструкции по формированию отчетов с помощью Crystal Reports для Visual Basic. Вначале: 1. Открыть Crystal Reports.
90 Построение отчетов Рис. 5.7. Вкладка Fields окна диалога File Options и опции форматирования числовых полей. 2. Нажать кнопку New Report на панели инструментов. Открывается окно Create New Report с галереей шаблонов отчетов (см. рис. 5.6.). Щелкнуть одну из кнопок мастеров (в Crystal Reports они называются экспертами) для пошагового создания отчета выбранного типа. Или: Щелкнуть кнопку Another Report, чтобы использовать другой отчет как шаблон для созда¬ ния нового отчета. Или: Щелкнуть кнопку Custom для формирования пользовательского отчета. При этом галерея отчетов расширяется. 5.2.1. Выбор типа отчета В разделе Choose Report Type and Data Type нажать кнопку соответствующего типа отчета: • выбрать Custom Report для создания стандартного отчета типа строка/столбец или в формате блока данных;
Гпава 5. Создание отчетов с помощью Crystal Reports 91 • выбрать Custom Cross-Tab для создания перекрестного отчета в виде сводной таблицы, в которой могут выводиться итоговые данные по указанным столбцам. Перекрестные отчеты предоставляют информацию в наглядном виде и полезны при проведении быст¬ рых сравнений или выявления тенденций; • выбрать тип Custom Mail Label для создания почтовых ярлыков или элементов типа надписи. 5.2.2. Выбор источника данных В разделе типов данных можно выбрать источник данных, который будет использоваться для создания отчета: • выбрать Data File для подключения одной или больше таблиц базы данных. Появляется окно диалога Choose Database File, в котором можно выбрать базу данных — источник данных для отчета; • если выбрать SQL/ODBC, из числа установленных можно выбрать любой источник дан¬ ных из широкого разнообразия поддерживаемых Crystal Reports (их драйверы должны быть зарегистрированы на машине). Появляется окно диалога Log On Server, в котором нужно зарегистрироваться на сервере, после чего для использования в отчете можно будет выбрать требуемые таблицы SQL. Рис. 5.8. Окно регистрации копии пакета Crystal Reports. Видны поддерживаемые источники данных и инструментальные средства разработки. 5.2.3. Связывание таблиц базы данных Если выбрано две или больше таблиц базы данных, их необходимо связать (если связь декларативно не определена при создании базы данных). Связывание таблиц базы данных
92 Построение отчетов выполняется с целью установления отношений записей одной таблицы с записями другой. Поле, используемое для связывания, должно быть общим для обеих таблиц. При выборе нескольких таблиц открывается окно мастера Visual Linking Expert (Шаг 2 мастера Create Report Expert), в котором можно связать таблицы базы данных вручную или автоматически. Рис. 5.9. Вкладка мастера Visual Linking Expert. Для связывания вручную: 1. Выбрать поле в таблице, которое требуется связать с полем второй таблицы. 2. Перенести мышью поле от первой таблицы ко второй. Если связь возможна, появится линия связи, указывающая на успешное установление связи. 3. Чтобы отредактировать связь, нужно выделить линию связи и щелкнуть кнопку Options. Появляется окно диалога Link Options, в котором можно провести требуемые изменения. Для автоматического связывания нужно нажать кнопку Smart Linking. Функция Smart Linking создаст логические связи между таблицами в отчете автоматически. Если установление связи невозможно, будет выведено соответствующее сообщение. 5.2.4. Режим Design В режиме Design открывается окно конструктора, в котором располагается заготовка отчета с пустыми разделами Title, Page Header, Details, Page Footer и Summary. В ходе создания отчета в каждый из этих разделов вставляются и форматируются соответствующие элемен¬ ты компоновки.
Гпава 5. Создание отчетов с помощью Crystal Reports 93 Рис. 5.10. Разделы отчета. Для каждого раздела отчета имеются свойственные ему характеристики печати: • раздел Title (заголовок отчета) печатается один раз в начале отчета; • раздел Page Header (заголовок страницы) печатается в начале каждой страницы; • раздел Details (данные отчета) печатается один раз для каждой записи; • раздел Page Footer (нижний колонтитул страницы) печатается в конце каждой страницы; • раздел Summary (резюме отчета) печатается один раз в конце отчета. 5.2.5. Выбор полей для отображения в отчете Окно диалога Insert Database Field (см. рис. 5.1) появляется на экране при открытии нового отчета. Оно доступно также через команду меню Insert | Database Field. В этом окне выводится список полей и таблиц текущей базы данных, доступных для использования в отчете. Для ускорения ввода нескольких полей окно остается на экране, пока разработчик не нажмет кнопку Done. Для вставки полей: Выбрать поле (поля), данные которого требуется отразить в отчете. Для этого можно: • выбрать одно поле, щелкнуть кнопку lnsert и затем поместить поле в отчет; • выбрать одно поле и перенести его мышью на отчет; • использовать комбинацию <ЗЫА+щелчок> для выбора непрерывного интервала полей или комбинацию <СМ+щелчок> для выбора несоседних полей из списка и перенести их на отчет.
94 Построение отчетов Примечание: При размещении нескольких полей они будут располагаться в отчете в том порядке, в котором они перечислены в окне диалога Insert Database Field. Crystal Reports отмечает позицию каждого поля прямоугольной рамкой. Символы в рамке указывают на тип поля: текстовое (XXX...), число (555 ...), валюта ($555 ...), дата (12/31/99) или логическое (Boolean) (T/F). Число символов в рамке определяет число символов, допустимое для поля в базе данных. Вид полей можно изменить, выбрав команду Options из меню File и установив флажок Show Field Names во вкладке Layout окна диалога File Options (см. рис. 5.2). Каждое поле после этого вместо соответствующих символов будет обозначено именем. Crystal Reports автоматически поместит заголовки для каждого поля в разделе Page Header непосредственно выше соответствующего поля. Эту опцию можно деактивировать, сняв флажок Insert Detail Field Titles во вкладке Layout окна диалога File Options. 5.2.6. Перемещение, изменение размера, форматирование и удаление полей 1. Для перемещения, изменения размера, форматирования, добавления окантовки и цвета, удаления или вставки для поля промежуточной суммы или общего итога его сначала необходимо выбрать щелчком мыши. При выборе поля справа и слева от него появляют¬ ся черные маркеры. Примечание: Для одновременного выбора нескольких полей можно использовать метод <5^й+щелчок> или в меню Edit выбрать команду Select Fields. Команда Select Fields активирует курсор с перекрестием, которым вокруг нескольких полей можно обозначить прямоугольную область выбора. 2. После того как поле выбрано, необходимо сообщить Crystal Reports, что с этим полем делать дальше. Для перемещения поля — перенести его мышью в требуемую позицию. Для изменения размера поля — передвинуть правый или левый маркер, пока поле не приобретет требуемый размер. Для форматирования поля (выравнивание, представления числа, валюты, даты и т. д.) — щелкнуть поле правой кнопкой мыши и выбрать команду Change Format из контекстного меню. Соответственно типу данного выбранного поля появляется окно диалога Format, в котором можно изменить настройки формата. Для установки окантовок, фона заполнения и тени — щелкнуть поле правой кнопкой мыши и выбрать Change Border and Colors из контекстного меню (рис. 5.11). Появляется окно диалога Change Border and Colors, в котором можно установить требуемые выборы. Для изменения шрифта — щелкнуть поле правой кнопкой мыши и выбрать из контекст¬ ного меню команду Change Font. Провести необходимые изменения в окне диалога Font. Для удаления выбранного поля — нажать клавишу <Delete>. Примечание: При щелчке на поле правой кнопкой мыши за одну операцию выбирается это поле и выводится контекстное меню. Примечание: Многие из опций установки шрифта и форматирования также доступны через кнопки в панели форматирования внизу окна Crystal Reports. 5.2.7. Сортировка данных отчета Сортировка означает порядок вывода значений. Информация в телефонном справочнике, например, сортирована в алфавитном порядке по фамилиям абонентов, что позволяет быстро найти нужную информацию.
Гпава 5. Создание отчетов с помощью Crystal Reports 95 Рис. 5.11. Контекстное меню для работы с полями. При сортировке данных в Crystal Reports программа предлагает пользователю выбрать два параметра: поле, по которому требуется выполнить сортировку, и направление сортировки (Ascending (по возрастанию), означающее от наименьшего к наибольшему, от 1 до 9, сначала False, потом True; или Descending (по убыванию)). В качестве поля сортировки можно использовать любое поле. При выборе поля сортировки метод сортирования определяется установками "Язык и стандарты" панели управления Windows. Например, символьные значения сортируются так, что пробелы имеют самое низкое кодо¬ вое значение, затем идут знаки пунктуации, затем символы чисел, затем латинские символы верхнего регистра, латинские символы нижнего регистра и, наконец, символы кириллицы верхнего и нижнего регистра. Поля типа Currency сортируются в порядке эквивалентных чисел. Числовые поля сортируются в числовом порядке. Поля типа Date сортируются в хронологическом порядке. Crystal Reports позволяет выполнять сортировку по одному или нескольким полям. При сортировке по нескольким полям Crystal Reports вначале сортирует записи, основываясь на значениях в первом выбранном поле, располагая их по возрастанию или по убыванию значений этого поля. Когда две или больше записи имеют одинаковое значение поля в первом поле сортировки, Crystal Reports сортирует эти (и только эти) записи, основываясь на значениях второго поля сортировки. Например, при сортировке фамилии и имени (в порядке возрастания) "Семенов, Николай" было бы возвращено раньше, чем " Семенов, Петр", но после "Johnson, Nick". Для задания параметров сортировки: 1. Нажать кнопку Sort Records на панели инструментов. Откроется окно диалога Record Sort Order. 2. Из списка Report Fields выбрать поле (поля) сортировки. 3. Нажать кнопку Add. Выбранное поле будет добавлено к списку полей Sort Fields. 4. Выбрав on4HioAscending или Descending, специфицировать направление сортировки. По завершении нажать ОК.
96 Построение отчетов Рис. 5.12. Окно диалога Record Sort Order. 5.2.8. Группирование данных отчета Crystal Reports позволяет группировать данные в отчете. Группа — набор записей, которые некоторым образом связаны друг другом. Например, в списке клиентов группа могла бы содержать всех клиентов, живущих в одном городе. В отчете по продажам группа может содержать заказы, размещенные одним клиентом, или все заказы, оформленные одним коммерческим представителем. Crystal Reports предоставляет большую гибкость в группировании данных. Он также дает возможность создавать ряд разных видов значений группы. Значение группы — значение, сгенерированное как результат оценки или вычисления, выполняемого с данными из отдельной группы записей. Промежуточная сумма — один из видов значения группы, это сумма всех значений одного поля по всем записям в группе. В коммерческом отчете, например, если требуется получить итог продаж одного коммерче¬ ского агента, Crystal Reports собирает все записи, которые принадлежат этому коммерче¬ скому агенту, и суммирует объемы продаж из всех записей. Значения группы — важные инструменты для создания мощных отчетов. Crystal Reports позволяет, в частности, вывести среднее значение по группе записей, подсчитать количест¬ во значений в группе, вычислить стандартное отклонение или разброс значений, опреде¬ лить самое высокое и самое низкое значение в группе. В то время как в отчете может отображаться много полей данных, обычно имеется только одно поле, по которому требуется выполнить группирование. В коммерческом отчете, например, это, вероятнее всего, будет поле, содержащее объемы продаж и т. д. Порядок организации группирований: 1. При создании групп в отчете сначала нужно определиться с полем, по которому будет выполняться группирование. 2. В меню lnsert выбрать команду Group Section. Открывается окно диалога Insert Group Section. 3. В окне диалога Insert Group Section выбрать поле группирования и порядок сортировки значений в группе.
Гпава 5. Создание отчетов с помощью Crystal Reports 97 После того как эти простые выборы сделаны, Crystal Reports соответствующим образом сгруппирует данные в отчете. Создание пользовательских группирований В большинстве случаев сортировка и группирование данных основываются на значениях полей отчета. Например, если имеется список клиентов и требуется отсортировать и сгруп¬ пировать его по городам, Crystal Reports вначале сортирует список по городам и затем разбивает список клиентов на группы при изменении значения в поле Город. Иногда, однако, может потребоваться сгруппировать данные, основываясь на значениях, не входящих в число полей отчета: • отчет может не содержать поле, по которому требуется выполнить группирование. На¬ пример, отчет содержит поле Клиент и поле Город, но не содержит поля Страна, по которому требуется получить группы; • отчет может содержать поле, по которому нужно выполнить группирование, но для каждой группы требуется выбрать определенные значения или интервалы значений. Например, нужно получить одну группу с записями, где сумма продаж меньше некоторого значения, вторую группу, где сумма продаж больше некоторого значения, и заключитель¬ ную группу, в которой сумма продаж располагается между двумя значениями. Для решения таких проблем Crystal Reports позволяет применить специфицированный порядок группирования. Специфицированный порядок группирования дает возможность создать требуемые группы и конкретизировать, какие записи должна содержать каждая группа. Единственное реальное ограничение здесь — запись может принадлежать только одной группе. Создать специфицированное группирование можно, выбрав в окне вставки группы или промежуточной суммы в качестве порядка сортировки опцию in specified order (рис. 5.13). Затем в окне Define Named Group параметры группы и порядок отбора записей конкретизи¬ руются. 5.2.9. Получение итогов и промежуточных сумм Когда Crystal Reports суммирует данные, он разбивает их на группы и затем выполняет специфицированную операцию со значениями каждой группы. Он делает это автоматиче¬ ски. Все, что должен сделать разработчик, — специфицировать: • поле, по которому требуется выполнить подсчет; • тип операции, которую нужно выполнить с данными поля; • поле, при изменении значения которого нужно начать новую группу; • порядоксортировки. Чтобы вставить промежуточную сумму (сумма по группе данных; выполняется только для числовых полей): 1. Щелкнуть правой кнопкой мыши поле и выбрать команду Insert Subtotal из контекстного меню. Открывается окно диалога Insert Subtotal. 2. Выбрать поле, по которому требуется инициировать подсчет новой промежуточной сум¬ мы при каждом изменении значения. 3. Специфицировать порядоксортировки: Ascending (возрастание) или Descending (убыва¬ ние). 4. Crystal Reports создает новые разделы Group Header и Group Footer и автоматически помещает промежуточную сумму в раздел Group Footer.
98 Построение отчетов Рис. 5.13. Окна Insert Subtotal и Define Named Group в режиме создания пользовательских (именованных) групп. Для вставки общего итога: 1. Для вставки в конце отчета общего итога (среднее по отчету, количество данных и т. д.) нужно щелкнуть поле правой кнопкой мыши и выбрать команду Insert Grand Total из контекстного меню. Открывается окно диалога Insert Grand Total. 2. Выбрать из списка требуемую операцию и нажать ОК. 3. Crystal Reports создает раздел Grand Total, в котором будет выводиться общий итог (рис. 5.14). Для вставки подсчетов: 1. Для вставки подсчета (количество значений, сумма, среднее, стандартное отклонение, раз¬ ница, минимум, максимум и т. д.) нужно щелкнуть поле правой кнопкой мыши и в контекстном меню выбрать команду Insert Summary. Открывается окно диалога Insert Summary. 2. Выбрать поле, при изменении значения которого требуется начинать новый подсчет. 3. Специфицировать порядок сортировки: Ascending (возрастание) или Descending (убывание). 4. Crystal Reports создает разделы Group Header и Group Footer и автоматически помещает подсчет в раздел Group Footer.
Гпава 5. Создание отчетов с помощью Crystal Reports 99 Рис. 5.14. Создание разделов Group Header, Group Footer и Grand Total при вставке промежуточной суммы и общего итога (см. строку состояния). 5.2.10. Выборзаписей При выборе поля для отчета Crystal Reports, по умолчанию, печатает значения поля из каждой записи активной таблицы. В ряде (если не в большинстве) случаев, однако, требу¬ ется включать в отчет не все значения, но только некоторое подмножество этих значений. Например, из общего количества записей активной таблицы базы данных нужно получить записи только для определенной группы клиентов или для определенного интервала номе¬ ров счетов. В Crystal Reports это реализуется весьма просто. Для этого при выборе записи необходимо дать указание Crystal Reports базировать отчет только на тех записях, которые отвечают некоторым установленным условиям. А условия эти устанавливаются, исходя из того, какую информацию требуется получить в законченном отчете. Процедуру специфицирования записей, которые требуется включить в отчет, помогает выполнить мастер Select Records Expert. При этом нужно просто выбрать поле, на котором требуется базировать отбор записей, и затем в окне мастера установить критерии выбора. Если нужно установить дополнительные критерии или если требуется базировать отбор записей на дополнительных полях, мастер обеспечивает для этого соответствующие инст¬ рументальные средства. Начать работу с Select Records Expert можно одним из двух способов: • выбрать поле в отчете и щелкнуть кнопку Select Records на панели инструментов либо выбрать команду меню Report | Select Records Expert. Программа открывает окно диалога Select Records Expert, готовое для установки условий для выбранного поля; • не выбирая поле отчета, щелкнуть кнопку Select Records на панели инструментов либо выбрать команду меню Report | Select Records Expert. Появляется окно диалога Choose Field. Выбрать поле, на котором требуется базировать отбор записей и нажать ОК. Открывается окно диалога Select Records Expert.
100 Построение отчетов Далее, для создания простых критериев: 1. Используя раскрывающиеся списки, ввести критерии для значений выбранного поля. 2. Если отбор записей требуется базировать на более чем одном поле, щелкнуть вкладку New и выбрать следующее поле из окна диалога Choose Field. 3. По завершении нажать OK, чтобы вернуться к отчету. Crystal Reports выполнит отбор записей в соответствии с установленными критериями. Рис. 5.15. Окно диалога Select Records Expert. Нажав кнопку Formula Editor, в окне Edit Formula созданный критерий можно отредактиро¬ вать или добавить более сложные условия. Относительно работы с формулами см. ниже раздел "Работа с формулами". TopN В некоторых случаях в отчете требуется показывать только группу из нескольких верхних или нижних значений полей: самые умелые коммерческие агенты с наибольшими объемами продаж; самые "уважаемые" клиенты, размещающие наиболее крупные заказы; наименее ходовые товары и т. д. Так как этот вид выбора групп весьма популярен, Crystal Reports включает средство, позволяющее это легко сделать. Отбор группы Тор N (или Bottom N) устанавливается выбором команды Top N/Sort Group Expert в меню Report. В окне Top N/Sort Group Expert можно специфицировать вывод группы верхних или нижних значений, а также количество (N) этих значений. При выборе группы Тор N имеется один аспект, который заключается в том, что требуется решить, что делать с записями из других групп, которые не удовлетворяют установленным критериям Тор N или Bottom N. Эти записи можно либо полностью удалить из отчета, либо свести их в отдельную группу, установив для нее некоторое имя. Программа позволяет сделать и то и другое переключением флажка include Others, with the name (см. рис. 5.16).
Гпава 5. Создание отчетов с помощью Crystal Reports 101 Рис. 5.16. Окно диалога Top N/Sort Group Expert. 5.2.11. Добавление графика/диаграммы Crystal Reports позволяет включать в отчет сложные, красочные диаграммы и графики. При добавлении диаграммы в отчете выводится графическое представление информации под¬ счета и промежуточной суммы. Следовательно, прежде чем можно будетдобавить график, необходимо иметь в отчете, по крайней мере, одну группу и одну промежуточную сумму. Например, если имеется отчет по продажам, сгруппированный по коммерческим агентам с промежуточной суммой объемов по каждому агенту, можно быстро создать диаграмму, которая будет отражать эти цифры графически. Добавление и изменение графиков в Crystal Reports выполняется с использованием масте¬ ра Graph/Chart Expert. Мастер пошагово проводит разработчика через процедуру создания диаграммы. Чтобы обратиться к мастеру Graph/Chart Expert, нужно нажать кнопку Insert Chart на панели инструментов или выбрать команду меню Insert | Graph/Chart Expert. В окне мастера имеется несколько вкладок-шагов, позволяющих выбрать тип диаграммы и выполнить ее настройку (рис. 5.17): • вкладка Type. Здесь можно выбрать один из доступных типов диаграмм. Для выбора нужно щелкнуть соответствующую кнопку и перейти к следующему шагу; • вкладка Data. В этой вкладке можно выбрать: какие данные требуется представить, как часто выводить диаграмму (зависит от того, где она будет располагаться) и что требуется показать в диаграмме. В раскрывающемся списке выводятся все расчеты и промежуточ¬ ные суммы отчета; из них нужно выбрать элемент, на котором будет базироваться диаграмма; • вкладка Text. Позволяет ввести в соответствующие поля надписи для диаграммы — заголовки, сноски, заголовки осей. Crystal Reports использует надписи только соответст¬ венно выбранному типу диаграммы. Ненужные надписи будут игнорироваться; • вкладка Options. Позволяет поместить на диаграмме легенду, ввести максимальное или минимальное ограничение значений данных и ряд других опций.
102 Построение отчетов Рис. 5.17. Типы диаграмм Crystal Reports. Рис. 5.18. 3-D гистограмма в разделе заголовка отчета (режим Design).
Гпава 5. Создание отчетов с помощью Crystal Reports 103 5.2.12. Объекты OLE Crystal Reports — приложение-контейнер OLE, которое позволяет помещать в отчет OLE- объекты. Для этого: 1. Выбрать команду Object в меню lnsert. Открывается стандартное окно Insert Object. 2. Вставить существующий объект, выбрав опцию Create from file и выбрав требуемый объект, или создать новый объект, выбрав опцию Create New и затем объектный тип. Запустится соответствующее приложение (например, Paint при выборе "Рисунок BMP), где можно создать объект. 3. Если требуется отредактировать объект, нужно просто дважды щелкнуть его — и запу¬ стится программа, в которой объект был создан (или подобное приложение, которое позволяет выполнить редактирование). 4. Изменить объект, сохранить его — и Crystal Reports автоматически модифицирует объект в отчете. 5.2.13. Добавление заголовка отчета 1. Для добавления заголовка к отчету нужно нажать кнопку Insert Text Field на панели инструментов или выбрать команду меню Insert | Text Field. Открывается окно диалога Edit Text Field. 2. Ввести требуемый заголовок в поле редактирования и по завершении нажать Accept. 3. Поместить созданное текстовое поле в требуемую позицию в разделе Title отчета. 5.2.14. Предварительный просмотротчета 1. Перейти в режим предварительного просмотра (Preview) можно в любое время, нажав кнопку Preview Report на панели инструментов либо щелкнув ярлык вкладки Preview. Открывается вкладка Preview с результатами отчета. 2. После этого можно либо настроить отчет во вкладке Preview, либо закрыть это окно и продолжать работать с отчетом в режиме Design. Функциональные возможности в обоих режимах одинаковы. 5.3. Работа с формулами Во многих случаях достаточным будет вывод в отчете данных в том виде, как они хранятся в полях таблиц базы данных. Например, чтобы подготовить форму заказа, нужно просто заполнить данными соответствующие поля отчета. Иногда, однако, в отчете требуется вывести данные, которых нет в полях базы данных. Такие значения можно получить, рассчитав их по формуле. Если требуется создать формулу для вычисления числовых значений, сравнения одного значения сдругим и выбора альтернативныхдействий по результатам сравнения, соедине¬ ния нескольких текстовых строк в одну строку и т. д., следует: 1. Нажать кнопку Insert Formula field на панели инструментов или выбрать команду меню Insert | Formula field. Открывается окно диалога Insert Formula. 2. Ввести имя для формулы и нажать ОК. Открывается окно Edit Formula, в котором можно создавать, тестировать и редактировать формулу. Примечание: Окно диалога Edit Formula также можно открыть, нажав кнопку Formula Editor в окне диалога Select Records Expert при установке критериев отбора записей для отчета (см. рис. 5.15). В этом случае создаваемая формула будет неименованной.
104 Работа с формулами 3. Ввести поля, операции и функции в поле Formula text, выбрав их двойным щелчком в соответствующих списках. Получить полную информацию относительно каждого доступ¬ ного элемента списков Function и Operator можно, нажав кнопку Help. Примечание: Каждая формула — текстовая строка, которую, вместо выбора компонентов из списков, можно впечатать непосредственно в поле Formula text. При двойном щелчке элемента списка Crystal Reports вводит элемент в формулу со скобками, пунктуацией и другими элемента¬ ми синтаксиса, требуемыми для правильной работы формулы. При вводе формулы вручную с клавиатуры эти элементы синтаксиса придется вводить самостоятельно. Обычно более без¬ опасно и более быстро строить формулу, выбирая соответствующие элементы из списков. Примечание: Значения полей в окне диалога Browse Field Data (просмотр значений полей) пред¬ ставляют только подмножество доступных записей. 4. По завершении редактирования нажать кнопку Accept. Crystal Reports контролирует синтаксис формулы и, если ошибок нет, закрывает окно Edit Formula. Если в синтаксисе имеется ошибка — например, не указано имя файла, пропущена разделяющая точка или поле не заключено в фигурные скобки, Crystal Reports генерирует сообщение Error компилятора формул, детализирующее ошибку. 5. Поместить поле формулы в требуемую позицию в отчете. Рис. 5.19. Окно диалога Edit Formula. Разделы окна Edit Formula: • в окне Fields перечислены все поля, которые можно использовать как параметры формулы; • в окне Functions представлено множество функций Crystal Reports. Эти функции — прекомпилированные процедуры, возвращающиезначения. Вседоступныефункции при¬ ведены в этом окне с соответствующими параметрами и упорядочены по их назначению; • в окне Operators перечислены операции ("глаголы действия"), которые можно использо¬ вать в формулах для объединения ее компонентов. Некоторые из типичных применений формул: Создание в отчете вычисляемых полей: {Orders.UnitPrice}*.8 5 // Вычисляет цену со скидкой 15%.
Гпава 5. Создание отчетов с помощью Crystal Reports 105 Форматирование текста в отчете: // Функция UpperCase переводит все значения в поле CustomerName в // верхний регистр литер. UpperCase ({customer.CustomerName}) Отбор части или частей текстовой строки: {customer.CustomerName} [1] // Извлекает первую литеру имени клиента Отбор части даты: Month({orders.OrderDate}) //Определяет, в каком месяце был размещен заказ Эти примеры демонстрируют лишь некоторые возможности формул. С помощью формул Crystal Reports можно выполнять очень сложные манипуляции с данными. 5.3.1. Приемы работы с формулами Точно так же, как в формулы вводятся поля, в формулы можно вводить другие формулы. Crystal Reports выполняет вычисления во вложенной формуле и затем использует значение, возвращенное этой формулой, как если бы это было любое другое значение. Например, формула: 1*(2+4*6/3-7*12-8) +2*(2+4*6/3-7* 12-8) +3*(2+4*6/3-7*12-8) +4*(2+4*6/3-7*12-8)= -820 включает выражение (2+4*6/3-7*12-8), повторяемое несколько раз. Если для повторяемого выражения создать формулу (@F = (2+4*6/3-7*12-8)) и затем обра¬ щаться к этой формуле вместо ввода непосредственно длинного выражения получим тот же результат: 1 *{@F}+2*{@ F}+3*{@F}+4*{@ F} = -820 Каждый раз, когда Crystal Reports видит формулу @F, он выполняет вычисление @F и возвращает значение -82 так же, как и выражение (2+4*6/3-7*12-8), лежащее в основе формулы. Вставить в формулу другие формулы можно так же, как и другие поля: через окно Fields или вводя их в вручную. Примечание: Формула не может ссылаться сама на себя. 5.3.2. Значение поля группы Значение поля группы — значение, которое суммирует значения записей группы (промежу¬ точная сумма группы, среднее значение группы и т. д). Использование таких значений в формулах может быть весьма полезным. Типичное применение — выяснить процент от общего итога, который составляет группа. Вставить значение поля группы в формулы можно либо через окно Fields, либо непосредст¬ венно впечатав его в поле Formula text. Примечание: Из-за сложности синтаксиса некоторых полей групп рекомендуется их вводить выбором из окна Fields. 5.3.3. Комментарии формул Комментарии формулы — примечания, включаемые в формулу для документирования ее структуры и действия.
106 Работа с формулами Комментарии не печатаются в отчете и не воздействуют на формулу, но они видны и доступны в окне Edit Formula. Рекомендуется всегда включать комментарии со сложными формулами, особенно с теми, которые будут неоднократно использоваться. Комментарии вводятся непосредственно в поле Formula text. Комментарий может быть выше или ниже формулы, он может также следовать за формулой на той же строке. Примечание: Комментарию нужно предшествовать двумя знаками прямого слэша (/f). Знак коммен¬ тария может быть также выбран в списке Operators. Например, приемлемы следующие варианты ввода комментариев: // Это пример правильного ввода комментария. // Следует помнить, что при разбиении строки комментария. // следующая строка также должна начинаться со знака комментария. // Иначе Crystal Reports обработает строку комментария, как часть // формулы, и выдаст сообщение об ошибке. If {Orders.OrderAmount} in (100.00 to 250.00) Then .10 * {orders.OrderAmount} Else 0 // Это - также правильный ввод комментария. If {Orders.OrderAmount} > 10.00 Then "" // Этот вариант - также приемлем. Else "Заказ очень мал" 5.3.4. Синтаксис формул Crystal Reports требует, чтобы различные компоненты формулы вводились согласно опре¬ деленному набору правил, составляющих синтаксис формул. Синтаксис, подобно грамматике любого языка, имеет тенденцию к расширению и совершен¬ ствованию. Компоненты формулы должны вводиться определенным образом и в опреде¬ ленном порядке. Различные элементы синтаксиса (кавычки, скобки, круглые скобки и т. д.) используются программой для идентификации различных компонентов формулы. Поэтому очень важно придерживаться правил синтаксиса, с тем чтобы элементы формулы могли быть правильно распознаны компилятором и формула работала так, как это планировалось. Различные компоненты формул и их синтаксиса перечислены ниже: Текст Синтаксис: "Текст" или 'Текст' (Заключается в ’одинарные’ или "двойные кавычки") При использовании текста в формулах он должен быть заключен в одинарные или двойные кавычки. Любой текст внутри этих кавычек будет напечатан в отчете в поле формулы. Числа Синтаксис: 23134.567 Числа, вводимые в формулы, не могут содержать в качестве разделителей разрядов запятые, а также символы валюты.
Гпава 5. Создание отчетов с помощью Crystal Reports 107 Поля данных Синтаксис: {Файл.Поле} При использовании в формулах полей они должны быть заключены в фигурные скобки {} с именем таблицы, указывающим, какой таблице базы данных принадлежит поле. Имя поля отделяется точкой. Например: {Customer.Region} идентифицирует поле Region из таблицы Customer. Операции Синтаксис: 1+1 При использовании операций в формулах в нужном месте просто вводится знакоперации. До и после знака операции можно вводить пробел, однако это не обязательно (то есть 1 + 1). Функции Синтаксис: Имя_функции(параметры) При использовании функций в формулах вводится имя функции и необходимые параметры в круглых скобках. Например, функция Sum(x) требует в качестве параметра поля или формулы. Например: Average({Order.Amount}) Эта формула вернет среднее из всех значений в поле Amount. Скобки в формулах При написании формулы в Crystal Reports используется три разныхтипа скобок. Каждый тип имеет определенное назначение и может использоваться только с некоторыми элементами формулы: {} — фигурные скобки помещаются вокруг полей формулы и базы данных: {Customer.Region}, {@sum} [ ] — квадратные скобки вводятся при использовании операции индекса массива: {Customer.CustomerName} [1] () — в круглые скобки заключаются параметры функции: Round(x), Abs(x) Примечание: Круглые скобки могут также использоваться для управления порядком оценки элемен¬ тов формулы. 5.3.5. Порядок вычислений в формулах Если создается формула, которая содержит разные виды операций, важно учитывать порядок, в котором Crystal Reports оценивает отдельные части формулы. Этот порядок называется порядком старшинства. Простой порядок старшинства соответствует базовым математическим правилам старшин¬ ства: сначала, слева направо, выполняется умножение и деление, затем — сложение и вычитание. Например: 5 + 10*3 = 35 Сначала выполняется умножение 10 * 3, затем 30 прибавляется к 5.
108 Работа с формулами Однако, если требуется вначале 5 прибавить к 10 и затем умножить сумму на 3, необходимо изменить порядок выполнения операций вводом круглых скобок. Выражение будет выгля¬ деть следующим образом: (5 + 10) * 3 = 45 Ясно, что круглые скобки имеют более высокий приоритет, чем операции сложения, вычи¬ тания, умножения и деления. Они переопределяют порядок вычислений. Примечание: Когда формула содержит другие формулы, например: @Summa * 107.5%, программа сначала оценивает внедренную формулу, @Summa, следуя правилам порядка старшин¬ ства, и затем оценивает остальную часть основной формулы. 5.3.6. Удаление формул из отчета При создании формулы и вводе ее в отчет Crystal Reports сохраняет спецификацию форму¬ лы, используя назначенное ей имя, и помещает рабочую копию этой формулы в позицию, указанную для нее в отчете. Копия работы — любой экземпляр формулы в отчете. Для удаления формулы необходимо удалить как спецификацию, так и все рабочие копии формулы, причем нельзя удалить спецификацию, не удалив все рабочие копии формулы. Чтобы удалить отдельную рабочую копию формулы: 1. Выбратькопиюформулывотчете. 2. Нажать клавишу <Delete> или <Del> на клавиатуре компьютера. Примечание: Даже после удаления всех рабочих копий формулы из отчета спецификация фор¬ мулы остается нетронутой. Спецификации формул представлены в окне диалога Insert Formula и доступны для немедленного использования, когда формулу нужно снова ввести в отчет. Чтобы удалить спецификацию формулы: 1. После удаления всех рабочих копий формулы нажать кнопку Insert Formula на панели инструментов. Появляется окно диалога Insert Formula. 2. Выбрать спецификацию формулы, которую требуется удалить из списка Formula Name. Crystal Reports активирует кнопку Delete. 3. Нажать кнопку Delete; Crystal Reports удаляет спецификацию формулы. Примечание: Если формула используется в другой формуле, программа все равно удалит специ¬ фикацию. Примечание: Если удалены не все рабочие копии выбранной формулы, программа выводит на экран сообщение о невозможности удалить спецификацию формулы. 5.3.7. Копирование формул из оперативной справки Windows позволяет копировать текст из тем оперативной справки в буфер обмена. Затем этот текст можно вставлять везде, где необходимо. Так какформулы, создаваемые с использова¬ нием окна Edit Formula, — простой текст, можно сэкономить время, копируя полезные формулы непосредственно в Edit Formula и затем изменяя их под свои потребности. Чтобы скопировать формулу из оперативной справки: 1. При активном окне Edit Formula любым из стандартных способов (меню Help, функцио¬ нальная клавиша F1 и т. д.) вызвать справку Crystal Reports. 2. Перейти ко вкладке Search (Поиск), чтобы найти тему, которая содержит представляю¬ щую интерес формулу. Открыть тему.
Гпава 5. Создание отчетов с помощью Crystal Reports 109 3. Пролистать текст темы и найти формулу, которую требуется скопировать. 4. Выделить формулу в тексте и выбрать команду Edit | Copy. Windows помещает копию выбранного текста в буфер обмена. 5. В окне Edit Formula установить курсор в позицию вставки и нажать Ctrl-V, чтобы вставить текст формулы из буфера обмена. 6. Отредактировать формулу. 5.3.8. Функции Функции — встроенные процедуры или подпрограммы, используемые для выполнения вычислений или манипулирования данными. При специфицировании функции Crystal Re¬ ports выполняет набор встроенных в функциюопераций; при этом специфицировать каждую операцию отдельно нет необходимости. Таким образом, функция существенно облегчает создание формул. В Crystal Reports имеется свыше ста полезных функций. Все они доступ¬ ны в списке Functions окна диалога Edit Formula, где они представлены по категориям: арифметические, строковые, функции дат, массивов и прочие. 5.3.9. Операции Операции — специальные символы или слова, которые описывают операцию или действие, выполняемое с одним или более значениями. Операции используются в формулах. Crystal Reports читает операции в формуле и выполняет специфицированные действия. Операции доступны в списке Operators окна диалога Edit Formula, где они представлены по категориям: арифметические, преобразования, сравнения, строковые, интервалы, логиче¬ ские, массивы, шаблоны и прочие. 5.3.10. Переменные Переменная — именованная область памяти, выделяемая для хранения некоторого значе¬ ния. Переменная характеризуется типом данного, который определяет характер данных, которые могут храниться в переменной. В Crystal Reports переменные могут быть одного из пяти типов данных: NumberVar (число¬ вой), CurrencyVar (денежный), StringVar (строковый), BooleanVar (логический), DateVar (дата). Объявление переменных Прежде чем переменная может быть использована, ее нужно объявить, то есть сделать известной компилятору. Синтаксис объявлений: NumberVar x; CurrencyVar x; StringVar x; BooleanVar x; DateVar x; Примеры: Объявление переменной Amount, которая может содержать любое целое или дробное числовое значение: NumberVar Amount;
110 Элемент управления Crystal Объявление переменной YesNo, которая может возвращать значение FALSE или TRUE: BooleanVar YesNo; Объявление переменной LastName, которая может содержать строковое значение: // Здесь выполняется также присваивание значения переменной StringVar LastName := "Воронков"; 5.4. Элемент управления Crystal Кроме выполнения функций мощного автономного процессора отчетов, Crystal Reports обеспечивает модуль отчетов, с которым можно устанавливать связь из приложения Visual Basic. Разработчик, использующий Visual Basic 5.0, может добавлять к приложению слож¬ ные возможности генерации и печати отчетов, не затрачивая времени на написание собст¬ венного программного кода. Процессор Crystal Report Engine — библиотека динамической компоновки, которая позволя¬ ет в приложении обращаться к тем же функциям формирования отчетов, которые доступны в Crystal Reports. Доступ к Report Engine из приложения Visual Basic осуществляется через элемент управле¬ ния Crystal. Когда к проекту подключен элемент управления Crystal, при компиляции прило¬ жение связывается с Report Engine. Раздел приложения, связанный с отчетом, может быть простым и заключаться в создании единственного отчета, который передается на принтер или окно печати без всяких опций, доступных пользователю. Задание это может быть также весьма сложным и может позволять пользователю изменять параметры выбора, сортиров¬ ки, группирования записей и принимать решение, куда должен быть направлен результиру¬ ющий отчет. Report Engine обеспечивает удобное дополнение — через элемент управления Crystal — к существующему проекту приложения Visual Basic. Введя лишь несколько строк программ¬ ного кода, можно получить мощный инструмент, который иначе потребовал бы недель работы. 5.4.1. Подготовка к использованию элемента управления Crystal Приступая к использованию элемента управления Crystal, следует помнить, что Report Engine печатает существующие отчеты. С помощью Report Engine нельзя создавать новые файлы отчета. Отчеты должны быть созданы в Crystal Reports. Процедура использования любого проекта Visual Basic, который включает Crystal Report Engine, требует трех шагов: • создать отчеты, с которыми будут работать пользователи. Создание отчетов, с которыми будет работать приложение, идентично созданию отчетов для автономного использова¬ ния; здесь нет никаких ограничений. Отчеты могут быть простыми или сложными, и их может быть столько, сколько требуется для удовлетворения всех потребностей пользо¬ вателей; • спроектировать пользовательский интерфейс в Visual Basic, который будет управлять доступом к Report Engine; • добавить к приложению элемент управления Crystal. 5.4.2. Проектирование пользовательского интерфейса Интерфейс, разрабатываемый для работы с отчетами, ограничен только потребностями пользователей и воображением разработчика. Если интерфейс может использовать эле¬
Гпава 5. Создание отчетов с помощью Crystal Reports 111 мент управления Crystal, он будет работать. Для Crystal Reports вид создаваемого пользо¬ вательского интерфейса безразличен — он к этому времени свое дело уже сделал. Вариантами использования Report Engine могут быть команда меню, которая создает един¬ ственный отчет, окно диалога, позволяющее сделать выбор из нескольких опций печати отчета, или полностью автономное приложение внешнего интерфейса, которое вызывается из текущего приложения. Все это — приемлемые методы, и каждый из них имеет свои преимущества. Реализация пользовательского интерфейса может определяться любым или всеми следующими аспектами: • назначение приложения; • типы отчетов, используемых в приложении; • параметры печати, установку которых требуется сделать доступными для этих отчетов; • в приложении имеется только один отчет или может быть сделан выбор из нескольких отчетов. 5.4.3. Подключение элемента управления Crystal к проекту Элементы управления ActiveX обеспечивают подключаемые возможности, которые позво¬ ляют добавлять компоненты приложения и даже целые приложения к разрабатываемым проектам без написания больше чем нескольких строк программного кода. Crystal Reports реализует концепцию ActiveX в элементе управления Crystal. Элемент управления Crystal (файл Crystl32.ocx) устанавливается в каталоге \Windows\System при инсталляции Visual Basic 5.0. Подключить элемент управления Crystal к npoeKTyVisual Basic можно, используя команду Components меню Project. В окне Components (см. рис. 1.3) в списке Controls нужно выбрать компонент Crystal Report Control 4.6. После подключения компонента Visual Basic добавляет элемент управления Crystal к пане¬ ли элементов. Рис. 5.20. Элемент управления Crystal в форме. 5.4.4. Применение элемента управления Crystal После размещения элемента управления Crystal в форме (в период выполнения он не виден) необходимо сформировать соединение между приложением и Crystal Reports. Сое¬ динение устанавливается установкой свойств объекта во время разработки или изменени¬ ем свойств в период выполнения. Свойства элемента управления позволяют специфицировать: • имя отчета, который требуется напечатать в ответ на событие в приложении; • адресат для вывода отчета (окно Preview, дисковый файл, принтер или электронная почта);
112 Элемент управления Crystal • количество копий, которое требуется напечатать (если отчет направляется на принтер); • информацию файла печати (если отчет направляется в дисковый файл); • информацию размеров и расположения окна Preview (если отчет направляется в окно предварительного просмотра); • информацию формулы выбора записей (если требуется ограничить записи в отчете); • информацию сортировки; • другие свойства отчета. Свойства элемента управления Crystal могут быть изменены как во время разработки, так и в период выполнения. Следует отметить, однако, что некоторые свойства доступны только в период выполнения. В окне свойств во время разработки эти свойства не представлены. Изменение свойств во время разработки Во время разработки свойства элемента управления Crystal могут быть доступны либо через окно свойств, либо через окно страниц свойств Property Pages. 1. Щелкнуть элемент управления Crystal, расположенный в форме, правой кнопкой мыши. 2. Выбрать команду Crystal Properties из контекстного меню. Появляется окно диалога Property Pages. 3. Используя вкладки и элементы управления в этом окне диалога, настроить свойства элемента управления ActiveX. Рис. 5.21. Окно диалога Property Pages для элемента управления Crystal. Изменение свойств в период выполнения Большинство свойств элемента управления Crystal можно установить в период выполнения, добавляя простые вхождения в программный код процедуры. Установки свойств периода выполнения заменяют установки, которые сделаны во время разработки. Свойство Action и метод PrintReport предназначены для фактического запуска отчета в период выполнения и могут использоваться только в период выполнения.
Гпава 5. Создание отчетов с помощью Crystal Reports 113 Информация по установке значений отдельных свойств в период выполнения приводится ниже в разделе описаний свойств. Каждое описание содержит пример установки свойства в программном коде приложения Visual Basic. 5.5. Свойства элемента управления Crystal Action Свойство, инициирующее печать отчета. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.Action = 1 Например: CrystalReportl.Action = 1 ' Печатает специфицированный отчет в ответ ' на событие в приложении. Доступность свойства: период выполнения. BoundReportFooter Значение свойства True или False определяет, нужно или нет вставлять раздел Page Footer в Default Bound Report (умолчательный связанный отчет). Применение в коде Visual Basic в период выполнения: [qbopwa.]CrystalReport1 .BoundReportFooter = True Например: CrystalReportl.BoundReportFooter = True Доступность свойства: разработка, выполнение. BoundReportHeading Свойство String, которое позволяет пользователю определять заголовок отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport1 .BoundReportHeading = "заголовок Например: ' Печать заголовка для специфицированного отчета CrystalReportl.BoundReportHeading = "Продажи по регионам" Доступность свойства: разработка, выполнение. Connect Регистрация на сервере SQL. Применение в коде Visual Basic в период выполнения: ^opMa.]CrystalReport.Connect[= _ "имя_сервера;идентификатор_пользователя; _ пароль; базаданных"] Например: CrystalReportl.Connect = "DSN = Accounting;UID = 734;PWD = _ bbbl;DSQ = Administration"
114 Свойства элемента управления Crystal В этой строке выполняется соединение с базой данных Administration на сервере Accounting с использованием идентификатора пользователя 734 и пароля bbb1. Параметры должны быть указаны в следующем формате: DSN = имя_сервера\UID = идентификатор_пользователя\ _ PWD = пароль, DSQ = базаданных Примечание: Прежде чем можно будет использовать это свойство, для всех баз данных SQL, к которым планируется обращаться, необходимо установить драйверы ODBC. Доступность свойства: разработка, выполнение. CopiesToPrinter Определяет количество копий, которые необходимо напечатать, если вывод отчета направ¬ ляется на принтер (если значение, назначенное для свойства Destination, 1 — Printer). Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.CopiesToPrinter[= количество_копий ] Например: CrystalReportl.CopiesToPrinter = 3 ' Печатает три копии ' специфицированного отчета. Параметр количество_копий не должен быть нулем или отрицательным числом. Доступность свойства: разработка, выполнение. DataFiles Определяет расположение файлов базы данных или таблиц, используемых в отчете. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.DataFiles(uH6eKC_Maccuea)[= расположение] Расположение — имя и путь каждого файла базы данных или таблицы в отчете, для которого требуется изменить расположение. Отдельную строку кода следует вводить для каждого файла, для которого требуется изме¬ нить расположение. Порядок файлов в массиве должен соответствовать порядку файлов в отчете. В дизайнере Crystal Reports определить порядок файлов в отчете можно в окне Set Location (команда Set Location в меню Database). Первый файл в отчете имеет индекс массива (0), второй файл — (1) и т. д. Например, чтобы изменить расположение первого и третьего файлов в отчете (1 .dbf и 3.dbf) на каталог c:\new, нужно использовать следующий синтаксис: CrystalReportl.DataFiles(O) = "c:\new\l.dbf" CrystalReportl.DataFiles(2) = "c:\new\3.dbf" DataFiles — свойство-массив, которое доступно только в период выполнения. Это свойство следует использовать, если требуется сформировать отчет с файлами из расположений, отличных от специфицированных в файле отчета. При использовании этого свойства изменять расположения всех файлов в отчете не требу¬ ется. Необходимо лишь обеспечить соответствие индексов массива каждого файла позици¬ ям этих файлов в отчете.
Гпава 5. Создание отчетов с помощью Crystal Reports 115 Свойство DataFiles очищается сразу после выполнения задания печати. Если потребуется распечатать отчет второй раз, программа к этому моменту уже вернется к расположениям, первоначально специфицированным в файле отчета. Доступность свойства: период выполнения. DataSource Определяет, какой элемент управления Data должен использоваться в качестве источника данных для элемента управления Crystal. Доступность: только во время разработки. Destination Определяет адресат печати отчета (Window, Printer или File). Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.Destination[= адресат] Например: CrystalReportl.Destination = 0 ' Передает специфицированный отчет ' в окно печати. Возможен выбор следующих адресатов печати: Значение Адресат Константа 0 Window (передает отчет в окно печати) crptToWindow 1 Printer (передает отчет на принтер) crptToPrinter 2 File (направляет вывод отчета в дисковый файл для последую¬ щей распечатки отчета или для импорта в другое приложение. Если выбирается это значение свойства Destination, необходимо также установить свойства PrintFileName и PrintFileType). crptToFile 3 EMail через MAPI (передает отчетдругому пользователю сети через MAPI Email (Microsoft Mail). Отчет присоединяется к со¬ общению EMail в формате, специфицированном свойством PrintFileType). crptMapi Доступность свойства: разработка, выполнение. DetailCopies Определяет количество копий каждой записи, которое должно быть напечатано в разделе Details отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.DetailCopies[= количество_копий ] Например: CrystalReportl.DetailCopies = 3 ' Определяет, что в разделе данных ' должны быть напечатаны ' три (3) копии каждой записи Если для DetailCopies установлено значение, меньшее или равное нулю, значение игнори¬ руется и в разделе данных будет напечатана 1 копия записей отчета. Доступность: разработка, выполнение.
116 Свойства элемента управления Crystal DiscardSavedData Если со специфицированным отчетом сохранены данные, установка этого свойство в 1 (True) отвергает данные. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.DiscardSavedData[= TrueFalse] Например: CrystalReportl.DiscardSavedData = 1 ' Отвергает данные, сохраненные ' со специфицированным отчетом. Для параметра TrueFalse используются значения: False = 0, True = 1. Доступность: разработка, выполнение. EMailCCList Определяет список "CC", по которому требуется маршрутизировать сообщение электрон¬ ной почты. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.EMailCCList [= списокадресатов] Например: ' Передать сообщение E-mail пользователям Волков и Воронков. CrystalReportl.EMailCCList = "Волков;Воронков" Применяется к MAPI. Имена должны разделяться точкой с запятой. Доступность: разработка, выполнение. EMailMessage Определяет строку, составляющую тело сообщения электронной почты. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.EMailMessage[=coo6u^eHue] Например: CrystalReportl.EMailMessage = "Встречаемся в 18:00 под часами" Применяется к MAPI. Доступность: разработка, выполнение. EMailSubject Определяет подчиненную строку (тему) сообщения электронной почты. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.EMailSubject[= тема] Например: CrystalReportl.EMailSubject = "По поводу предыдущей договоренности" Применяется к MAPI. Доступность: разработка, выполнение.
Гпава 5. Создание отчетов с помощью Crystal Reports 117 EMailToList Определяет список адресатов "To", по которому требуется направить сообщение электрон¬ ной почты. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.EMailToList [=список_адресатов] Например: CrystalReportl.EMailToList = "Воронков" ' В списке "To" - одно имя Применяется к MAPI. Несколько имен должны разделяться точкой с запятой. Доступность: разработка, выполнение. Formulas Определяет для существующей формулы новую строку спецификации. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.Formulas(uH6eKC_Maccuea)[= "имя_формулы= текст_формулы"] В этом свойстве вводится имя и новый текст для каждой формулы, которыми требуется заменить существующие спецификации формул отчета. Например, чтобы изменить формулу @COMMISSION на {file.SALES} *.1, а вторую формулу @TOTAL — на {file.SALES} + {file.COMMISSION}, нужно ввести следующее: CrystalReportl.Formulas(0) = "COMMISSION= {file.SALES} * .1" CrystalReportl.Formulas(1) = "TOTAL= {file.SALES} + {file.COMMISSION}" Особенности свойства: • Formulas — свойство-массив, которое доступно только в период выполнения; • для каждой формулы, которую требуется изменить, нужно вводить отдельную строку программного кода; • первой изменяемой формуле должен быть назначен индекс массива (0), второй — индекс массива (1) и т. д.; • новая строка формулы должна отвечать требованиям синтаксиса Crystal Reports; • по завершении выполнения задания печати значение этого свойства очищается. При повторной печати программа возвращается к формулам, первоначально специфициро¬ ванным в отчете. Примечание: Пробелы в именах формул — значащие. По этой причине знак равенства должен следовать непосредственно за именем формулы без дополнительных пробелов. Примечание: Знак @ при обозначении имени формулы в этом свойстве не используется. Примечание: Для создания новых формул свойство Formulas использовать нельзя. Его можно использовать только для изменения существующих формул. Доступность свойства: период выполнения. GraphData Получает и устанавливает данные, используемые для специфицированной диаграммы. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.GraphData(uHcteKC_Maccuea)[= раздел_отчета\ _ номер_диаграммы; строка; столбец; поле; направление]
118 Свойства элемента управления Crystal Параметр Назначение раздел_отчета Определяет раздел, в котором требуется изменить диаграмму (см. ниже таблицу значений параметра раздел_отчета). номер_диаграммы Номер диаграммы внутри раздела, которую требуется изменить. Ди¬ аграммы в разделе нумеруются начиная с нуля, слева направо и затем сверху вниз. строка Номер группы в отчете, используемой для создания строк в диаграм¬ ме, например GROUP1,GROUP2, GROUP3, . . ., GROUP9 столбец Номер группы в отчете, используемой для создания столбцов в диаг¬ рамме, например GROUP1, GROUP2, GROUP3, . . ., GROUP9. поле Поле суммирования, содержащее значения, которые нужно исполь¬ зовать в качестве значения каждого элемента диаграммы (столбика, сектора и т.д). Первое поле суммирования, добавленное к отчету, получает значение 0, второе — 1 и т. д. направление Указывает, какие значения используются для создания диаграммы: строк, столбцов или оба. Возможные значения: ROWS, COLS, ROWANDCOL или COLANDROW. В следующей таблице приведены возможные значения параметра раздел_отчета\ Раздел Код раздела Раздел Код раздела Все разделы ~ALL Group Footer 1 ^Fi Заголовок отчета TITLE Group Footer 2 ~GF2 Page Header HEADER Group Footer 3 GF3 Group Header 1 GH1 Group Footer 4 GF4 Group Header 2 GH2 Group Footer 5 GF5 Group Header 3 GH3 Group Footer 6 GF6 Group Header4 GH4 Group Footer 7 GF7 Group Header 5 GH5 Group Footer 8 GF8 Group Header 6 GH6 Group Footer 9 GF9 Group Header 7 GH7 Grand Total GRNDTTL Group Header 8 GH8 Page Footer FOOTER Group Header 9 GH9 Резюме отчета SUMMARY Раздел данных DETAIL Например: CrystalReportl.GraphData(0)= "DETAIL; 1; GROUPl; GROUP2; 0;COLANDROW" С помощью свойства GraphData в период выполнения можно специфицировать изменения в одной или больше диаграммах. Эти изменения затем применяются при вызове "Action=1". Значение для GraphData просто определяет последовательный номер изменения. Таким образом, строка: CrystalReportl.GraphData(O) = "DETAIL; 3; Groupl; Group2;666; COLANDROW" вводится для создания изменений только в одной диаграмме, но строки CrystalReportl.GraphData(O) = "HEADER; 3; Groupl; Group2;666; _ COLANDROW"
Гпава 5. Создание отчетов с помощью Crystal Reports 119 CrystalReportl.GraphData(l) = "DETAIL; 3; Groupl; Group2;666; COLANDROW" обусловливают изменения в более чем одной диаграмме. Доступность свойства: период выполнения. GraphOptions Получает и устанавливает ряд опций для специфицированной диаграммы. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.GraphOptions(uHcteKC_Maccuea)[= раздел_отчета\ _ номер_диаграммы; шрифт; направлениестолбиков; _надпись_элемента; _ линии_сетки;легенда;тах;т'т] Параметр Описание раздел_отчета Определяет раздел отчета, в котором требуется изменить ди¬ аграмму. номер_диаграммы Определяет, какую диаграмму в разделе требуется изменить. Диаграммы в разделе нумеруются начиная с нуля, слева на¬ право и сверху вниз. шрифт Определяет стиль шрифта (фактическое имя шрифта, напри¬ мер Arial), который требуется использовать для всей диаграм¬ мы. направлениестолбиков В гистограмме (столбиковой диаграмме) определяет направ¬ ление столбиков. Возможные значения: H = горизонтально, V = вертикально, X = как есть. надпись_элемента Определяет, требуется или нет показывать значения данных на каждом элементе диаграммы. Возможные значения: T = да, F = нет, X = как есть. линии_сетки Определяет, требуется ли показывать линии сетки диаграммы. Возможные значения: T = да, F = нет, X = как есть. легенда Определяет, требуется ли показывать легенду диаграммы. Возможные значения: T = да, F = нет, X = как есть. max Определяет максимальное значение, которое требуется ото¬ бражать в диаграмме. min Определяет минимальное значение, которое требуется ото¬ бражать в диаграмме. Например: CrystalReportl.GraphOptions(0) ="FOOTER;0;Arial;H;T;F;X;max;min" (В разделе Page FooteroT4eTa в первой диаграмме устанавливает шрифт диаграммы в Arial, устанавливает горизонтальное направление столбиков, показывает значения данных на каждом элементе (надпись_элемента = T) и отключает вывод сетки.) С помощью свойства GraphOptions в период выполнения можно специфицировать измене¬ ния в одной или больше диаграммах. Эти изменения применяются последовательно при отработке вызова "Action=1". Значение индексмассива для GraphOptions просто определя¬ ет последовательный номер изменения. Доступность свойства: период выполнения.
120 Свойства элемента управления Crystal GraphText Получает и устанавливает для специфицированной диаграммы различные текстовые ком¬ поненты. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.GraphText(uH6eKC_Maccuea)[= раздел_отчета;_ номер_диаграммы;заголовок; подзаголовок; нижний_колонтитул; ряд; группа; x; у; z] Например, строка: CrystalReportl.GraphText(O) = "HEADER; 0;;;;;;новая_надпись_х; _ новая надпись у; новая надписв z " определит надписи по осям x, у и z для первой диаграммы в разделе Page Header. С помощью свойства GraphText в период выполнения можно специфицировать изменения в одной или больше диаграмм. Эти изменения применяются последовательно при отработ¬ ке вызова "Action=1". Значение индексмассива для GraphOptions просто определяет после¬ довательный номер изменения. Таким образом, строка: CrystalReportl.GraphText (0) = "DETAIL; 1; строка заголовка; строка подзаголовка; строка колонтитула; строка ряда; строка группы; строка x; строка у; строка z" создает изменения только в одной диаграмме, но строки: CrystalReportl.GraphText (0) = "DETAIL; 1; строка заголовка; строка подзаголовка; строка колонтитула; строка ряда; строка группы; строка x; строка у; строка z" CrystalReportl.GraphText (1) = "DETAIL; 1; строка заголовка; строка подзаголовка; строка колонтитула; строка ряда; строка группы; строка x; строка у; строка z" обуславливают изменения более, чем в одной диаграмме. Доступность свойства: период выполнения. GraphType Получает и устанавливает вид диаграммы, используемой в указанном разделе специфици¬ рованного отчета. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.GraphType(uH6eKC_Maccuea)[= раздел_отчета;_ номер_диаграммы;тип_диаграммы] Например: CrystalReportl.GraphType(0)= "GH1; 0; PIE" Определяет первую диаграмму (graphNum = 0) в разделе Group Header 1 как круговую. С помощью свойства GraphType в период выполнения можно специфицировать изменения в одной или больше диаграммах. Эти изменения применяются последовательно при отра¬ ботке вызова "Action=1". Значение индекс массива для GraphOptions просто определяет последовательный номер изменения. Таким образом, строка: CrystalReportl.GraphType(O) = "DETAIL; 0; PIE" создает изменения только в одной диаграмме, но строки: CrystalReportl.GraphType(0) = "HEADER; 0; PIE"
Гпава 5. Создание отчетов с помощью Crystal Reports 121 CrystalReportl.GraphType(l) = "DETAIL; 0; PIE" обусловливают изменения больше чем в одной диаграмме. Графы в разделе нумеруются начиная с нуля, слева направо и сверху вниз. В следующей таблице приводятся константы типов диаграмм для применения в програм¬ мном коде: Тип диаграммы Константа Плоская гистограмма SIDEBYSIDE 3-D гистограмма 3DSIDE Сложенная плоская гистограмма STACKEDBAR 3-D сложенная гистограмма 3DSTACKED Процентная плоская гистограмма PERCENTBAR 3-D процентная гистограмма 3DPERCENT График LINE Диаграмма с областями AREA 3-D столбики 3DBARS Круговая ~ЙЁ Несколько кругов MULTIPLEPIE Ранжированные круги WEIGHTEDPIE Доступность свойства: период выполнения. GroupCondition Определяет, какое изменение значения поля группы вызовет создание новой группы. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.GroupCondition(uHcteKc)[= группа; поле; условие;_ порядок_сортировки] Например, строка: CrystalReportl.GroupCondition(0)="GROUPl;{Header.Ordernum};ANYCHANGE;А" определяет, что любое изменение в поле Ordernum в Group1 обусловит новое группиро¬ вание. Параметры свойства: Параметр Описание группа Группа, для которой требуется установить условие группирова¬ ния. Первая группа в отчете — GROUP1, следующая группа — GROUP2 и т. д. поле Имя поля, при изменении значения которого инициируется новое группирование. Имя поля нужно вводить в следующем формате: {таблица.поле} условие Условие, которое вызывает группирование (см. таблицы ниже). порядок_сортировки Направление, в котором должны сортироваться группы: А = возрастание, D = убывание.
122 Свойства элемента управления Crystal В следующей таблице приводятся возможные значения параметра условие'. Условие Код условия Поля типа Date Ежедневно DAILY Еженедельно WEEKLY ~ Два раза в месяц SEMIMONTHLY Ежемесячно MONTHLY Ежеквартально QUARTERLY Раз в полгода SEMIANNUALLY Ежегодно ANNUALLY Поля типа Boolean При изменении значения на Yes TOYES При изменении значения на No TONO При каждом Yes EVERYYES ~ При каждом No EVERYNO ~ Следующее будет Yes NEXTISYES ~ Следующее будет No NEXTISNO ~ Для всех остальных типов данных Любое изменение ANYCHANGE Доступность свойства: период выполнения. GroupSelectionFormula Определяет группы, которые нужно использовать при печати отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.GroupSelectionFormula[= "формула_выбора_группы"] Формула выбора группы специфицируется точно также, как и в окне Edit Formula. Например, для ограничения отчета только группами с промежуточной суммой по полю {Header.Amount}, меньшей 10000 (с инициированием группирования изменениями в поле {Header.CustNum}), нужно в качестве формулы выбора группы ввести следующую строку: CrystalReportl.GroupSelectionFormula = Sum ( {Header.Amount}, {Header.CustNum}) < 10000 Если формула выбора группы включает внутренние кавычки, нужно изменить все внутрен¬ ние двойные кавычки на одинарные кавычки и затем заключить всю формулу в двойные кавычки. Примечание: Если во время разработки в отчете уже была создана формула выбора группы, любая формула выбора, введенная в период выполнения будет конкатенирована к первой формуле с соединением через "AND". Таким образом, записи будут отбираться на базе комбинации из двух формул. Доступность свойства: разработка, выполнение. GroupSortFields Определяет поле (поля) группы, которые должны использоваться, для сортировки данных при печати отчета.
Гпава 5. Создание отчетов с помощью Crystal Reports 123 Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.GroupSortFields(uH6eKC_Maccuea)[= "{+\-}поле"] Например, допустим, что данные в группах разбиты по городам и Crystal Reports должен подсчитать количество клиентов в каждой группе. Чтобы вначале напечатать группу с самым большим количеством клиентов, затем группу со следующим количеством и т. д. (в порядке убывания), можно ввести примерно следующую строку: CrystalReportl.GroupSortFields(O) = "-Count({Customer.Customer}, _ {Customer.Sity})" Особенности свойства: • GroupSortFields — свойство-массив, доступное только в период выполнения; • для специфицирования каждого поля сортировки группы следует использовать отдель¬ ную строку программного кода; • вводить поля сортировки групп нужно в том порядке, в котором требуется сортировать отчет. Например, если требуется, чтобы отчет был отсортирован сначала по полю А , а затем по полю В, соответственно, нужно создать две строки программного кода; • первому специфицируемому полю сортировки группы должен быть назначен индекс_мас- сива 0, второму полю — 1 и т. д. Ряд значений индексов должен быть непрерывным; • значения индексов должны быть указаны в строке кода непосредственно после имени свойства, то есть CrystalReportl.GroupSortFields (0) =.... • если имеются поля сортировки, специфицированные для отчета во время разработки, они будут заменены полями, введенными в коде в период выполнения; • если свойство GroupSortFields не используется, программа использует инструкции сор¬ тировки, специфицированные в файле отчета; • если требуется очистить поля сортировки группы в отчете, следует использовать пустую строку: CrystalReportl.GroupSortFields (0) = "" • значение свойства, установленное в период выполнения, после выполнения задания печати сбрасывается. При повторной печати программа возвращается к полям сортиров¬ ки группы, первоначально специфицированным в файле отчета. Примечание: Имени поля сортировки группы должен предшествовать указатель направления сортировки (+ или -) без пробелов. Примечание: Чтобы найти правильный синтаксис для любой группы в отчете, используя Crystal Reports для Visual Basic, нужно: выбрать команду меню Insert | Formula field, ввести имя формулы в окно диалога Insert Formula, когда он появляется, и в списке Fields в окне Formula Edit дважды щелкнуть поле группы, представляющее интерес. Crystal Reports вводит имя поля группы в окно Formula text. Имя и синтаксис из этого поля можно использовать при построении строки для поля сортировки группы. Доступность свойства: период выполнения. LastErrorNumber Возвращает код последней ошибки, возникшей во время выполнения программы. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.LastErrorNumber
124 Свойства элемента управления Crystal Например: ' Если возвращается ошибка, перейти к метке Error Handler ErrorHandler: MsgBox CrystalReportl.LastErrorNumber Если возвращается ошибка, этот программный код вызывает окно сообщения, которое выводит на экран номер ошибки. Примечание: Значение LastErrorNumber может быть получено после того, как отработает вызов свойства Action. После печати отчета можно обратиться к этому свойству за номером ошибки (если таковой имеется). Если ошибки при печати не было, LastErrorNumber = 0. Доступность свойства: чтение и запись в период выполнения. LastErrorString Во время выполнения программы возвращает описание последней ошибки. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.LastErrorString Например: ' Если возвращается ошибка, перейти к процедуре Error Handler ErrorHandler: MsgBox CrystalReportl.LastErrorString Доступность свойства: период выполнения. MarginBottom, MarginLeft, MarginRight, MarginTop Устанавливают поля для специфицированного отчета: MarginBottom — устанавливает нижнее поле отчета. MarginLeft — устанавливает левое поле отчета. MarginRight — устанавливает правое поле отчета. MarginTop — устанавливает верхнее поле отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.MarginBottom[=3Ha4eHue] Например: ' Установить нижнее поле для отчета равным 1/2 дюйма ' (1 дюйм = 14 40 твипов) CrystalReportl.MarginBottom = 720 Доступность свойств: разработка, выполнение. Password Вводит пароль, требуемый для использования таблицы базы данных Access (файл.гт^Ь) ограниченного доступа. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.Password[= пароль] Например: CrystalReportl.Password = "PPP4" Доступность свойства: разработка, выполнение.
Гпава 5. Создание отчетов с помощью Crystal Reports 125 PrintDay Устанавливает компонент дня даты печати (если печатается отчет с датой, отличной от фактической даты). Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.PrintDay[=cteHb] Например: CrystalReportl.PrintDay = 23 Особенности свойства: свойства PrintYear, PrintMonth и Рпп10аудолжны использоваться совместно. To есть, чтобы изменить дату печати, необходимо изменить значения всех трех свойств. Если этого не сделать, используется дата печати, сохраненная с отчетом. Это может быть также текущая дата, если с отчетом не сохранена определенная дата. Доступность: разработка, выполнение. PrinterCollation Если специфицируется печать более одной копии (через свойство PrinterCopies), свойство PrinterCollation определяет, будутли эти копии объединены. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.PrinterCollation[=Ko6] Например: CrystalReportl.PrinterCollation = 1 ' Объединить копии ' специфицированного отчета Значение параметра код может быть назначено из следующей таблицы: Действие с копиями Значение параметра код Константа Не объединять 0 crptUncollated Объединять 1 crptCollated Умолчательное объединение 2 crptDefault Доступность: разработка, выполнение. PrinterCopies Устанавливает количество копий отчета, которое требуется напечатать. Применение в коде Visual Basic в период выполнения: [qb0pMa.]CrystalRep0rt.PrinterC0pies[=4UCT0_K0nu<J] Например: CrystalReportl.PrinterCopies = 3 ' Программа должна печатать ' три (3) копии отчета Параметр число_копий не должен быть нулем или отрицательным значением. Доступность: разработка, выполнение. PrinterDriver, PrinterName, PrinterPort Возвращают и устанавливают, соответственно, имя драйвера принтера, имя принтера и порт принтера, на котором должен печататься отчет.
126 Свойства элемента управления Crystal Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.PrinterDriver[= драйвер_принтера] [gbopMa.]CrystalReport. PrinterName[= имя_принтера] [gbopMa.]CrystalReport.PrinterPort[= порт_принтера] Например: CrystalReportl.PrinterDriver = "Epson24.drv" ' Определяет драйвер ' Epson24.drv CrystalReportl.PrinterName= "Epson LQ-850" ' Определяет принтер ' Epson LQ-850 CrystalReportl.PrinterPort= "LPT1" ' Устанавливает для принтера ' порт LPT1 Свойства PrinterDriver, PrinterName и PrinterPort работают совместно. Для определения нового принтера должны быть установлены все три свойства. Если все три свойства не установлены, будет использоваться принтер, определенный в отчете. Если в отчете прин¬ тер не был специфицирован, будет использоваться умолчательный принтер системы. Доступность свойств: разработка, выполнение. PrinterStartPage Устанавливает страницу, с которой нужно начать печатать отчет. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.PrinterStartPage[= StartPage] Например: CrystalReportl.PrinterStartPage = 7 ' Начать печатать отчет ' с 7-й страницы Если значение StartPage меньше или равно 0, это значение игнорируется и печать начина¬ ется со страницы 1. Доступность: разработка, выполнение. PrinterStopPage Устанавливает последнюю страницу, которая должна быть напечатана. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.PrinterStopPage[=StopPage] Например: ' Печать должна закончиться на странице 12 отчета CrystalReportl.PrinterStopPage = 12 Чтобы указать, что печать нужно продолжить до последней страницы, для свойства PrinterStopPage можно ввести значение -1. Доступность: разработка, выполнение. PrintFileCharSepQuote Получает и устанавливает символ кавычки, используемый для заключения алфавитно-циф- ровых данных поля при печати в файл с использованием формата текста с разделителями. Применение в коде Visual Basic в период выполнения:
Гпава 5. Создание отчетов с помощью Crystal Reports 127 [qbopMa.]CrystalReport.PrintFileCharSepQuote[=Kaeb/4Ka] Например: CrystalReportl.PrintFileCharSepQuote = " ' " Особенности свойства: • применяется, только когда PrintFileType = 5 — формат "текст с разделителями"; • применяется, только когда свойство Destination = 2 — файл или 3 — EMail; • если для свойства PrintFileCharSepQuote указана строка, содержащая более одного символа, элемент управления использует только первый символ этой строки. Доступность: разработка, выполнение. PrintFileCharSepSeparator Устанавливает символ (символы), которые требуется использовать для разделения полей при печати в файл с использованием формата текста с разделителями. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.PrintFileCharSepSeparator[=pa36&numanb] Например: ' Для разделения значений полей должен использоваться символ " @ " CrystalReportl.PrintFileCharSepSeparator= "@" Особенности свойства: • применяется, только когда PrintFileType = 5 — формат "текст с разделителями"; • применяется, только когда свойство Destination = 2 — файл или 3 — EMail. Доступность свойства: разработка, выполнение. PrintFileName Определяет имя файла, в который должен быть направлен вывод отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.PrintFileName[= имя_файла] Например: ' Вывести отчет в файл "cust rpt.txt" в каталоге c:\crw CrystalReportl.PrintFileName ="c:\crw\cust rpt.txt" Особенности свойства: • дважды щелкнув это свойство в окне свойств, можно затем нажать кнопку с многоточием в окне Property Pages для этого свойства и в окне диалога Choose Output File выбрать имя и путь файла, в который программа должна напечатать отчет; • значение для этого свойства можно установить, только когда выполняется печать в файл (если значение свойства Destination = 2 — файл). Примечание: Если требуется специфицировать PrintFileName в период выполнения, имя файла необходимо заключать в кавычки. Доступность свойства: разработка, выполнение. PrintFileType Определяет тип файла, используемого при печати отчета в файл. Применение в коде Visual Basic в период выполнения:
128 Свойства элемента управления Crystal [gbopMa.]CrystalReport.PrintFileType[= тип_файла] Например: CrystalReportl.PrintFileType = 1 ' Формат разделения табуляторами При печати в файл можно выбрать один из следующих типов файла (если значение свойства Destination = 2 — файл): Тип файла Описание Константа 0 — Запись Стиль записи (столбцы значений). Не использует¬ ся никаких разделителей. Каждая запись имеет фиксированную длину. crptRecord 1 — Разделение табуляторами Представляет данные в табличной форме. Алфа- витно-цифровые данные поля заключаются в ка¬ вычки, и поля разделяются табуляторами. crptTabSep 2 — Текст Данные сохраняются в текстовом формате ASCII со всеми значениями, отделяемыми пробелами. Текст этого стиля выглядит, как напечатанная страница. crptText 3 — DIF Сохранение данных в формате DIF (data interchange format — формат обмена данных). Этот формат часто используется для передачи данных между электронными таблицами разных форма¬ тов. crptDIF 4 — CSV (Comma separated values) Значения отделяются запятыми. Апфавитно-циф- ровые данные поля заключаются в кавычки, и поля разделяются запятыми. crptCSV 5 — Разделение символами Сохранение значений данных в текстовом форма¬ те ASCII с разделением символами. Все значения отделяются символом или символами, специфи¬ цированными свойством PrintFileCharSepSeparator. crptCharSep 6 — Разделение табуляторами Сохранение значений данных в текстовом форма¬ те ASCII с разделением табуляторами. crptTabSepText 7 — Формат Crystal Reports RPT Используется стандартный формат Crystal Reports. Наиболее часто применяется для переда¬ чи отчета другому пользователю через EMail. crptCrystal 8 — Excel 2.1 XLS Отчет экспортируется в формате рабочего листа Microsoft Excel 2.1. crptExcel21 9 — Excel 3.0 XLS Отчет экспортируется в формате рабочего листа Microsoft Excel 3.0. crptExcel30 10 — Excel 4.0 XLS Отчет экспортируется в формате рабочего листа Microsoft Excel 4.0. crptExcel40 11 — Lotus 1-2-3 WK1 Отчет экспортируется в формате рабочего листа Lotus 1-2-3 WK1. crpt123wk1 12 — Lotus 1-2-3 WK3 Отчет экспортируется в формате рабочего листа Lotus 1-2-3 WK3. crpt123wk3
Гпава 5. Создание отчетов с помощью Crystal Reports 129 Тип файла Описание Константа 13 — Lotus 1-2-3 WKS Отчет экспортируется в формате рабочего листа Lotus 1-2-3 WKS. crpt123wks 15 — RTF Данные сохраняются в формате RTF (Rich Text Format). crptRTF 17 — Word для Windows Данные сохраняются в формате Word для Windows. crptWinWord 19 — Excel 5.0 XLS Отчет экспортируется в формате рабочего листа Microsoft Excel 5.0. crptExcel50 20 — HTML 3.0 Отчет экспортируется в формате HTML. crptHTML30 21 — Internet Explorer Отчет экспортируется в формате Internet Explorer. crptlntExpl 22 — Netscape Отчет экспортируется в формате Netscape. crptNetscape Доступность свойства: разработка, выполнение. PrintFileUseRptDateFmt При печати в файл указывает, должна ли программа сохранить даты в том же формате дат, который используется вотчете, или вместо этогооптимизировать даты сучетом выбранного формата файла. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.PrintFileUseRptDateFmt[= TrueFalse] Например: ' Программа должна печатать даты в том же формате, ' который используется в отчете. CrystalReportl.PrintFileUseRptDateFmt = 1 Особенности свойства: • применяется, только когда свойство PrintFileType = 0, 1, 3, 4 или 5; • применяется, только когда свойство Destination = 2 — файл или 3 — EMail. Доступность: разработка, выполнение. PrintFileUseRptNumberFmt При печати в файл указывает, должна ли программа печатать числа в том же формате (десятичные позиции, отрицательные значения и т. д.), который использовался в отчете, или вместо этого оптимизировать числа с учетом выбранного формата файла. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.PrintFileUseRptNumberFmt[=7rueFa/se] Например: ' Программа должна печатать числа в том же формате, ' какой используется в отчете CrystalReportl.PrintFileUseRptNumberFmt = 1 Особенности свойства: • применяется, только когда свойство PrintFileType = 0, 1, 3, 4 или 5; • применяется, только когда свойство Destination = 2 — файл или 3 — EMail. Доступность: разработка, выполнение.
130 Свойства элемента управления Crystal PrintMonth, PrintYear Устанавливают, соответственно, компонент месяца и года даты печати (если он отличается от фактической даты печати отчета). Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.PrintMonth[= месяц] [qbopMa.]CrystalReport.PrintYear[=3od] Например: CrystalReportl.PrintMonth= 7 'Устанавливает июль как месяц печати CrystalReportl.PrintYear = 1997 ' Устанавливает компонент ' года даты печати равным 1997 Особенности свойств: • значение месяца вводится в интервале от 1 до 12 (январь = 1, декабрь = 12); • год вводится как четырехзначное число; • свойства PrintYear, PrintMonth и PrintDay функционируют совместно. Чтобы изменить дату печати, необходимо изменить значения всех трех свойств. Если этого не сделать, будет использована дата печати, сохраненная с отчетом. Если определенная дата не сохранена с отчетом, будет использована текущая дата. Доступность: разработка, выполнение. RecordsPrinted Определяет количество фактически напечатанных записей. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.RecordsPrinted Например: 'Вернуть количество напечатанных записей и сохранить его в переменной Printed= CrystalReportl.RecordsPrinted Если печатаемый отчет содержит одну или больше формул выбора группы, значение, возвра¬ щенное свойством RecordsPrinted, может быть значительно меньше значения, возвращенного свойством RecordsSelected. Иначе это значение должно равняться RecordsSelected. Доступность свойства: период выполнения. RecordsRead Определяет количество фактически обработанных записей. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.RecordsRead Например: ' Получить количество прочитанных записей и сохранить его в переменной Readl = CrystalReportl.RecordsRead Если при печати отчета Crystal Reports Engine генерирует запрос SQL, чтобы получить данные из базы данных SQL, RecordsRead вернет только количество записей, полученных из запроса. Это значение может быть значительно меньше, чем количество записей, факти¬ чески сохраняемых в таблице базы данных. Доступность свойства: период выполнения.
Гпава 5. Создание отчетов с помощью Crystal Reports 131 RecordsSelected Определяет количество записей, отобранных для включения в отчет из общего количества прочитанных записей. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.RecordsSelected Например: ' Получить количество выбранных записей и сохранить его в переменной Selected = CrystalReportl.RecordsSelected RecordsSelected возвращает значение между нулем и значением, возвращенным свойством RecordsRead. Значение, возвращенное свойством RecordsSelected, зависит от установленных в отчете запросов и формул выбора. Доступность свойства: период выполнения. ReportDisplayPage Указывает, которая страница многостраничного отчета в данный момент выводится на экран в окне Preview. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.ReportDisplayPage Например: ' Получить номер выводимой страницы и сохранить его в переменной Result = CrystalReportl.DisplayPage Доступность свойства: период выполнения. ReportFileName Определяет отчет, который должен быть напечатан. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.ReportFileName[= имя_отчета] Например: CrystalReportl.ReportFileName = "c:\crw\company.rpt" Дважды щелкнув это свойство в окне свойств, можно затем нажать кнопку с многоточием в окне Property Pages для этого свойства и в окне диалога Choose Report выбрать имя и путь отчета, который программа должна напечатать в ответ на пользовательское событие. Примечание: Если требуется специфицировать ReportFileName в период выполнения, имя отчета в программном коде должно быть заключено в кавычки. Доступность свойства: разработка, выполнение. ReportLatestPage Определяет последнюю страницу, напечатанную в специфицированном отчете. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.ReportLatestPage
132 Свойства элемента управления Crystal Например: ' Получить номер последней напечатанной страницы ' и сохранить ее в переменной Latest = CrystalReportl.ReportLatestPage Доступность свойства: период выполнения. ReportStartPage Определяет первую страницу, напечатанную в специфицированном отчете. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.ReportStartPage Например: ' Получить номер первой напечатанной страницы ' и сохранить его в переменной StartPage = CrystalReportl.ReportStartPage Доступность свойства: период выполнения. SectionFont Устанавливает шрифт для одного или больше разделов специфицированного отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.SectionFont(uHcteKc)[= кодраздела; _шрифт; размер_шрифта; _ курсив; полужирный; подчеркивание; зачеркивание] Например: ' Установить для раздела нижнего колонтитула ' шрифт в 12 пунктов, Arial, зачеркнутый CrystalReportl.SectionFont(0)="FOOTER;Arial;12;N;N;N;Y" С помощью свойства SectionFont в период выполнения можно специфицировать изменения в одном или больше разделах отчета. Эти изменения затем последовательно применяются при вызовах "Action=1". Значение индекс для свойства SectionFont просто определяет последовательный номер изменения. Таким образом, строка: CrystalReportl.SectionFont(0)= "DETAIL;Arial;12;N;N;N;Y" вносит изменения только в раздел DETAIL, но строки: CrystalReportl.SectionMinHeight(0) = "HEADER;Arial;12;N;N;N;Y" CrystalReportl.SectionMinHeight(1) = "DETAIL;Arial;12;N;N;N;Y" обусловливают изменения в более чем одном разделе. SectionLineHeight Определяет высоту строки отчета в твипах. Твип — 1/1440 дюйма; в точке — 20 твипов. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.SectionLineHeight(uHcteKc)[= код раздела; _строка; высота; _ подъем]
Гпава 5. Создание отчетов с помощью Crystal Reports 133 Параметр Описание кодраздела Определяет программный код раздела (разделов) отчета, для которых тре¬ буется установить новую высоту строки. строка Определяет номер строки (строк), для которых требуется установить высо¬ ту. Строки в разделах нумеруются начиная с 0. высота Определяет высоту строки в твипах. Твип — 1/1440 дюйма; в точке — 20 твипов. подъем Определяет подъем шрифта в твипах. Подъем — расстояние от верхней границы распределенного пространства строки (высота строки) до базовой линии шрифта. Параметр подъем используется для специфицирования позиции базовой линии. Если подъем установить в 0, программа помещает базовую линию наверху пространства строки; если для подъем установить то же значение, что и для высота, программа устанавливает базовую линию внизу пространства строки. Для любой другой базовой линии подъ¬ ем специфицируется в твипах. Например: ' Установить высоту второй строки в разделе нулевого ' заголовка группы в 50 0 твипов с подъемом 30 0 твипов CrystalReportl.SectionLineHeight(O) = "GH0; 1; 500; 300" С помощью свойства SectionLineHeight в период выполнения можно специфицировать изменения в одном или больше разделах отчета. Эти изменения применяются последова¬ тельно при вызове "Action=1". Значение индекс для свойства SectionLineHeight определяет последовательный номер изменения. Доступность свойства: период выполнения. SectionMinHeight Устанавливает минимальную высоту специфицированного раздела отчета. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.SectionMinHeight(uHcteKc)[=Ko6_pa36&na;m/>7_eb/coma] Например: ' Установить минимальную высоту для всех разделов равной 50 0 твипов CrystalReportl.SectionMinHeight(O) = "ALL; 500" С помощью свойства SectionMinHeight в период выполнения можно специфицировать изме¬ нения в одном или больше разделах отчета. Эти изменения применяются последовательно при вызове "Action=1". Значение индекс для свойства SectionMinHeight определяет после¬ довательный номер изменения. Доступность свойства: период выполнения. SelectionFormula Определяет записи, которые нужно использовать при печати отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.SelectionFormula[= формула] Формула выбора вводится в свойство точно также, как в окно Edit Formula в Crystal Reports. Например, чтобы включить в отчет только те записи, которые в поле {file.Qty} имеют
134 Свойства элемента управления Crystal значение, большее 5, для параметра формула нужно ввести "{File.Qty} > 5", то есть CrystalReport1.SelectionFormula = "{File.Qty} > 5" Особенности свойства: • строку формулы выбора следует заключать в двойные кавычки; • если формула выбора включает внутренние кавычки, например: {File.Sity} = "Иваново", то нужно все внутренние двойные кавычки изменить на одинарные кавычки и затем заклю¬ чить всю формулу выбора в двойные кавычки: "{File.Sity} = ’Иваново’" • если формула выбора создана для отчета во время разработки, то любая формула, которая вводится в свойство SelectionFormula, будет конкатенирована к этой формуле выбора. Таким образом, записи будут отбираться с учетом комбинации двух формул выбора. Доступность свойства: разработка, выполнение. SessionHandle Устанавливает дескриптор сеанса пользователя, когда для использования в отчете с по¬ мощью свойств UserName и Password открывается файл .mdb. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.SessionHandle[= дескриптор] Если в приложении Visual Basic уже открыт сеанс Jet, с помощью свойства SessionHandle можно установить этот сеанс в качестве текущего. Иначе нужно использовать свойства Password и UserName для установления нового сеанса Jet. Например: CrystalReportl.SessionHandle = CurrentSessionHandle Здесь текущим устанавливается дескриптор сеанса, возвращенный где-либо в другом месте в приложении и сохраненный в переменной CurrentSessionHandle. Доступность свойства: период выполнения. SortFields Определяет поле (поля), которые должны использоваться для сортировки данных при печати отчета. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.SortFields(uH6eKC_Maccuea)[= "{+|-}лоле"] Например, чтобы отсортировать в отчете данные из базы данных заказов сначала в алфа¬ витном порядке по клиентам, а затем по дате заказа, можно ввести такие строки кода: CrystalReportl.SortFields(O) = "+{Orders.Customer}" CrystalReportl.SortFields(l) = "+{Orders.Orderdate}" Особенности свойства: • SortFields — свойство-массив, доступное только в период выполнения; • для специфицирования каждого поля сортировки нужно использовать отдельную строку кода; • поля сортировки нужно вводить в том порядке, в котором требуется отсортировать отчет; • первому полю сортировки должен быть назначен индекс массива 0, второму полю — 1 и т. д; • значения ряда индексов массива должны быть непрерывны; пропуски не допускаются (0,1,3 = неправильно);
Гпава 5. Создание отчетов с помощью Crystal Reports 135 • если во время разработки для отчета уже были специфицированы поля сортировки, поля, которые вводятся в свойство SortFields, заменят ранее назначенные поля; • если это свойство не используется, программа использует инструкции сортировки, спе¬ цифицированные в файле отчета; • для очистки поля сортировки в отчете можно использовать пустую строку (CrystalReport1 .SortFields (0) = ""); • имена полей следует заключать в фигурные скобки; • полями сортировки могут быть поля базы данных или поля формулы. Если сортировка выполняется по полю формулы, перед именем формулы используется знак @, то есть @имя_формулы. Доступность свойства: период выполнения. SQLQuery Устанавливает запрос SQL, используемый для специфицированного отчета. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.SQLQuery[=3anpoc_SQL] Например: CrystalReportl.SQLQuery = "SELECT authors.au_id, authors.au lname, authors.au fname FROM pubs2 authors WHERE authors.au lname > 'Воронков'" Здесь выполняется запрос SQL базы данных, в котором возвращаются только записи, содержащие фамилии авторов после фамилии ’Воронков’, в алфавитном порядке фамилий. Изменять можно только разделы WHERE и FROM запроса SQL. Хотя свойство требует ввода всего запроса SQL, раздел SELECT не должен отличаться от оригинального запроса. Доступность свойства: разработка, выполнение. Status Определяет статус печати специфицированного отчета. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.Status Например: ' Получить статус печати и сохранить его в переменной rptStatus = CrystalReportl.Status Свойство Status может вернуть одно из следующих значений: • 0 — отчет не был напечатан или печать не закончена; • 3 — печать отчета завершена; • 5 — печать отчета была отменена пользователем. Доступность свойства: период выполнения. StoredProcParam При использовании отчета, базирующегося на хранимой процедуре SQL, возвращает и устанавливает параметры хранимой процедуры. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.StoredProcParam(uHcteKC_napaMempa)[= новый_параметр]
136 Свойства элемента управления Crystal Например: ' Установить для первого параметра хранимой процедуры ' дату 14 июня 1996 года CrystalReportl.StoredProcParam(O) = "06/14/1996" Это свойство устанавливает значение специфицированного параметра в таблице базы данных SQL, которая базируется на хранимой процедуре. Значение параметра, который требуется установить, передается как строка, даже если для параметра ожидается другой тип данного. Например, при передаче целого значения 396 используется строковый параметр "396". Преоб¬ разованием значения в целочисленный формат управляет процессор Crystal Reports Engine. Доступность свойства: только период выполнения. UserName Вводит имя, данное пользователю для регистрации доступа к защищенному файлу .mdb, который должен использоваться в отчете. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.UserName[= имя] Например: CrystalReportl.UserName = "Волков" Особенности свойства: имя должно быть заключено в кавычки. Доступность свойства: период выполнения. WindowBorderStyle Определяет тип окантовки для окна печати. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowBorderStyle[= стиль_окантовки] Например: ' Установить масштабируемый стиль окантовки (Стиль #2) CrystalReportl.WindowBorderStyle = 2 Для окна печати может быть установлен один из следующих стилей окантовки: Стиль Описание Константа 0 Нет (создает окно без окантовки). CrptNoBorder 1 Fixed Single (создает окно фиксированного раз¬ мера с одинарной окантовкой). crptFixedSingle 2 Масштабируемое окно (создает окно, размер которого может изменяться пользователем). crptSizeable 3 Fixed Double (создает окно фиксированного размера с двойной окантовкой). crptFixedDouble Доступность свойства: разработка, выполнение. WindowControlBox Определяет, должно ли окно печати иметь в верхнем левом углу управляющее (системное) меню. Применение в коде Visual Basic в период выполнения:
Гпава 5. Создание отчетов с помощью Crystal Reports 137 [gbopMa.]CrystalReport.WindowControlBox[= {True\False}] Например: CrystalReportl.WindowControlBox = True ' Системное меню есть Особенности свойства: • выбрать True, если требуется, чтобы окно содержало управляющее меню. Иначе — False; • значения свойства имеют смысл, только если печать отчета направляется в окно (свой¬ ство Destination = 0). Доступность свойства: разработка, выполнение. WindowControls Определяет, должно ли окно Preview при печати отчета иметь элементы управления печати. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.WindowControls[=7>ue|Fa/se] Например: ' Элементы управления печати в окне Preview должны быть CrystalReportl.WindowControls = 1 Доступность: разработка, выполнение. WindowHeight Устанавливает высоту окна печати, когда вывод отчета направлен в окно. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowHeight[= высота] Например: ' Установить высоту окна печати равной 30 0 пикселей CrystalReportl.WindowHeight = 300 Особенности свойства: значение свойства имеет смысл, только если печать направляется в окно (если свойство Destination = 0). Доступность свойства: разработка, выполнение. WindowLeft Устанавливает расстояние в пикселях от левого края родительского окна до окна печати. Если окно печати — окно верхнего уровня, то расстояние измеряется от левого края экрана. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowLeft[= расстояние] Например: ' Установить расстояние левого края окна печати в 100 пикселей ' от левого края экрана CrystalReportl.WindowLeft = 100 Особенности свойства: значение свойства имеет смысл, только если печать направляется в окно (если свойство Destination = 0). Доступность свойства: разработка, выполнение.
138 Свойства элемента управления Crystal WindowMaxButton, WindowMinButton Определяют, соответственно, должно ли окно печати при печати отчета иметь кнопку Maximize и Minimize. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowMaxButton[= {True\False}] [gbopMa.]CrystalReport.WindowMinButton[= {True\False}] Например: CrystalReportl.WindowMaxButton = False ' Кнопки Maximize ' не должно быть CrystalReportl.WindowMinButton = True ' Окно должно иметь ' кнопку Minimize Особенности свойств: значение свойств WindowMaxButton и WindowMinButton имеет смысл, только если печать направляется в окно (если свойство Destination = 0). Доступность свойств: разработка, выполнение. WindowParentHandle Определяет дескриптор родительского окна, если окно печати должно быть потомком другого окна. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowParentHandle[= дескриптор] Например: CrystalReportl. WindowParentHandle = Forml.hWnd Здесь для свойства WindowParentHandle устанавливается дескриптор Form1. Этим опреде¬ ляется, что окно печати должно быть потомком формы Form1. Доступность свойства: период выполнения. WindowState Устанавливает состояние окна Preview: нормальное, минимизированное или максимизиро¬ ванное, когда отчет выводится в окно Preview. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowState[= состояние] Например: ' При печати отчета — максимизировать окно Preview CrystalReportl.WindowState= 2 Для установки свойства WindowState можно использовать следующие значения: Значение Описание Константа 0 Окно Preview не является ни минимизированным, ни макси¬ мизированным. При открытии оно имеетумолчательный раз¬ мер и позицию, ранее определенную приложением или Windows. crptNormal
Гпава 5. Создание отчетов с помощью Crystal Reports 139 Значение Описание Константа 1 Окно Preview выводится минимизированным в виде пиктог¬ раммы в нижнем левом углу экрана. Пиктограмма может быть расширена с переводом окна в нормальное (0) состоя¬ ние. crptMinimized 2 Окно Preview максимизировано и заполняет весь экран. crptMaximized Доступность свойства: разработка, выполнение. WindowTitle Определяет заголовок в титульной строке окна печати при выводе отчета в окно. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowTitle[= заголовок] Например: CrystalReportl.WindowTitle = "Квартальные обороты" Особенности свойства: • заголовок окна необходимо заключать в кавычки; • значение свойства WindowTitle имеет смысл, только если печать направляется в окно (если свойство Destination = 0). Доступность свойства: разработка, выполнение. WindowTop Устанавливает расстояние в пикселях от края окна печати до верхнего края родительского окна. Если окно печати — окно верхнего уровня, расстояние измеряется от верхнего края экрана. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowTop[= расстояние] Например: ' Установить равным 100 пикселей расстояние от верхнего края окна ' печати до верхней части экрана CrystalReportl.WindowTop = 100 Особенности свойства: значение свойства WindowTop имеет смысл, только если печать направляется в окно (если свойство Destination = 0). Доступность свойства: разработка, выполнение. WindowWidth Определяет ширину окна печати в пикселях. Применение в коде Visual Basic в период выполнения: [gbopMa.]CrystalReport.WindowWidth[= ширина] Например: CrystalReportl.WindowWidth = 480 ' Установить ширину окна печати ' в 48 0 пикселей
140 Методы элемента управления Crystal Значение свойства WindowWidth имеет смысл, только если печать направляется в окно (если свойство Destination = 0). 5.6. Методы элемента управления Crystal PrintReport Инициирует печать отчета. Применение в коде Visual Basic в период выполнения: [qbopMa.]CrystalReport.PrintReport Например: ' Распечатать специфицированный отчет Result = CrystalReportl.PrintReport отчет Особенности метода: • метод PrintReport возвращает код результата 0, если вызов успешен, и код ошибки в интервале 20XXX, если печать терпит сбой; • печатать отчет можно также, используя свойство Action. Однако, если что-то отрабаты¬ вает неправильно, во время выполнения программы возвращается ошибка, которая завершит приложение. Для обработки таких ситуаций необходимо ввести процедуру обработки ошибок.
Гпава 6. Работа с библиотеками динамической компоновки 141 Главаб. Работасбиблиотеками динамической компоновки Одно из самых больших преимуществ использования Visual Basic — в том, что с его помощью можно создавать сложные приложения для Windows, совершенно не вникая в тонкости интерфейса программирования приложений Windows (API). Если требуется, чтобы приложение включало функциональные возможности, которые не обеспечиваются Visual Basic, можно использовать библиотеки динамической компоновки Windows (DLL) для обращения непосредственно к Windows API. Например, можно использовать DLL при создании формы, которая всегда остается на экране поверх остальных форм, даже когда не имеет фокуса. В этой главе показано, как использовать DLL для расширения функциональных возможно¬ стей приложения Visual Basic, объясняются базовые шаги объявления и вызова процедур DLL и другие вопросы. 6.1. Обзор DLL Библиотеки DLL могут обеспечивать разработчика многими возможностями, которые в Visual Basic непосредственно не доступны. Библиотека динамической компоновки — набор процедур, внешних по отношению к приложению, которые могут вызываться из приложения. DLL не связаны с исполняемым файлом приложения; они могут компоноваться с ним в период выполнения вместо загрузки во время компиляции. Библиотеки могут обновляться независимо от приложения, и несколько приложений могут совместно использовать одну и ту же DLL. 6.1.1. Преимущества использования DLL С помощью DLL можно: • решать задачи, которые невозможно решить средствами Visual Basic; • повышать производительность приложения. Код в DLL часто выполняется быстрее, чем код Visual Basic. Для процедур, в которых требуется высокая скорость выполнения, можно написать DLL и затем вызывать DLL из Visual Basic; • модификация независимо от приложения. DLL можно модифицировать без перекомпиля¬ ции приложения, которое вызывает DLL. Это облегчает сопровождение приложения. 6.1.2. Библиотеки Windows API Windows обеспечивает ряд полезных DLL, которые можно вызывать H3Visual Basic. Эти DLL создают интерфейс программирования приложений Windows (Windows API). 32-разрядные версии операционной системы Windows (Windows 95 и Windows NT) состоят из трех основных DLL: User32, GDI32 и Kernel32. Эти DLL обеспечивают большую часть функциональных возможностей Windows API: User32 Модули библиотеки User32.dll решают задачи, связанные с управлением окнами, меню, элементами управления и окнами диалога. Например, про¬ цедура FlashWindow в User32.dll обусловливает вывод окна. GDI32 Библиотека GDI32.dll отвечает за вывод графики.
142 Обзор DLL Kernel32 Библиотека Kernel32.dll управляет задачами операционной системы. На¬ пример, в Kernel32.dll можно вызвать процедуру GetWindowsDirectory, что¬ бы получить текущий путь папки Windows. В дополнение к этим трем DLL Windows 95 и Windows NT содержат много других библиотек, которые обеспечивают расширение функциональных возможностей Visual Basic. 6.1.3. ИспользованиеАР! Viewer Отобрать соответствующие объявления для процедур Windows API можно с помощью утилиты API Viewer (Apiload.exe), поставляемой с Visual Basic. При загрузке текстового файла API, такого, как файл Win32api.txt, API Viewer читает файл и выводит на экран константы, типы и операторы Declare для процедуры в Windows API. В API Viewer можно скопировать объявление в буфер обмена и затем вставить его в приложение Visual Basic. Рис. 6.1. Окно API Viewer. 6.1.4. Загрузка объявления из базы данных Для ускорения поиска определенных объявлений DLL лучше загрузить и просматривать файл базы данных (.mdb), чем искать вхождение в текстовом файле (.txt). API Viewer позволяет либо загрузить и просмотреть текстовый файл API, либо преобразовать его в файл базы данных формата Jet. Преобразованный файл базы данных .mdb можно будет загружать всякий раз при использовании API Viewer.
Гпава 6. Работа с библиотеками динамической компоновки 143 6.1.5. Использование DLL с Visual Basic При использовании процедуры DLL имеется два базовых шага: 1. С помощью оператора Declare сообщить Visual Basic, какую процедуру требуется исполь¬ зовать. 2. Вызвать процедуру DLL из соответствующего места в программном коде. Эти шаги обсуждаются ниже. 6.2. Объявление процедуры DLL Процедуры DLL располагаются во внешних по отношению к приложению Visual Basic файлах, поэтому, прежде чем можно будет вызывать процедуру, ее необходимо объявить. Объявление процедуры обеспечивает Visual Basic информацией, необходимой для нахож¬ дения и выполнения процедуры. При объявлении процедуры DLL оператор Declare следует поместить в разделе Declarations формы, стандартного модуля или модуля класса. Если DLL объявляется в стандартном модуле, процедура DLL — Public по умолчанию и может вызываться кодом отовсюду в приложении Visual Basic. Чтобы ограничить область определения процедуры DLL формой или модулем класса, в объявлении необходимо поместить ключевое слово Private. Синтаксис оператора Declare: [Public|Private] Declare Sub имя Lib "имя_библиотеки" [Alias "имя_псевдонима"] [(список_параметров)] или [Public|Private] Declare Function имя Lib "имя_библиотеки" [Alias "имя_псевдонима"] [(список_параметров)] [As тип] Элементы оператора Declare: Элемент Описание имя Имя процедуры, используемой в коде. Lib "имя_библиотеки" Имя библиотеки, в которой находится процедура. Если постро¬ ена пользовательская DLL, специфицируется ее имя. Напри¬ мер: Function Declare AddNum Lib "c:\add.dll" (ByVal a as long) As long. Если полный путь к DLL не специфицируется, DLL должна находиться на пути системной переменной PATH. список_параметров Параметры, требуемые процедурой. Тип данных каждого пара¬ метра должен соответствовать типуданного, специфицирован¬ ного в объявлении. Параметр может быть передан по значению или по ссылке. Alias "имя_псевдонима" Если DLL содержит имя, которое представляет недопустимый идентификатор в Visual Basic, то для идентификации вызывае¬ мой процедуры можно использовать ключевое слово Alias. Клю¬ чевое слово Alias определяет альтернативное имя используемой процедуры. В следующем примере объявляется процедура API AccessCheckAndAuditAlarm: ' Поместить в раздел General Declarations стандартного модуля .BAS Declare Function AccessCheckAndAuditAlarm Lib "advapi32.dll" Alias "AccessCheckAndAuditAlarmA" _
144 Объявление процедуры DLL (ByVal SubsystemName As String, HandleId As Any, ByVal ObjectTypeName As String, ByVal ObjectName As String, SecurityDescriptor As SECURITY_DESCRIPTOR, _ ByVal DesiredAccess As Long, GenericMapping As GENERIC_MAPPING, _ ByVal ObjectCreation As Long, GrantedAccess As Long, ByVal AccessStatus As Long, ByVal pfGenerateOnClose As Long) As Long 6.2.1. Преобразование объявлений С в типы AaHHbixVisual Basic Обычно процедуры DLL пишутся на языке программирования С, поэтому их параметры определяются типами данных С. Когда используется оператор Declare для DLL в Visual Basic, необходимо спроецировать типы данных параметров на типы данных С. В следующей таблице перечислены обычно используемые объявления языка С и их экви¬ валенты Visual Basic для 32-разрядных компиляторов: Объявление языка С Объявление Visual Basic Вызов Указатель на строку (LPSTR) ByVal <переменная> As String с переменной String или Variant NULL ByVal <переменная> As String с константой VbNullString char ByVal <переменная> As Byte с выражением, которое оценива¬ ется как тип данного Byte lnteger ByVal <переменная> As Long с выражением, которое оценива¬ ется как тип данного Long Дескриптор Windows (hWnd, hDC, hMenu) ByVal <переменная> As Long с выражением, которое оценива¬ ется как тип данного Long Примечание: В 16-разрядных компиляторах С тип данного int соответствует типу данного lnteger Visual Basic. В 32-разрядных компиляторах С тип данного int соответствует типу данного Long Visual Basic. 6.2.2. Гибкиетипы параметров В DLL тип данного параметра определяет тип данного, возвращаемого процедурой. Однако в Visual Basic можно определять процедуру таким образом, чтобы параметр мог принимать любой тип данных. Для объявления параметра, который может принимать более одного типа данного, можно использовать тип данного Any; при этом Visual Basic не будет выполнять контроль соответ¬ ствия типов и позволит передавать для этого параметра переменную любого типа. Примечание: Используя предложение Alias, можно объявить DLL дважды и в каждом объявлении обеспечить явные типы данных, чтобы избежать синтаксиса Any. Использование явных типов данных гарантирует, что, если передается параметр неправильного типа данного, возвращается ошибка компиляции, а не ошибка выполнения. Следует, однако, удостовериться, что DLL может принимать параметр такого типа данного. Если передается неправильный тип данного, обраще¬ ние к DLL может обусловить блокировку по общей защите. 6.2.3. Библиотеки ANSI и Unicode Каждая процедура Win32 API, которая принимает в качестве параметра строку, реализуется в двух версиях: в символьном наборе ANSI и Unicode. В ANSI каждый символ представлен одним байтом. В Unicode для представления каждого символа используются два байта.
Гпава 6. Работа с библиотеками динамической компоновки 145 Трансляция между ANSI и Unicode В Visual Basic версии 5.0 для хранения строк внутренне используется символьный набор Unicode. Однако при вызове функции в Win32 API необходимо использовать версию ANSI функции API. При вызове процедуры DLL Visual Basic автоматически преобразует строку в код ANSI. При возвращении из процедуры DLL Visual Basic транслирует строку обратно в Unicode. Функции Windows API обычно именуются с суффиксами ’А’ и ’W’ для ANSI и Wide (Unicode) соответственно. При вставке оператора Declare из API Viewer будет получено правильное имя функции ANSI. Например, чтобы использовать функцию Win32 API SetWindowText, правильным будет объявление: Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" _ (ByVal hwnd As Long, ByVal lpString As String) as Long Хотя приложение Visual Basic вызовет SetWindowText, фактически будет вызвана версия ANSI функции, SetWindowTextA. 6.3. Вызов DLL После объявления процедуры ее можно вызывать точно так же, как если бы это была процедура Visual Basic, как показано в следующем операторе: result = AccessCheckAndAuditAlarm(Subsysteml,, Objectl) Примечание: Если функция объявлена в модуле, для вставки вызова процедуры в коде приложения можно использовать Object Browser. При вызове процедуры DLL имеется несколько аспектов, связанных с передачей парамет¬ ров. Они включают: • передача в процедуру DLL пустого значения; • выбор передачи параметров с их значением или по ссылке на это значение; • обеспечение в Visual Basic строк, размер которых достаточен для размещения строк С. В этом разделе освещаются некоторые различия в обработке значений параметров в процедурах Visual Basic и Windows API. 6.3.1. Передача нулевыхзначений Когда процедура DLL принимает параметр с пустым значением, она ожидает нулевое значение (0) вместо пустой строки (NULL). Чтобы передать пустое значение, следует объявить параметр ByVal As String и передать константу vbNullString, как показано в следу¬ ющем примере: Declare Function FindWindow Lib "User32" Alias "FindWindowA" _ (ByVal lpClassName As String, ByVal lpCaption As String) As Integer rc = FindWindow (vbNullString, "Microsoft Word") Примечание: В Visual Basic версии 3.0 единственым способом передать пустое значение было ByVal 0&. Если использовались DLL, которые требовали строку или NULL, нужно было либо объявить параметр As Any, либо объявить DLL дважды, один раз с параметром String и второй раз — с параметром Long.
146 Вызов DLL Начиная с Visual Basic 4.0, можно объявлять параметр как String и передавать стандартную константу Visual Basic vbNullString. 6.3.2. Передача параметров по значению и по ссылке Visual Basic передает параметры процедурам по ссылке, используя 32-разрядный адрес значе¬ ния данного, или по значению, используя фактическое значение переменной параметра. По умолчанию, Visual Basic передает параметры по ссылке. Однако многие процедуры DLL ожидают, что параметры будут переданы по значению. Если параметр передается непра¬ вильно (например, если передается значение в процедуру, которая ожидает адрес), это может обусловить блокировку по общей защите. Передача параметров по значению При передаче параметра по значению процедуре передается копия оригинального значения данного. Если процедура изменяет значение, на оригинальную переменную это изменение не воздействует. Чтобы передать параметр по значению, необходимо в операторе Declare передобъявлени- ем параметра поместить ключевое слово ByVal, как показано в следующем фрагменте: Declare Function FlashWindow Lib "User32" (ByVal hwnd as Long, ByVal bInvert As Long) As Long Передача параметров по ссылке При передаче параметра по ссылке в процедуру передается адрес памяти оригинальной переменной. Если процедура изменяет значение этой переменной, оригинальное значение также изменяется. В объявлении процедуры можно специфицировать ByVal или ByRef. Если ключевое слово не специфицируется, Visual Basic автоматически передает параметры по ссылке. Хотя включать ByRef в объявлении не требуется, текст кода будет более читабельным, если явно используется или ByRef, или ByVal. 6.3.3. Передача строковых значений Строковые типы данных в Visual Basic хранятся в формате, отличном от эквивалентных типов данных языка С. Большинство DLL и все процедуры в Windows API распознают формат строки языка С. При передаче строковых значений в Visual Basic необходимо учитывать эти различия, объявляя строковые параметры по значению, принимая во внима¬ ние при этом различия в длине строковых значений. Объявление строковых параметров по значению Если процедура DLL ожидает в качестве параметра строку формата С, необходимо объя¬ вить параметр Visual Basic как String, которому предшествуют ключевое слово ByVal. Значение строковой переменной — это фактически указатель на область в памяти, которая содержит строку. Следовательно, процедура DLL может изменять строковую переменную Visual Basic, полученную как параметр. Учет различий в длине строк DLL не может увеличить длину строки Visual Basic и производит запись вне конца строки, если она недостаточно длинная. Чтобы обеспечить достаточно пространства для строки любой длины, можно использовать один из следующих методов:
Гпава 6. Работа с библиотеками динамической компоновки 147 Заполнить символьную строку максимальным ожидаемым числом символов: Dim FilePath As String FilePath = String (255, 0) Определить строку фиксированной длины с максимально возможной длиной: Dim FilePath As String * 255 Строки, возвращаемые процедурой DLL, в конце строки содержат символ пробела. При объединении нескольких строк потребуется удалять этот символ пробела. Так как имеются процедуры, которые возвращают целое число, указывающее длину строки, можно либо использовать функцию Left, чтобы удалить символ пробела, либо искать символ пробела, используя Chr(0). Пример передачи строкового значения Процедура GetWindowsDirectory используется для возвращения пути папки Windows. При этом для пути папки Windows необходимо обеспечить пустую строку достаточной длины, чтобы принять самое длинное возможное имя папки. Процедура GetWindowsDirectory возвращает целое число, которое указывает фактическое число символов в изменяемой строке. Эта строка будет содержать NULL в качестве послед¬ него символа. NULL можно удалить, найдя его или используя функцию Left, как показано в следующем примере: Declare Function GetWindowsDirectory Lib "Kernel32" Alias "GetWindowsDirectoryA" (ByVal f as String, ByVal fLen as Long) As Long Sub Commandl Click () Dim sWinDir As String Dim lLen As Long sWinDir = String(255,0) lLen = GetWindowsDirectory(sWinDir, Len(sWinDir)) sWinDir = Left(sWinDir, lLen) sWinDir = sWinDir + "\" MsgBox "Windows находится в " + sWinDir End Sub 6.4. Дополнительная информация по DLL В этом разделе дается информация по использованию DLL, которая выходит за рамки базовых способов объявления и вызова процедур DLL. Знакомство с этими механизмами использования процедур DLL будет весьма полезным при создании приложений Visual Basic. 6.4.1. Процедуры обратного вызова DLL может сообщать или давать информацию клиенту, вызывая подпрограмму, обеспечи¬ ваемую клиентом. Эта подпрограмма клиента известна как функция обратного вызова. В течение одного вызова Windows API эта функция обратного вызова может вызываться несколько раз. Процедуры-перечисления, в которых перечисляется набор элементов, являются общим приме¬ ром DLL, использующих функции обратного вызова для передачи информации клиенту.
148 Дополнительная информация по DLL Обратные вызовы в Visual Basic Visual Basic позволяет создавать процедуры обратного вызова, которые обеспечивают сообщение клиенту. Например, можно создать процедуру обратного вызова, которая будет посылать сообщение клиенту каждый раз, когда сервер выполнит некоторую операцию. Затем для вызова этой процедуры используется DLL. На следующей иллюстрации показано, как процедуры обратного вызова работают в Visual Basic: Описание процедуры обратного вызова Передача адреса обратного вызова Сохранение обратного вызова Вызов процедуры обратного вызова Рис. 6.2. Обратные вызовы в Visual Basic. Передача процедуры обратного вызова KDLL Для передачи процедуры обратного вызова к DLL Visual Basic использует операцию AddressOf. Процедура обратного вызова должна быть размещена в стандартном модуле и иметь правильный синтаксис. Нахождение точного синтаксиса для процедуры обратного вызова может быть довольно трудной задачей, так как обычно указания на этот счет можно найти только в документации к DLL. Использование правильного синтаксиса важно, так как Visual Basic не обеспечивает контроль синтаксиса и ничего не сообщает относительно ошибок. Примечание: Использование неправильного синтаксиса в процедуре обратного вызова наиболее вероятно обусловит в приложении фатальную ошибку в период выполнения. При специфицировании обратных вызовов из Visual Basic следует убедиться в том, что выполнены следующие два требования: • функция обратного вызова должна быть размещена в стандартном модуле; • для передачи процедуры обратного вызова к DLL должна использоваться операция AddressOf. Function Callback1(..) End Function Sub Routine10 SetCall1(.... AddressOf Callback1) End Sub SetCall1 (..., lpCallback1) { ' Сохранить адрес обратного ‘вызова Callback1 =lpCallback1 1 // Вызов процедуры обратного // вызова Cailback1 (...) Приложение Visual Basic DLL
Гпава 6. Работа с библиотеками динамической компоновки 149 Объявление функции Windows API содержит функцию EnumChildWindows, которая перечисляет все окна-потомки родительского окна. Объявление функции следующее: Declare Function EnumChildWindows Lib "user32" Alias "EnumChildWindows" (ByVal hWndParent As Long, ByVal lpEnumFunc As Long, ByVal lParam As Long) As Boolean Первый параметр — hWndParent — требует дескриптора родительского окна. Второй пара¬ метр — lpEnumFunc — требует адреса процедуры обратного вызова. Третий параметр — любое 32-разрядное значение, которое хочет передать клиент. Это значение впоследствии будет передано в функцию обратного вызова. Написание обратного вызова В следующем примере показано, как подпрограмма обратного вызова оформляется в Visual Basic: Public Function EnumProc(ByVal hWndChild as Long , ByVal lParam As Long) As Boolean ' Выполнение некоторой обработки End Function Вызов DLL Далее следует вызвать процедуру-перечисление и затем специфицировать процедуру обратного вызова, используя onepa4HioAddressOf, как показано в следующем примере: EnumChildWindows forml.hWnd, AddressOf EnumProc, 0 6.4.2. Использование процедур-оболочек Если приложение неоднократно вызывает некоторую DLL, для ее вызова можно создать процедуру, вместо неоднократного вызова непосредственно DLL. Эта процедура, известная как процедура-оболочка, по своему назначению и действию подобна централизованной процедуре обработки ошибок. Использование процедуры-оболочки для вызова DLL упро¬ щает приложение, консолидируя вызовы и изолируя подробности использования DLL. Написание процедуры-оболочки В следующем примере функция GetWinDirBbi3biBaeT подпрограммуАР! GetWindowsDirectory: Public Function GetWinDir () As String sWindir = String(255,0) lLen = GetWindowsDirectory (sWindir, Len(sWinDir)) sWinDir = Left (sWinDir, lLen) GetWinDir = sWinDir End Function Каждый раз, когда требуется определить папку Windows, вызывается функция GetWinDir. Вызов процедуры DLL В следующем фрагменте GetWinDir, которая фактически представляет вызов подпрограм¬ мы API, внедрена в процедуру Click (): Sub cmdGetWin_Click () Msgbox GetWinDir End Sub
150 Дополнительная информация по DLL 6.4.3. Полезные DLL Ниже перечислены некоторые процедуры Windows API, которые могут быть полезны при написании приложения Visual Basic. Также приводится пример использования процедуры Windows API SetWindowPos для создания окна в режиме "Поверх остальных". Часто применяемые процедуры Windows API Процедура Windows API Назначение BitBlt Перемещает растровый рисунок из контекста исходного уст¬ ройства в адресат. Extractlcon, Drawlcon, Loadlcon Манипулирует пиктограммами. FindExecutable Находит и отбирает имя исполняемого файла, ассоцииро¬ ванного с файлом определенного формата. GetSystemDirectory Возвращает путь системного каталога Windows. GetSystemMetrics Возвращает ширину и высоту элементов отображения в Microsoft Windows. GetTempFileName Возвращает имя и путь временного файла, используя сис¬ темную переменную TEMP. GetWindowPlacement, SetWindowPlacement Возвращает или устанавливает состояние, а также позиции нормального (восстановленного), минимизированного и мак¬ симизированного окна. SendMessage Передает сообщения Windows для управления приложени¬ ем. Например, сообщение LB_SETTABSTOPS устанавлива¬ ет табулостопы в простом списке. LB_FINDSTRING находит первую строку в списке, которая соответствует указанному тексту. Здесь также доступны сотни других сообщений. BringWindowT oT op, SetActiveWindow Устанавливает фокус на определенное окно. DragAcceptFiles, DragFinish Поддерживает функции технологии drag-and-drop. FindWindow, ShowWindow Проверяет, выполняется или нет в данный момент специфи¬ цированное приложение. GetActiveWindow, lsWindow Определяет, когда функция системной оболочки заканчивает загружать программу. GetWindowText Возвращает заголовок окна или текст в элементе управле¬ ния, специфицируемым дескриптором окна. Использование функции SetWindowsPos Функция SetWindowPos API создает окно (или форму), которое остается поверх других окон, даже если не имеет фокуса. Чтобы можно было использовать функцию SetWindowPos, необходимо объявить соответст¬ вующие константы. С помощью API Viewer из текстового файла Win32api.txt можно скопиро¬ вать константы HWND_TOPMOST, SWP_NOSIZE и SWP_NOMOVE. Пример использования функции SetWindowPos для создания окна "Поверх остальных" см. ниже.
Гпава 6. Работа с библиотеками динамической компоновки 151 6.4.4. Пример: Нахождение расположения папки Windows В этом примере для нахождения папки, которая содержит файлы Microsoft Windows, исполь¬ зуется функция Windows API GetWindowsDirectory. 1. Создать новый проект Standard EXE. 2. Добавить к форме элементы управления, как показано на рис. 6.3. 3. Добавить к проекту стандартный модуль. 4. В окне API Viewer скопировать оператор Declare для GetWindowsDirectory. 5. Вставить оператор Declare в новый модуль. ' Объявление DLL в стандартном модуле Declare Function GetWindowsDirectory Lib "kernel32" Alias "GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize As Long) As Long 6. Создать процедуру обработки события Click для кнопки "Директория Windows". 7. В процедуре события добавить код, который выводит путь к папке Windows в окне сообщения: Private Sub cmdWinDir Click() Dim WinDir As String Dim ReturnSize As Long WinDir = String(255, 0) ' Заполнение строки нулями ' Вызов API для получения каталога Windows и фиксация ' размера возвращенной строки ReturnSize = GetWindowsDirectory(lpBuffer:=WinDir, nSize:=Len(WinDir)) ' Усечь строку до правильного размера WinDir = Left(WinDir, ReturnSize) MsgBox "Директория Windows: " & WinDir End Sub Рис. 6.3. Форма и сообщение сдиректорией Windows. 6.4.5. Пример: Создание окна "Поверх остальных" В этом примере используется функция Windows API SetWindowPos для создания окна или формы, которая остается поверх других окон независимо от текущего фокуса.
152 Дополнительная информация по DLL 1. Создать новый проект. 2. Добавить к форме элементы управления, как показано на рис. 6.4. 3. Добавить к проекту стандартный модуль. 4. В API Viewer скопировать требуемые константы (HWND_TOPMOST, SWP_NOSIZE и SWP_NOMOVE) и оператор Declare для функции SetWindowPos. 5. Вставить оператор Declare в новый модуль. Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Long, _ ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal у As Long, ByVal cx As Long, ByVal су As Long, ByVal wFlags As Long) As Long Const HWND_TOPMOST = -1 Const HWND_NOTTOPMOST = -2 Const SWP_NOSIZE = 1 Const SWP_NOMOVE = 2 Dim flags As Integer 6. Создать процедуры обработки событий для переключателей "Поверх остальных" и "Не поверх остальных". Private Sub optNonTopmost Click() SetWindowPos frmTopmost.hwnd, ' Имя формы - frmTopmost HWND_NOTOPMOST, 0, 0, 0, 0, FLAGS End Sub Private Sub optTopmost Click() SetWindowPos frmTopmost.hwnd, HWND_TOPMOST, 0, 0, 0, 0, FLAGS End Sub Рис. 6.4. Форма "Поверх остальных" и "Не поверх остальных".
Гпава 7. СОМ и создание клиентов ActiveX 153 Глава 7. СОМ и создание клиентов ActiveX Компонентная Объектная Модель (СОМ) — архитектура промышленного стандарта для объектно-ориентированной разработки приложений и основа для формирования компонен¬ тов ActiveX. Компонент ActiveX — физический файл (например, .exe, .dll, .ocx), который содержит классы, представляющие определения объектов. Эти объекты можно подключать и использовать в приложении Visual Basic. Компоненты ActiveX позволяют программистам объединять в приложении порции кода многократного использования. Для решения общих задач, таких, как числовой анализ или формирование элементов пользовательского интерфейса, разработчик может создавать свои собственные компонен¬ ты ActiveX или использовать подключаемые компоненты Microsoft или сторонних разработ¬ чиков. При создании в приложении пользовательских решений можно объединять компоненты ActiveX с общими компонентами. Эта глава — первая из четырех глав, в которых показывается, как реализовать ActiveX-ком- понентные приложения, используя встроенные возможности Visual Basic. В этой главе рассматривается сторона клиента, в следующих трех главах освещаются различные реали¬ зации на сервере. 7.1. Компонентная Объектная Модель Для формирования эффективных современных приложений-клиентов требуется иметь представление относительно компонентов сервера, используемых клиентом; требуется также понимание базовой технологии СОМ, посредством которой клиент соединяется с этими компонентами. С СОМ связаны два различных аспекта. Во-первых, спецификация СОМ обеспечивает определение (или модель) для объекта. Во-вторых, СОМ обеспечивает возможности для создания объектов и организации связи между клиентом и сервером. В этом разделе предлагается краткий обзор СОМ — мощного дополнения к комплекту инструментальных средств разработчика. Здесь описываются умолчательные интерфей¬ сы, обеспечиваемые объектами СОМ, показывается, как объекты поддерживают связь с клиентами и как использовать клиенты при создании и использовании экземпляра объекта. Для лучшего понимания СОМ полезно ознакомиться со следующими терминами и опреде¬ лениями: Компонент — единица исполняемого кода, которая предоставляет некоторые функцио¬ нальные возможности. Компоненты обеспечиваются серверами, которые представлены файлами .exe, .dll или .ocx. Серверы могут быть построены из одного или больше компонен¬ тов; компоненты обеспечивают шаблоны, из которых затем создаются объекты. Компонен¬ тная Объектная Модель определяет, как компоненты создаются и как приложения-клиенты соединяются с компонентами. СОМ также обрабатывает запросы из приложений-клиентов на создание объектов. Объект — комбинация кода и данных, которые могут обрабатываться как единица. Объект имеет период существования, то есть он создается и разрушается. Автоматика — часть спецификации СОМ, которая определяет стандартную методику создания компонентов и использования объектов. ОбъектАвтоматики — объект, который предоставлен другим приложением или инструмен¬ тальным средством программирования через интерфейсы Автоматики. Объекты Автоматики также известны как программируемые объекты. Программируемый объект может управлять¬ ся программным способом посредством его методов и свойств (интерфейс объекта).
154 Компонентная Объектная Модель Разработчику приложения-клиента объект предоставляет возможность ввода информации или запроса и обеспечивает вывод, но внутренняя организация объекта разработчику недоступна. Разработчики должны лишь понимать, как использовать предоставляемые объектом функциональные возможности. Эти функциональные возможности предоставля¬ ются через один или несколько интерфейсов. Интерфейсы — средства (свойства и мето¬ ды), посредством которых приложения-клиенты сообщаются с компонентом. 7.1.1. Краткая история СОМ Целью разработки идеологии СОМ было сделать приложения более настраиваемыми и гибкими, причем главной задачей была поддержка концепции, известной как связывание и внедрение объектов. Идея состояла в том, чтобы получать документ-ориентированное приложение, работая в котором, например, можно было бы редактировать электронную таблицу из текстового процессора. Версия Microsoft технологии связывания и внедрения объектов называется OLE. В первой версии OLE для поддержания связи между клиентом и компонентом использовалось нечто, именуемое DDE (Dynamic Data Exchange — динамиче¬ ский обмен данными). В OLE 1 ни о какой СОМ речи не шло. DDE был сформирован на верхнем уровне архитектуры передачи сообщений Windows. Технология DDE была далека от совершенства. DDE работает медленно и недостаточно гибко. Кроме того, трудно напи¬ сать код для DDE, который работает правильно. Эти серьезные недостатки свидетельство¬ вали о том, что поиски должны быть продолжены. Решением было СОМ. СОМ меньше по ресурсам, работает быстрее, значительно более устойчивая и гибкая чем DDE. Во второй версии OLE было модернизировано с использова¬ нием СОМ вместо DDE. Однако OLE было первой системой, разработанной на базе СОМ. В OLE не реализовано все то, что может обеспечить COM. OLE имеет репутацию системы, также работающей медленно и сложной в программировании. Впрочем, причина этих про¬ блем — в реализации OLE, это не результат использования СОМ. Все же следует помнить, что в OLE сделана попытка реализовать многие прежде недоступ¬ ные возможности. Посредством OLE можно помещать изображение из графической про¬ граммы одного разработчика в текстовый процессор другого разработчика и редактировать его, не покидая текстовый процессор. Протокол OLE определяет многофункциональную связь между клиентом и компонентом. Компонент может многое, а приложение-клиент должно быть к этому готово. Это, однако, делает OLE очень трудным в программировании. СОМ — не компьютерный язык и не конкурирует с ними. Рассуждения относительно того, что лучше: C++ или СОМ или наоборот, не имеет никакого смысла, так как перед СОМ и C++ стоят разные задачи. СОМ сообщает программисту, какстроить компоненты, и программист свободен в выборе языка, на котором он будет писать компоненты. Часто компоненты пишутся на C++. Сегодня это позволяет делать и Visual Basic. 7.1.2. Компонентные приложения Исполняемая часть приложения часто состоит из единственного монолитного двоичного файла. После того как компилятор генерирует приложение, оно не изменяется, пока не будет скомпилирована следующая версия. Изменения в операционных системах, аппарат¬ ных средствах и желаниях заказчика вынуждают разработчика вносить изменения и пере¬ компилировать приложение. В этих условиях разработчики должны искать способы продлить период существования уже созданных приложений. Решение состоит в том, чтобы разбить монолитное приложение на отдельные части, или компоненты (см. рис. 7.1.). По мере совершенствования технологий новые компоненты могут заменять существующие компоненты, формирующие приложение. Приложение — более не статичный объект, оно может развиваться с появлением более эффективных компонентов. Более того, из сущест¬ вующих компонентов может быть быстро построено полностью новое приложение.
Гпава 7. СОМ и создание клиентов ActiveX 155 Монолитное приложение Компонентное приложение Компонент А Компонент В Компонент С Компонент D Рис. 7.1. Разбиение монолитного приложения на компоненты позволяет упростить модернизацию приложения. Традиционно приложение разделялось на файлы, модули или классы, которые компилиро¬ вались и компоновались для создания приложения. Формирование приложений из компо¬ нентов — процесс несколько иной. Компонент подобен мини-приложению; он поставляется упакованным, как функциональная порция двоичного кода, которая скомпилирована, ском¬ понована и полностью готова к употреблению. Монолитное приложение уступает место группе компонентов, которые для формирования приложения соединяются друг с другом в период выполнения. Изменение или расширение приложения — простой вопрос замены одного из этих состав¬ ляющих компонентов его новой версией или другим компонентом. Разбиение монолитного приложения на компоненты поддерживается механизмами СОМ. Компонентное приложение Компонент А Компонент С Компонент В Новый Компонент D Рис. 7.2. Замена старого компонента новым, улучшенным компонентом. 7.1.3. Облегчение настройки приложения Пользователи часто хотят иметь возможность настраивать приложение под свои потребности и вкусы. В случае монолитного приложения конечный пользовательдолжен все время общаться с программистом, давая ему заявки на реализацию того или иного пользовательского решения. Компонентные архитектуры облегчают настройку приложения, так как каждый компонент может быть заменен на другой, который лучше удовлетворяет потребностям пользователя. Предположим, что имеются компоненты, основанные на графических редакторах Paint и Photo Shop. На рис. 7.3 Пользователь 1 сконфигурировал приложение, чтобы использовать Paint, в то время как Пользователь 2 предпочитает Photo Shop. Приложение может быть легко настроено добавлением новых компонентов или изменением существующих компонентов. Пользователь 1 Пользователь 2 Компонент А Компонент В Компонент С Компонент D Редактор Paint Компонент А Компонент В Компонент С Компонент D | Редактор Photo 5hop Рис. 7.3. Формирование приложения из компонентов облегчает настройку.
156 Компонентная Объектная Модель 7.1.4. Библиотеки компонентов Одно из больших преимуществ компонентной архитектуры — быстрая разработка приложе¬ ния. СОМ позволяет выбирать компоненты из библиотеки компонентов и складывать их вместе при формировании приложения, подобно строительным блокам. Рис. 7.4. Компоненты могут быть собраны в библиотеки, из которых разработчик может быстро создать приложение. Построение приложений из стандартных частей долгое время было неосуществимой меч¬ той разработчиков программного обеспечения. Однако с появлением элементов управле¬ ния ActiveX, ранее называвшихся элементами управления OLE, "процесс пошел". Программисты на Visual Basic, С, C++ и Java могут использовать преимущества элементов управления ActiveX для ускорения разработки своих приложений и Web-страниц. В прило¬ жениях, конечно, потребуется создавать также некоторые пользовательские компоненты, однако большая часть приложения может быть сформирована с использованием стандар¬ тных компонентов. 7.1.5. Распределенные компоненты С увеличением пропускной способности сетей и роли сетевых технологий потребность в приложениях, составленных из частей, доступных в сетевой системе, будет возрастать. Компонентная архитектура помогает упростить процесс разработки таких распределенных приложений. Эта архитектура уже реализуется в приложениях клиент/сервер, которые разделяются на две части: часть клиента и часть сервера. Создание распределенного приложения из существующего приложения упрощается, если существующее приложение сформировано из компонентов. Во-первых, приложение уже разделено на функциональные части, которые могут быть размещены дистанционно. Во- вторых, так как компоненты мобильны, можно заменить один компонент другим компонен¬ том, который имеет единственную задачу — взаимодействовать с компонентом, размещенным дистанционно. Например, на рис. 7.5 Компонент С и Компонент D размещены на разных удаленных машинах сети. На локальной машине они были заменены двумя новыми компонентами: Транслятор С и Транслятор D. Эти новые компоненты адресуют запросы из других компо¬ нентов по сети к Компоненту С и Компоненту D. Приложение на локальной машине не заботит то, что реальные компоненты размещены дистанционно. Аналогично, сами удален¬ ные компоненты также не беспокоит ихдистанционное размещение. Если имеется трансли¬ рующий компонент, приложение может быть полностью не осведомлено о том, где фактически размещен компонент.
Гпава 7. СОМ и создание клиентов ActiveX 157 Рис. 7.5. Компонентное приложение с удаленными компонентами. 7.1.6. Требования к компонентам Преимущества использования компонентов непосредственно вытекают из их способности динамически подключаться и отключаться из приложения. Для достижения этой возможно¬ сти компоненты должны отвечать двум требованиям. Во-первых, компоненты должны обес¬ печить возможность динамической компоновки. Во-вторых, компоненты должны скрывать (или инкапсулировать) подробности их реализации. Определить, какое требование являет¬ ся более важным, — значит решать проблему яйца и курицы. Каждое требование зависит от другого. Можно остановиться на таком определении: динамическая компоновка — опре¬ деляющее требование для компонента, а скрывание информации — необходимое условие для динамической компоновки. Ниже эти два требования исследуются более подробно. 7.1.7. Динамическая компоновка Для понимания важности динамической компоновки можно представить себе приложение, сформированное из компонентов, которые не могут связываться в период выполнения. Если нужно изменить один из компонентов в системе, потребуется статически повторно скомпоновать или перекомпилировать программу и затем перераспределить ее. Разработ¬ чик не может ожидать, что конечные пользователи его приложения смогут повторно скомпо¬ новать и скомпилировать приложение самостоятельно. Даже если бы они знали, как это делать, у них, наиболее вероятно, неоказалось бы требуемого компилятора. Приложение, созданное из компонентов, которые должны статически перекомпилироваться каждый раз при необходимости внести изменения, эквивалентно монолитному приложению. 7.1.8. Инкапсуляция Почему динамическая компоновка требует инкапсуляции? При формировании приложения компоненты соединяются друг с другом. Если требуется заменить компонент на новый компонент, необходимо отключить старый компонент от системы и затем подключить но¬ вый. Новый компонент должен подключаться тем же самым способом, что и старый компо¬ нент, иначе потребуется переписать код, перекомпилировать или повторно скомпоновать эти компоненты. В данном случае не имеет значения, поддерживают ли компоненты и приложение динамическую связь. Если изменяется способ соединения компонента с други¬ ми компонентами, нарушается система компонентов и, по крайней мере, придется переком¬ пилировать, если не переписать приложение. Для понимания, как все это связано с инкапсуляцией, нужно ввести некоторые определения. Программа или компонент, который использует другой компонент, называется клиентом. Клиент соединен с компонентом через интерфейс. Если компонент изменяется без изме¬ нения интерфейса, для клиента ничего не должно измениться. Аналогично, если изменяется клиент без изменения интерфейса, компонент не должен изменяться. Однако, если при изменении или компонента, или клиента изменяется интерфейс, другая сторона интерфей¬ са также должна измениться.
158 Компонентная Объектная Модель Следовательно, чтобы использовать преимущества динамической компоновки, компоненты и клиенты должны стремиться не изменять их интерфейсы. Они должны быть скрыты. Подробности относительно того, как реализованы клиент и компонент, не должны быть отражены в интерфейсе. Чем больше интерфейс изолирован от подробностей реализации, тем меньше вероятность того, что в результате изменения клиента или компонента изме¬ нится интерфейс. Если интерфейс не изменяется, изменение компонента не будет иметь никакого эффекта для остальной части приложения. Изоляция клиента от реализации компонента накладывает на компонент некоторые важные ограничения: 1. Компонент должен скрыть компьютерный язык, используемый для его реализации. Лю¬ бое приложение— клиент должно иметь возможность использовать любой компонент независимо от компьютерного языка, на котором написано приложение или компонент. Ориентация на какой-либо язык может создать новые зависимости между клиентом и компонентом. Это также обусловит трудности в дальнейшей эксплуатации клиента и компонента в случае перехода разработчиков на новые языки программирования: новые компоненты нельзя будет подключить к приложению для его модернизации. 2. Компоненты должны поставляться в двоичной форме. Так как компоненты должны скры¬ вать язык их реализации, они должны предоставляться в скомпилированном, скомпоно¬ ванном и готовом к использованию виде. 3. Компоненты должны быть расширяемы без влияний на существующих пользователей. Новые версии компонента должны работать как со старой, так и с новой версиями приложения-клиента. Установка новой версии компонента не должна нарушать приложение, которое исполь¬ зует старый компонент. Например, на рис. 7.6 старое приложение использует новый Компонент D точно так же, как новое приложение. Старое приложение Новое приложение Старый Компонент А Старый Компонент В Старый Компонент С Новый Компонент D Новый Компонент А Новый Компонент В Новый Компонент С Новый Компонент D Рис. 7.6. При модернизации приложения новые компоненты не должны нарушать работу старых компонентов. Однако обратная совместимость не должна ограничивать расширение компонента. Дол¬ жна быть обеспечена возможность радикально изменить поведение компонента для нового приложения при обеспечении работы старого приложения. 4. Расположение компонента в сети должно быть прозрачно (незаметно) для приложений- клиентов. Компонент и программа, которая его использует, должны работать в одном процессе, в разных процессах одной машины или на разных машинах. Клиент должен быть способен обработать удаленный компонент таким же образом, как он обрабатывает локальный компонент. Если удаленные компоненты должны обрабатываться иначе, чем локальные компоненты, клиент придется перекомпилировать всякий раз, когда локаль¬ ный компонент перемещается в другое место в сети.
Гпава 7. СОМ и создание клиентов ActiveX 159 7.1.9. Спецификация СОМ Спецификация СОМ определяет общую схему для создания компонентов. В то время как спецификация диктует "обязанности" компонента и требования к нему, она не специфици¬ рует, как эта функциональность должна быть реализована. Вместо этого спецификация СОМ определяет: • как из компонента создается объект; • как клиент обращается к возможностям, предоставляемым объектом; • ответственность объекта за уничтожение себя, когда он более не используется. Все эти действия обрабатываются интерфейсами, которые существенно упрощают исполь¬ зование возможностей сервера. До разработки компонентных технологий серверы часто предоставляли услуги клиентам через широкое разнообразие функций (не всегда должным образом организованных). Фун¬ кции, которые экспортировались сервером, детализировались в больших массивах доку¬ ментации, на изучение которой требовалось много времени и сил. Это обусловливало три главные проблемы: • приложения-клиенты должны были строиться с учетом особенностей и преимуществ сервера; • когда изменялся сервер, должен был, соответственно, изменяться клиент; • в возможностях серверов было трудно разобраться, так как в обеспечиваемых ими функциях не имелось никакой логической структуры. С помощью интерфейсов СОМ решает все эти проблемы. 7.1.10. Использованиеинтерфейсов Интерфейсы — группы функций, обеспечивающие логические пункты соединения, через которые компоненты клиента и сервера поддерживают связь. Интерфейсы обеспечивают стандартизованный доступ к методам и свойствам (функциональным возможностям), до¬ ступным из серверов. Далее, они представляют соглашение между автором компонента и разработчиком клиента, что гарантирует согласованный доступ к функциональным возмож¬ ностям. Наконец, они структурируют этот доступ, упрощая использование серверов. На следующей иллюстрации показано, как клиенты и компоненты сервера сообщаются через интерфейсы. Рис. 7.7. Взаимодействие клиента и компонентов сервера через интерфейсы. Объект может иметь несколько интерфейсов, которые обеспечивают доступ к различным функциональным возможностям для различных клиентов.
160 Компонентная Объектная Модель На следующей иллюстрации показан объект для работы с кредитной карточкой с двумя интерфейсами Розница и Кредит, которые обеспечивают различные возможности приложе¬ нию розничной продажи и приложению менеджера кредита — соответственно. База данных Рис. 7.8. Два различных интерфейса объекта. Интерфейс IUnknown Спецификация СОМ требует обеспечения следующих функциональных возможностей всех объектов: • объект должен быть способен отслеживать установленные с ним соединения. Если объект больше не используется, он должен быть способен уничтожить себя; • объект должен допускать запросы от клиентов на дополнительные интерфейсы, которые он может поддерживать. Для обеспечения этих возможностей все объекты имеют встроенный интерфейс, именуе¬ мый IUnknown. Интерфейс IUnknown должен поддерживаться каждым объектом СОМ. Каж¬ дый следующий интерфейс объекта должен включать функциональные возможности, обеспечиваемые IUnknown. Функции интерфейса IUnknown Интерфейс IUnknown имеет три функции — 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 (.exe файл). Взаимодействие между клиентом и компонентом in-process сервера обеспечивает наибо¬ лее эффективный обмен информацией. Так как клиент и компонент сервера совместно используют одно и то же адресное пространство, вызовы между ними передаются непос¬ редственно. Взаимодействие между клиентом и сервером out-of-process Схема взаимодействия между клиентом и компонентом out-of-process сервера более сложна, чем для сервера in-process, так как этосоединение должно пересечь границы процесса. В особенности это касается связи с исполняемым файлом на удаленном компьютере. Для управления этой связью СОМ-компилятор вставляет в приложение-клиент код полно¬ мочий (proxy), чтобы управлять вызовами сервера и их возвращаемыми значениями. При компиляции СОМ-сервера вставляется код фиктивного модуля, предназначенный для об¬ работки вызовов от кода полномочий клиента и значений, возвращаемых клиенту. Это управление параметрами и возвращаемыми значениями известно как маршаллинг. Маршаллинг— пакетирование всех параметров и возвращаемыхзначений и пересылка их через границу процесса. Иными словами, трансляция и передача параметров и возврат результатов при передаче вызовов в другое адресное пространство. На следующей иллюстрации показан поток информации от клиента к серверу через код полномочий и код фиктивного модуля. Рис. 7.9. Поток информации от клиента к серверу.
162 Реализация Автоматики Эта реализация межпроцессной связи независима от платформы, так как она основана на спецификации Вызова Удаленной Процедуры в Распределенной Вычислительной Среде (DCE-RPC). Вызовы между СОМ-компонентами могут производиться между Windows 95, Windows NT, UNIX и Macintosh, a также другими средами, поддерживающими DCE-RPC. COM, GUID и системный реестр При компиляции компонента для каждого public класса и интерфейса в компоненте созда¬ ются уникальные глобальные идентификаторы (GUID). Эти GUID — 128-битовые числа, которые генерируются с использованием алгоритма, гарантирующего их уникальность. Чтобы компонент стал доступным для клиентов, он должен зарегистрироваться в операци¬ онной системе. Компонент делает это, модифицируя раздел HKEY_CLASSES_ROOT сис¬ темного реестра, внося туда информацию относительно себя. Информация включает программный идентификатор (ProglD), представляющий описательное имя компонента, идентификатор класса (ClasslD), его расположение и расположение библиотеки типов. При компиляции приложения-клиента, который обращается к компоненту сервера, иденти¬ фикаторы классов и интерфейсов любого объекта, которые создает компонент, включаются в исполняемый файл. В период выполнения клиент (вместе с СОМ) использует информа¬ цию в реестре для вызова компонента сервера. Дополнительную информацию относительно реестра, отношений между приложениями- клиентами, СОМ и создания объектов см. ниже, в разделах "Библиотеки типов" и "Третий шаг: создание объектов". 7.2. Реализация Автоматики Автоматика (ранее была известна как OLE-автоматика) — технология манипулирования объектами, которые определены приложением или библиотекой вне приложения. В то время как СОМ представляет и спецификацию, и тип реализации, Автоматика — это часть СОМ, которая позволяет стандартным способом создавать и программировать объекты в приложении-клиенте. Автоматика работает через стандартный интерфейс, известный как IDispatch. Этот интер¬ фейс экспортирует любое количество свойств и методов, поддерживаемых объектом. Обычно клиент Автоматики может использовать любой компонент, который предоставляет интерфейс IDispatch. 7.2.1. Объекты Автоматики Объект Автоматики — любой тип объекта, который предоставляет приложениям-клиентам доступ ксвоим свойствам и методам. Свойства описывают характеристики объекта, такие, как имя, ширина или цвет фона. Свойства создаются с использованием public переменных или процедур Property. Методы — запросы к объекту на выполнение некоторых действий. Например, чтобы доба¬ вить элемент к списку, используется метод Addltem списка. События инициируют связь от объекта к клиенту. Вопросы событий рассматриваются в разде¬ лах 'Уведомление клиентов" и "Сообщения сервера с использованием обратных вызовов". 7.2.2. Библиотеки типов Клиенты получают информацию относительно объектов Автоматики от сервера, просмат¬ ривая библиотеку типов компонента сервера. Библиотека типов может поставляться в одной из следующих форм: как ресурс в DLL; как ресурс в .EXE файле; как подфайл внутри
Гпава 7. СОМ и создание клиентов ActiveX 163 файла составного документа или как автономный двоичный файл. Известные также как библиотеки объектных модулей, библиотеки типов обеспечиваютследующую информацию: • определения интерфейсов, поддерживаемых объектом; • описания свойств, методов и событий, обеспечиваемых объектом; • возвращаемые типы и типы параметров методов и событий объекта; • ссылки на описания типов в других библиотеках типов; • имена файла помощи и тем помощи, связанные с объектом и его методами и свойствами. Как и в случае с серверами, библиотеки типов регистрируются в операционной системе. Ключи для библиотеки типов размещены в папке TypeLib раздела HKEY_CLASSES_ROOT системного реестра. Библиотеки типов могут быть сохранены как часть .exe или .dll файла, который они описы¬ вают, или как отдельные файлы .olb или .tlb. Когда для создания компонента используется Visual Basic, библиотека типов встраивается в исполняемый файл. Использование окна Object Browser Object Browser — инструмент, который позволяет просматривать методы и свойства объек¬ та Автоматики. На рис. 1.7 показаны методы и свойства, доступные для объекта Project1. Список Проект/Библиотека показывает, что в данный момент в Object Browser просматрива¬ ется библиотека типов Project1. В панели Классы видно, что имеется два объекта, доступ¬ ных из Project1: Class1 и Form1. В панели Компоненты класса видно, что Class1 содержит два свойства (gsUser и User) и два метода (ShowDate и Squarelt). 7.2.3. Объектные модели Вместе СОМ и Автоматика облегчают программирование, так как в них используются интерфейсы для структурирования доступа к объектам и группируются методы и свойства. Но это лишь один из способов, которым Автоматика организует представление объекта. Объекты, которые предоставляет сервер, могут быть структурированы в объектную модель. Объектная модель определяет отношение среди объектов, доступных из сервера. Объект¬ ная модель организует объекты сервера в иерархию, которая отражает, какие объекты содержат другие объекты. Эта структура упрощает использование сервера. На следующей иллюстрации показано упрощенное представление объектов, доступных из Microsoft Excel. Рис. 7.10. Объектная модель Microsoft Excel.
164 Реализация Автоматики При создании приложений-клиентов важно понимание отношений между составляющими объектами (объектами, которые создаются автоматически с созданием другого объекта) и как они используются. В то время как некоторые из объектов создаются явно (с помощью ключевого слова New и метода CreateObject в Visual Basic), некоторые объекты создаются при вызове метода в другом объекте. Например, объект Application в Microsoft Excel созда¬ ется явно, в то время как содержащийся в нем объект Range — нет. Информацию относительно того, как создавать объектную модель, см. в разделе "Создание объектной модели" главы 8 "Создание программных компонентов ActiveX". 7.2.4. Интерфейс IDispatch Диспетчерский интерфейс, IDispatch, является стандартным интерфейсом Автоматики, разра¬ ботанным специально для предоставления методов и свойств компонента клиенту. Этот интер¬ фейс содержит четыре функции: GetTypelnfoCount, GetTypelnfo, GetlDsOfNames и lnvoke. Функции GetTypelnfoCount и GetTypelnfo получают информацию из библиотеки типов ком¬ понента относительно интерфейсов, методов и свойств, которые он поддерживает. GetlDsOfNames принимает одно или больше свойств и/или методов и возвращает значения их идентификаторов (displD), определенные в библиотеке типов. Invoke принимает displD и указатель на массив параметров и инициирует выполнение объектом ассоциированного свойства или метода. На следующей иллюстрации показаны функции, содержащиеся в IDispatch, а также допол¬ нительные функции, поддерживаемые интерфейсом: Рис. 7.11. Интерфейс ldispatch. IDispatch позволяет клиенту выполнять следующее: • запрос объекта из библиотеки типов; • вызов имени свойства или метода в форме строки, чтобы получить ассоциированный идентификатор (displD); • специфицирование значения идентификатора для вызова свойств и методов объекта. Как и другие интерфейсы COM, IDispatch поддерживают все функциональные возможности интерфейса IUnknown. На рис. 7.12 показано, как работает интерфейс IDispatch: Дополнительную информацию относительно IDispatch и displD см. в разделах "Введение в связывание" и "Использование интерфейсов". IDispatch AddRef Release Querylnterface GetTypelnfoCount GetTypelnfo GetlDsOfNames Invoke
Гпава 7. СОМ и создание клиентов ActiveX 165 Object Browser Рис. 7.12. Функционирование интерфейса IDispatch. 7.2.5. Двойные интерфейсы Интерфейс IDispatch предоставляет возможности Автоматики, поэтомулюбой клиент, который может использовать IDispatch, может использовать поддерживающий его компонент. Однако вызов свойства или метода IDispatch может потребовать двух обращений к функции — одно к GetlDsOfNames и одно к lnvoke (см. "Введение в связывание"). Метод lnvoke должен определить, какой метод или свойство вызывается, и затем распако¬ вать соответствующие параметры. Это не самый эффективный метод обеспечения Автома¬ тики. Более эффективным является использование двойного интерфейса. Двойной интерфейс— пользовательский интерфейс, определенный компонентом и получа¬ емый через IDispatch. Двойной интерфейссодержит все функции, содержащиеся в ldispatch, а также пользовательские функции для каждого метода и свойства, определенного для объекта. Двойной интерфейс обеспечивает СОМ-клиентам наиболее эффективный доступ к методам и свойствам объектов Автоматики. На следующей иллюстрации показано, как может выглядеть двойной интерфейс. Он содер¬ жит все функции IDispatch и все пользовательские функции для свойств и методов, которые поддерживают интерфейсы. Функции IDispatch - Пользовательские функции AddRef Release Querylnterface GetTypelnfoCount GetTypelnfo GetlDsOfNames Invoke Property1_Get(..) Property2_Let(..) Method1(-) Method2(..) Рис. 7.13. Двойной интерфейс.
166 Реализация Автоматики Когда менее сложный клиент соединяется с объектом, который поддерживает двойной интерфейс, он использует стандартную реализацию IDispatch, вызывая Method1 и Method2 через функцию lnvoke. Более сложный клиент, например написанный на Visual Basic 5.0, может вызывать в интер¬ фейсе непосредственно функции Method1 и Method2. Это намного более эффективная форма доступа, известная как связывание vtable, которое освещается в следующем разделе. 7.2.6. Введение в связывание Чтобы клиент мог использовать метод или свойство объекта, он должен быть связан с объектом. Связывание определяет, как клиент соединяется с конкретным объектом. Форма связывания клиента с объектом прежде всего определяется тем, как разработчик приложения-клиента объявляет объектные переменные. Связывание может происходить или в период выполнения или во время компиляции; исходя из этого, имеются два типа связывания: позднее и раннее. Позднее связывание Позднее связывание имеет место, когда компилятор до выполнения ничего не знает отно¬ сительно объекта. Когда используется позднее связывание, для обращения к методу или свойству объекта клиент должен делать два вызова. Первый вызов производится к методу GetlDsOfNames интерфейса IDispatch, чтобы отобрать имена доступных методов и свойств объекта. После этого производится вызов функции lnvoke, чтобы выполнить требуемое действие. Раннее связывание С другой стороны, раннее связывание происходит, когда Visual Basic во время компиляции точно знает, какой интерфейс будет использоваться с объектной переменной. Так как компилятор имеет доступ к библиотеке типов объекта, он может проконтролировать синтаксис любых вызовов, которые используют эту объектную переменную, и сообщить о любой ошибке синтаксиса во время разработки. Компилятор может также изменять компилированный код для оптимизации по быстродей¬ ствию выполнения доступа к объекту. Эта оптимизация может быть выполнена одним из двух способов: связыванием displD или связыванием vtable. Связывание displD При связывании displD компилятор получает идентификатор displD библиотеки типов объ¬ екта и изменяет все вызовы объекта вызовом Invoke с соответствующим параметром displD. Следовательно, для каждого метода или свойства, к которому выполняется обращение, исполняемый модуль устраняет вызовы GetlDsOfNames. Связывание vtable Более быстрая форма раннего связывания известна как связывание vtable. Связывание vtable — более эффективная форма связывания, так как при ней не делается два вызова GetlDsOfNames и lnvoke. Visual Basic вообще не делает каких-либо обращений к функциям. Вместо этого для непос¬ редственного доступа к методам и свойствам объекта он использует смещение (или указа¬ тель) на таблицу виртуальной функции (vtable). В спецификации СОМ серверы обеспечивают связывание vtable по умолчанию. Если в приложении-клиенте переменные объявляются с использованием явных имен классов,
Гпава 7. СОМ и создание клиентов ActiveX 167 Visual Basic всегда будет использовать связывание vtable. При использовании связывания vtable вызов метода или свойства в in-process компоненте Visual Basic не требует каких-либо дополнительных затрат ресурсов, кроме вызова функции в DLL. Дополнительную информацию относительно влияния различных типов связывания на производительность см. в разделах "Объявление объектных переменных" и "Создание объектов". 7.3. Характеристики компонентов сервера При разработке приложения-сервера программист определяет, сколько экземпляров компонента сервера будет создано в период выполнения и где сервер будет выполнять¬ ся. Эти решения могут оказывать существенное влияние на производительность и защиту клиента. 7.3.1. Установка свойства Instancing Разрабатывая компонент, автор должен установить свойство Instancing, чтобы специфици¬ ровать, будет или нет объект доступен для использования приложениями-клиентами и могут ли быть созданы несколько экземпляров объекта. В следующей таблице определяются различные установки свойства Instancing: Установка Результат 1 (Умолчание) Private. Другому приложению не разрешен доступ к информации библиотеки типов класса, и оно не может создавать экземпляры этого класса. Объекты Private используются только внутри компонента. Применяется к ком¬ понентам ActiveX EXE, ActiveX DLL, ActiveX Control и Standard EXE. 2 PublicNotCreatable. Другое приложение может использовать объекты этого класса, только если компонент перед этим сам создает объекты. Другое приложение не может использовать для создания объектов этого класса функцию CreateObject или операцию New. Это значение устанавливается для свойства Instancing, если требуется создать зависимые объекты. Приме¬ няется только к компонентам ActiveX EXE, ActiveX DLL и ActiveX Control. 3 SingleUse. Позволяет другому приложению создавать объекты из класса. Каждый объект этого класса, который создан клиентом, запускает новый экземпляр компонента. Применяется только к проектам ActiveX EXE. 4 GlobalSingleUse. Подобно установке SingleUse, за исключением того, что свойства и методы класса могут вызываться, как если бы они были глобаль¬ ными функциями. Применяется только к компонентам ActiveX EXE. 5 MultiUse. Позволяет другому приложению создавать объекты из класса. Один экземпляр компонента может обеспечивать любое количество объектов, со¬ зданных таким образом, независимо от того, сколько приложений их запраши¬ вает. Применяется только к компонентам ActiveX EXE и ActiveX DLL. 6 GlobalMultiUse. Подобно установке MultiUse, за исключением того, что свой¬ ства и методы класса могут вызываться, как если бы они были глобальными функциями. Предварительное явное создание экземпляра класса необяза¬ тельно, так как он будет создан автоматически. Применяется только к компо¬ нентам ActiveX EXE и ActiveX DLL.
168 Характеристики компонентов сервера Установка Применяется к проекту типа ActiveX Exe ActiveX DLL ActiveX Contol Standard Exe Private X X X X PublicNotCreatable X X X SingleUse X GlobalSingleUse X MultiUse X X GlobalMultiUse X X Свойство Instancing в Visual Basic 5.0 расширено и включает функциональные возможности свойства Public из Visual Basic 4.0. Когда допускается создание класса, создавать экземпляры класса из другого приложения можно любым из следующих способов: • с помощью функции CreateObject: Set Instancel = CreateObject("Projectl.Classl") • используя оператор Dim внутри проекта (или вне проекта, если свойство Public установ¬ лено в True): Dim Instancel As New Classl Ключевое слово New указывает, что lnstance1 должно быть объявлено как новый экземпляр Class1. Если свойство Public — False, установка свойства Instancing игнорируется. Можно всегда создавать экземпляры класса внутри проекта, который определяет класс. Если свойство Public — True, класс видим и, следовательно, если экземпляр класса существует, он может управляться другим приложением. Хотя клиент не имеет какого-либо контроля над созданием экземпляра компонента, уста¬ новка для свойства Instancing может существенно влиять на производительность клиента. Например, если клиент должен совместно использовать экземпляр компонента, производи¬ тельность может снижаться. 7.3.2. Определение расположения компонентов сервера В зависимости от назначения компоненты могут разрабатываться с целью предоставления услуг из различных расположений. Например, компонент пользовательского интерфейса, вероятно, лучше всего разместить возможно ближе к клиенту, в то время как компонент, который обеспечивает статистические вычисления удаленныхданных, эффективней будет расположить на отдельном компьюте¬ ре, рядом сданными, которыми компонент манипулирует в вычислениях. Компоненты могут работать в любом из трех мест: в том же адресном пространстве, что и клиент, в адресном пространстве, отдельном от приложения-клиента, или на удаленном компьютере. В следующей таблице видны различия между этими типами расположений компонентов:
Гпава 7. СОМ и создание клиентов ActiveX 169 Тип сервера Расположение ln-process Компонент in-process обычно реализуется как библиотека динамиче¬ ской компоновки (DLL). Он выполняется в том же адресном простран¬ стве (процессе), где и приложение-клиент. Это позволяет реализовать наиболее эффективную связь между клиентом и компо¬ нентом, так как для получения требуемых функциональных возмож¬ ностей требуется только вызвать нужную функцию DLL. Out-of-process Компонент out-of-process обычно реализуется как исполняемый файл и выполняется в собственном пространстве процесса. Связь между клиентом и компонентом будет медленнее, так как параметры и возвращаемые значения должны передаваться через границу про¬ цесса (маршаллинг). Однако единственный экземпляр компонента out-of-process может обслуживать много клиентов, разделять гло¬ бальные данные и изолировать другие приложения-клиенты от про¬ блем, с которыми может столкнуться один из клиентов. Удаленный Удаленные компоненты — также компоненты out-of-process, но они размещены на отдельном компьютере. Хотя время установления связи между клиентом и удаленным сервером существенно больше, чем на локальном сервере, удаленные серверы позволяют выполнять обра¬ ботку на более мощном компьютере. Компонент можно также разме¬ стить ближе к выполняемой работе. Например, удаленный компонент может быть расположен рядом с удаленной базой данных, с которой он взаи модействует. Как и в случае со свойством Instancing, клиент Visual Basic не имеет какого-либо контроля над расположением компонента. Однако расположение может существенно воздействовать на производительность клиента, в некоторых случаях расположение может также оказывать влияние на характер взаимодействия клиента с компонентом. При работе с out-of-process и удаленными компонентами необходимо гарантировать, что клиент минимизирует количество вызовов объектов, созданных из компонента. Например, если производятся повторные вызовы объекта с передачей данных, которые объект обрабатывает, желательно найти способ передавать данные крупными пакетами, сократив, насколько возможно, количество вызовов. 7.3.3. Уведомление клиентов Еще одна черта компонентов, с которой разработчику стоит разобраться, — их способность поддерживать связь с клиентами асинхронно. В Visual Basic это новая возможность для компонентов: более ранние версии Visual Basic допускали только синхронную обработку. Когда компонент используется лишь для отбора значений свойств и вызова методов, он немедленно возвращает значения клиенту. Однако, если компонент должен выполнить задачу, о которой известно, что она займет несколько секунд или минут, требуется обеспе¬ чить асинхронное сообщение клиенту, когда сервер завершит выполнение обработки. В этой версии Visual Basic, когда компоненту требуется установить связь с клиентом, компонент использует исходящий интерфейс. Это означает, что компонент определяет интерфейс, а клиент его реализует. Сервер устанавливает связь с клиентом, отбирая указатель на возможный способ реализации клиентом этого интерфейса, и затем делает соответствующие вызовы.
170 Создание клиента в Visual Basic На следующей иллюстрации показана асинхронная связь между компонентом и клиентом. Рис. 7.14. Асинхронная связь между компонентом и клиентом. Исходящая связь может принимать форму запуска событий или вызова в клиенте опреде¬ ленных функций, известных как функции обратного вызова. Дополнительную информацию относительно того, как события управляют клиентом и как реализованы функции обратного вызова, см. в разделах "Сообщения сервера с использо¬ ванием событий" и "Сообщения сервера с использованием обратных вызовов". 7.4. Создание клиента в Visual Basic В этом разделе показано, как создать компонент и как получить ссылки на дополнительные интерфейсы в компоненте. Компоненты СОМ создаются с помощью таких инструментальных средств, как Visual Basic, MicrosoftVisual С ++ и MicrosoftVisual J ++. Visual Basic в этом плане предлагает богатый набор возможностей в дополнение к преимуществам своей среды быстрой разработки приложений. Создание компонентного приложения-клиента в Visual Basic требует четырех простых шагов: 1. Установить ссылку на библиотеку типов компонента. 2. Объявить объектную переменную. 3. Создать объект. 4. Использовать методы и свойства объекта. 7.4.1. Первый шаг: установление ссылок При создании приложения-клиента необходимо соединить клиента с компонентом. Первый шаг при подключении клиента к компоненту — установить в проекте ссылку на библиотеку типов компонента. Для этого: 1. В меню Project выбрать References. 2. В окне диалога References выбрать библиотеку типов, которую требуется подключить, и затем щелкнуть OK (рис. 7.15). Если ссылка не представлена в списке, но известно, что компонент доступен, щелкнуть кнопку Browse, чтобы добавить ссылку. После того как на компонент установлена ссылка, можно открыть Object Browser для просмотра и выбора объектов, интерфейсов, методов, свойств, событий и констант, предоставляемых компонентом.
Гпава 7. СОМ и создание клиентов ActiveX 171 Дополнительную информацию относительно библиотек типов см. в разделе "Реализация Автоматики". Рис. 7.15. Окно диалога References. 7.4.2. Второй шаг: объявление объектных переменных Объектные переменные содержат указатели объектов, которые требуется создать для клиента Автоматики. Объектную переменную можно объявлять либо переменной общего объектного типа (As Object ), либо конкретного типа, в зависимости от того, как планируется использовать переменную и какое допускается воздействие объекта на производительность приложения. Примечание: Для объектных переменных применяются те же правила области определения, что и для общих переменных. Общие объектные переменные Общие объектные переменные могут содержать указатели на любой тип объекта. Наиболее общая переменная имеет тип Variant. Переменная типа данного Variant содержит числовые и строковые данные и, кроме того, может также содержать указатель на объект любого типа. Для общих объектных переменных желательно объявлять тип данных Object, как показано в следующем примере: Dim x As Object При использовании общих объектных переменных для соединения с объектом компилятор применяет позднее связывание. Объект или объекты, с которыми нужно установить связь, в этом случае не будут известны до выполнения приложения. Так как позднее связывание не использует библиотеку типов во время разработки, устанавливать ссылку на компонент в Visual Basic не требуется. Объектные переменные конкретного типа Объектные переменные конкретного типа относятся к дискретному объектному типу и могут содержать указатели только на объект этого типа.
172 Создание клиента в Visual Basic Например, следующий код объявляет переменную ex, которая будет содержать указатель только на объект 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 objObject1 As Project1 .CIass1 Set objObject1 = New Project1.Class1 Примеры кода, в которых используется этот синтаксис, см. в разделе "Создание экземпляра Microsoft Excel". Примечание: При создании объекта необходимо использовать оператор Set, чтобы назначить объект к объектной переменной. Это объясняется тем, что объект должен иметь счетчик исполь¬ зования, который позволяет объекту уничтожить себя, когда он более не используется. Оператор Set гарантирует, что, когда возвращается указатель объектного интерфейса, вызывается метод AddRef. Внутренний счетчик использования объекта получает инкремент, и объект существует, пока не вызывается функция Release и счетчик использования не устанавливается в ноль. Дополнительную информацию относительно AddRef и Release см. в разделе "Использова¬ ние интерфейсов". Использование оператора As New в разделе Declaration Для создания объекта оператором As New используется следующий синтаксис: Dim objObject1 as New Class1 Использование оператора As New для объявления объектной переменной откладывает создание объекта до тех пор, пока к объекту не будет фактического обращения. Следует избегать использования оператора As New, так как при этом создается менее эффективный код. Например, когда вводится следующий код: Dim ObjectVariablel As New Classl If Funcl() Then ObjectVariablel.Propl = 5 End if 0bjectVariablel.Prop2 = 6 Visual Basic регенерирует код, как если бы текст кода был следующий: Dim ObjectVariablel As New Classl If Funcl() 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 ' Добавлено компилятором 0bjectVariablel.Prop2 = 6 New или CreateObject? При создании единственного объекта по производительности нет существенных различий между использованием ключевого слова New и функции CreateObject. Однако, когда созда¬ ется несколько объектов, роль аспекта производительности возрастает. Функция CreateOb¬ ject при создании экземпляра класса использует стандартные сервисы СОМ, в то время как в Set x = New Y и Dim x As New Y используется оптимизированная внутренняя версия сервисов создания объектов.
174 Создание клиента в Visual Basic Когда используется CreateObject, код выполняет по крайней мере два просмотра информа¬ ции в системном реестре. Сначала он ищет идентификатор ProglD для класса (например, Excel.Application) и определяет ассоциированный ClasslD. Затем он ищет этот ClasslD в разделе ClslD реестра и извлекает требуемую информацию по данному серверу. Например, ClslD содержит данные по расположению сервера и его библиотеке типов. Эти просмотры при создании единственного объекта на производительность заметно не воздействуют, но при создании нескольких объектов влияние будет значительным, так как код должен выполнить эти поиски для каждого вызова функции CreateObject. С другой стороны, когда используется ключевое слово New, компилятор может оптимизиро¬ вать код (применяя раннее связывание), так как имеется только один просмотр для ClslD. Вся информация сервера (например, расположение библиотеки типов) кэшируется в памя¬ ти и многократно используется для последующих вызовов. Таким образом, при создании объектов нужно стараться вместо функции CreateObject использовать ключевое слово New. Использование функции GetObject Основная причина для использования функции GetObject состоит в том, что иногда требу¬ ется создать экземпляр объекта, который уже содержит данные из файла. Например, следующий код возвращает объект Workbook (рабочая книга) Microsoft Excel с уже открытым рабочим листом Finances.xls: Dim xl As Object Set xl = GetObject("c:\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 = check ' Возвращается интерфейс 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. Подпрограммы обратного вызова на стороне компонента создаются разработчиком компонента, создаю¬ щим пустой шаблон интерфейса, который впоследствии будет реализован разработчиком клиента. Примечание: Стандартные интерфейсы создаются путем компиляции абстрактных классов (мо¬ дули класса с объявлениями процедур, но без реализации) в npoeKmaxActiveX DLL или EXE Visual Basic или с помощью компилятора Microsoft Interface Definition Language (MIDL), который находится в папке Tools Visual Basic. Опытные пользователи Visual C++ для определения интерфейса, вероятно, предпочтут компилятор MIDL. Программистам BASIC, скорее, понравится создавать интерфейс, ис¬ пользуя модули класса Visual Basic. Использование ключевого слова Implements Для реализации определения интерфейса компонента сначала необходимо установить ссылку на этот компонент. После установления ссылки можно использовать Object Browser для просмотра определе¬ ния интерфейса. Затем в модуле класса можно использовать ключевое слово Implements для объявления дополнительного интерфейса. Предположим, например, что требуется реализовать интерфейс ISomelnterface с методами Method1 и Method2. В следующем фрагменте показано, как можно добавить эти методы к модулю класса: Implements ISomelnterface 'Объявление интерфейса Public Sub ISomeInterface_Methodl() ' Некоторое описание метода Methodl End Sub Public Sub ISomelnterface Method2() ' Некоторое описание метода Method2 End Sub Использование возможностей обратного вызова Сообщение обратного вызова требует, чтобы клиент реализовал явный интерфейс, опреде¬ ленный компонентом, и передал ссылку на этот интерфейс обратно к компоненту. Компонент сервера обеспечивает следующие две части кода: • имя пользовательского интерфейса, функции которого будут действовать как обратные вызовы клиенту; • функция public (обычно это свойство, которое используют только для записи), через которую клиент будет передавать ссылку на интерфейс, содержащий обратные вызовы. Чтобы получать сообщения обратного вызова из компонента, в приложении-клиенте долж¬ ны быть проделаны следующие шаги: 1. Гарантировать, что исходящий интерфейс из компонента распознаваем. В Visual Basic должна быть установлена ссылка на компонент.
Гпава 7. СОМ и создание клиентов ActiveX 177 2. В приложение-клиентдобавить модуль класса, который реализует исходящий интерфейс сервера через ключевое слово 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 ' Передать серверу ссылку на объект обратного вызова objNotifier.NotifyProc = objNotifyee End Sub Private Sub cmdExit Click() Unload Me End Sub Private Sub cmdSleep Click() objNotifier.Interval = txtInterval objNotifier.Wait ' Пользовательский метод перехода в ждущий режим End Sub 7.5.3. События или обратные вызовы? Обычно события проще в реализации, чем подпрограммы обратного вызова, но обратные вызовы обеспечивают большую управляемость процессом. Основное различие между событиями и подпрограммами обратного вызова в том, что событие подобно анонимной радиопередаче, в то время как обратный вызов — прямое рукопожатие. Событие в компоненте ничего не знает относительно использующих его
178 Прием сообщений от серверов приложений-клиентов, в то время как подпрограмме обратного вызова в компоненте изве¬ стно о клиенте многое. Ниже приводятся сравнительные характеристики событий и обратных вызовов. Любой объект, который имеет ссылку на компонент, предоставляющий событие, сможет управлять событием, если к объявлению переменной объекта добавить WithEvents. Компо¬ нент, который содержит это событие, не знает о том, что другие объекты могут обрабаты¬ вать его события, так как он "ведет передачу" для неизвестной аудитории. С другой стороны, компонент, который содержит подпрограммы обратного вызова, должен обеспечить ссылку на каждый объект, который он вызовет. Компонент точно знает, сколько объектов к нему обращаются. Компонент, предоставляющий события, не имеет какого-либо контроля над порядком, в котором приложения-клиенты получают события. С другой стороны, компонент, использующий обратные вызовы, может управлять порядком, в котором вызывающие приложения-клиенты получают обратные вызовы. Например, ком¬ понент может управлять приоритетом некоторых клиентов. Когда компонент устанавливает событие, все его клиенты обрабатывают событие прежде, чем серверу возвращается управление. С другой стороны, компонент, использующий обратные вызовы, восстанавливает управле¬ ние после каждого вызова клиента. Если событие содержит параметр ByRef, этот параметр может изменяться любым клиен¬ том, который обрабатывает событие. Компонент будет видеть только последние изменения, сделанные клиентом, так как компоненту не возвращается управление, пока все клиенты не обработают событие. С другой стороны, компонент, который обеспечивает подпрограмму обратного вызова, может видеть любые изменения, сделанные с параметром ByRef после каждого вызова клиента, и может передать следующему клиенту новые значения для этих параметров. Если возвращается ошибка в процедуре обработки события клиента, компонент, который передал событие, не будет знать об ошибке. С другой стороны, компонент, который обеспечивает подпрограмму обратного вызова, может получать ошибки, которые происходят в подпрограмме обратного вызова клиента, и может быть подготовлен к их обработке. Таким образом, события, вместо подпрограмм обратного вызова, следует использовать, когда компонент, передающий уведомления: • может передавать их анонимно; • не заботится о порядке их получения клиентами; • компоненту не требуется получать управление обратно между вызовами клиентов; • может использовать последнее известное значение любого параметра ByRef; • не должен обрабатывать ошибки клиента. Если любое из этих условий не выполняется, то компонент должен передавать уведомле¬ ния, используя подпрограммы обратного вызова. Когда критично важна производительность приложения, можно также использовать обрат¬ ные вызовы вместо событий. Подпрограммы обратного вызова могут работать быстрее, чем события, так как для обратных вызовов, в отличие от событий, может применяться связыва¬ ние vtable. Эффект от этого намного более значим для компонентов 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. Примечание: Зависимые объекты могут быть доступны только через метод объекта более высокого уровня. Например, метод Cells объекта Worksheet Microsoft Excel возвращает объект Range. Обращение к объектам осуществляется с использованием навигационной операции точка (.). Например, следующий код устанавливает значение ячейки A1 в рабочем листе Sheet1 в рабочей книге BOOK1.XLS: xl.Workbooks("BOOKl.XLS").Worksheets("SHEETl") _ .Range("Al").Value = 5 Для установления ссылки на объект, расположенный в объектной модели одним уровнем выше, можно использовать свойство Parent объекта, как в следующей строке: xlwb.Parent ' Обращение к объекту Application Для установления ссылок на неоднократно используемые объекты можно создавать объек¬ тные переменные. В следующем примере кода в объектной переменной xlsheet устанавливается ссылка на лист Sheet1 в рабочей книге Book1.xls: Dim xl as Excel.Application Dim xlSheet as Excel.Worksheet Set xl = CreateObject("Excel.Application") Set xlSheet = xl.Workbooks("BOOKl.XLS").Worksheets("SHEETl") xlSheet.Range("Al").Value = 5 Ссылку на объект можно установить по имени или индексу. В следующей строке устанавли¬ вается ссылка на рабочую книгу Book1.xls, часть группы, или семейства, рабочих книг: set xlwb = xl.WorkbooksCBOOKl.XLS")
180 Создание приложения-кпиента, использующего Microsoft Excel Первый элемент в семействе имеет индекс 1. В следующем примере устанавливается ссылка на первую рабочую книгу в семействе Workbooks: set xlwb = xl.Workbooks(l) 7.6.2. Создание экземпляра Microsoft Excel В первом шаге при использовании Автоматики в проекте Visual Basic необходимо добавить ссылку на библиотеку типов требуемого компонента. Например, чтобы добавить ссылку на библиотеку типов для 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. Функция 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 End If В следующем примере показано, как использовать оператор 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 Эта строка закрывает рабочую книгу Book1 .xls xl.Workbooks("BOOKl.XLS").Close SaveChanges :=False 7.6.4. Получение и установка значений Для ввода значения в ячейку рабочего листа используется метод Range объекта Worksheet. Специфицировать интервал в рабочем листе можно установкой ссылки на ячейку, например A1, или использовать именованный интервал. В следующем примере устанавливается объектная переменная Sheet1. Затем устанавли¬ вается значение ячейки A1 и значение именованного интервала range1:
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 lnteger x(l,l) = 5 x(l,2) = 5 x(l,3) = 6 . . . .' Либо добавить другой код заполнения массива xl.Range("Al:B4").Value = x ' Передать весь массив значений Можно отобрать интервал ячеек в переменную типа 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("A1:D4").Select set xlc = xl.Charts.Add() xlc.Type = xl3DColumn ' Тип диаграммы - ЗО-гистограмма Этот код устанавливает ссылку на существующую диаграмму и затем изменяет тип диаграммы:
Гпава 7. СОМ и создание клиентов ActiveX 183 set xlc =xl.workbooks("bkl.xls").Charts("mycht") xlc.Type = xl3DColumn В следующем фрагменте (процедура Click() кнопки 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 = xl3DColumn End Sub Рис. 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 ("с:\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 Excel Macro Recorder. Сгенерированный здесь код можно затем импортировать из Microsoft Excel в приложение Visual Basic. Однако, если используется этот подход, в импортируемый код потребуется внести некото¬ рые изменения. Например, в Visual Basic нужно будет создать экземпляр Microsoft Excel, добавив оператор с ключевым словом 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 Dim xl As Excel.Application Set xl = New Excel.Application xl.Workbooks.Add xl.ActiveWorkbook.SaveAs Filename:="TERMPAPR.XLS", FileFormat:=xlNormal, Password:="", WriteResPassword:="", ReadOnlyRecommended:=False , CreateBackup:=False 7.6.7. Пример: Управление Microsoft Excel В этом примере с помощью механизмов Автоматики осуществляется управление Microsoft Excel. На следующей иллюстрации показана часть рабочей книги с коммерческой информацией: Рис. 7.17. Коммерческая информация в Microsoft Excel. Создание проекта 1. Запустить новый npoeKTVisual Basic. 2. Построить следующую форму: Рис. 7.18. Форма для взаимодействия с Excel.
186 Создание приложения-кпиента, использующего Microsoft Excel Создание экземпляра объекта — приложения Microsoft Excel 1. Добавить к проекту ссылку на библиотеку Microsoft Excel 5.0 Object Library. 2. Добавить к проекту стандартный модуль, в котором объявить переменные xl и xlChart: 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() ' Кнопка "Создать объект Excel" set xl = CreateObject("Excel.Application") xl.Workbooks.Open App.Path & "c:\office\Market.xls" xl.Visible = True End Sub 6. Протестировать приложение. Передача информации в Microsoft Excel 1. В процедуре обработки события СИскдля кнопки "Оценить прибыль" активировать рабо¬ чий лист "Доходы" и установить значения ячеек "Оценка роста" (Growth) и "Оценка инфляции" (Inflation) равными значениям текстовых полей "Оценка роста" (txtGrowth) и "Оценка инфляции" (txtlnflation) соответственно. Примерный код процедуры кнопки: Private Sub cmdEstimate Click() ' Кнопка "Оценить прибыль" xl.Worksheets("Доходы").Activate xl.Worksheets("floxoflbi").Range("Growth").Value = txtGrowth.Text xl.Worksheets("floxoflbi").Range("Inflation").Value = txtInflation.Text End Sub 2. Протестировать приложение: • запустить приложение; • нажать кнопку "Создать объект Excel", чтобы запустить Microsoft Excel и открыть рабочую книгу; • перейти в Visual Basic, ввести проценты в текстовых полях и протестировать действие кнопки "Оценить прибыль". Создание диаграммы 1. В процедуре обработки события Click кнопки "Диаграмма", если переменная xlChart, добавленная выше, установлена в Nothing, используя метод Select, выбрать именован¬ ный интервал "Чистая прибыль" (Net_Profit) рабочего листа "Доходы". 2. Используя метод Add объекта Chart, создать новую диаграмму в рабочей книге и иници¬ ализировать переменную xlChart. 3. Установить для свойства Type объекта Chart значение xl3DColumn. Это — константа из библиотеки объектных модулей Microsoft Excel.
Гпава 7. СОМ и создание клиентов ActiveX 187 4. Если переменная xlChart не установлена в Nothing, можно использовать метод Activate, чтобы сделать диаграмму активным листом. Примерный код процедуры: Private Sub cmdChart Click() ' Кнопка "Диаграмма" If xlc Is Nothing Then xl.Worksheets("floxoflbi").Range("net profit").Select set xlc = xl.Charts.Add() xlc.Type = xl3DColumn Else xlc.Activate End If End Sub 5. Протестировать приложение: • запустить приложение; • нажать кнопку "Создать объект Excel", чтобы запустить Microsoft Excel и открыть рабочую книгу; • перейти в Visual Basic и нажать кнопку "Диаграмма". Рис. 7.19. Диаграммы Excel с разными значениями свойства Type.
188 Обзор компонентов ActiveX Глава8. Созданиепрограммных компонентов ActiveX Visual Basic версии 5.0 позволяет создавать программные компоненты ActiveX (ранее изве¬ стные как OLE серверы). Программный K0Mn0HeHTActiveX — приложение-сервер, обеспечи¬ вающее функциональные возможности, которые могут многократно использоваться другими приложениями через механизмы Автоматики. В этой главе дается краткий обзор программных компонентов ActiveX и показано, как их можно создавать в Visual Basic. 8.1. Обзор компонентов ActiveX Компонент ActiveX — единица исполняемого программного кода (например, файл .exe, или .dll или .ocx); которая отвечает спецификации ActiveX в части предоставления объектов, которые могут использоваться другими приложениями. В Visual Basic можно создавать три типа компонентов ActiveX: элементы управления ActiveX, документы ActiveX и программные компоненты ActiveX. 8.1.1. Элементы управления ActiveX Элементы управления ActiveX (прежде известные как элементы управления OLE) — стан¬ дартные элементы пользовательского интерфейса многократного использования, которые позволяют быстро строить формы и окна диалога. Информацию о порядке создания элементов управления ActiveX см. в главе 9 "Создание элементов управления ActiveX". 8.1.2. Документы ActiveX Документы ActiveX (ранее известные как объекты-документы) — компоненты ActiveX, кото¬ рые должны создаваться или внедряться и активизироваться внутри приложения-клиента. Технология документа ActiveX — расширение концепций документов OLE. Она расширяет функциональные возможности визуального редактирования внедренных объектов, актива¬ ции приложений-оболочек, таких как Internet Explorer, применение разныхтиповдокументов. Информацию относительно разработки документов ActiveX см. в главе 10 "Создание и использование документов ActiveX". 8.1.3. Программные компоненты ActiveX Программные компоненты — библиотеки объектов. Приложения-клиенты используют про¬ граммные компоненты, создавая объекты из классов, обеспечиваемых компонентом. Кли¬ енты вызывают свойства, методы и события, предоставляемые объектом. Любое приложение, которое поддерживает стандарты Автоматики, может использовать программный компонент ActiveX, созданный в Visual Basic. Это Visual Basic, Microsoft Excel, Microsoft Access, Microsoft Project, Microsoft Visual FoxPro, Microsoft Visual C++ и другие инструменты. Visual Basic обеспечивает средства для решения многих сложных задач создания програм¬ много компонента ActiveX, таких, как создание библиотеки типов и автоматическая регист¬ рация компонента.
Гпава 8. Создание программных компонентов ActiveX 189 8.1.4. Преимущества использования компонентов ActiveX Преимущества использования программных компонентов ActiveX включают: • ясно определенные интерфейсы. Функциональные возможности, реализованные в программном компоненте ActiveX, доступны через его свойства, методы и события. Эти интерфейсы само-документируемы в том смысле, что они автоматически предоставля¬ ются программным компонентом, и разработчик и пользователь может добавлять для каждого интерфейса описательную и контекстно-чувствительную информацию Help, ко¬ торая будет сохранена программным компонентом. Пользователи могут просматривать эту информацию для каждого интерфейса, используя Object Browser или другие инстру¬ ментальные средства; • простота создания, использования и обновления. Программные компоненты ActiveX можно создавать, скрывая сложность программной реализации отдругих программистов. Другим программистам требуется знать только, какую информацию обеспечить этому объекту и какую информацию можно отобрать. Можно создавать программный компонент ActiveX, который инкапсулирует бизнес-правила (правила и стандарты реальной работы, например с данными). Если бизнес-правила изменяются, потребуется модифицировать только программный компонент, а не все приложение, в котором этот компонент исполь¬ зуется. 8.2. Создание объектов в Visual Basic Процедура создания программных компонентов ActiveX включает работу с модулями клас¬ са, в которых определяются объекты, обеспечиваемые компонентом. Классы инкапсулиру¬ ют внутреннюю функциональность компонента, а клиенты в период выполнения создают объекты из экземпляров классов. В этом разделе описывается использование модулей класса для определения и создания экземпляра класса. Здесь также показано, как работать со свойствами, методами и событиями объектов, создаваемых при инициализации класса. Вначале модули класса создаются и используются внутри проекта Visual Basic. Затем эти классы могут быть превращены в программный KOflActiveX. 8.2.1. Модули классов При создании программных компонентов ActiveX первый шагсостоит в определении объек¬ тов внутри проекта Visual Basic. Для определения объектов для компонентов используются модули класса. Назначение модуля класса Модуль класса — один из типов модулей программного кода, обеспечиваемых Visual Basic. Каждый модуль класса действует как проект для объекта. Иными словами, каждый модуль класса определяет один тип объекта. В приложении может быть создано несколько модулей класса. В период выполнения через создание экземпляра класса создается объект. Модули класса полезны при создании любого вида программных компонентов ActiveX. Модули класса представляют логические объекты компонента. Например, можно создать класс Служащий, который имеет такие свойства, как Служащий.Фамилия и Служащий.Имя, или такой метод, как Служащий.Принять. Приложение может работать с несколькими экзем¬ плярами объекта Служащий и создавать семейство объектов Служащий. Добавление модуля класса к проекту Для добавления в проект нового модуля класса нужно в меню Project выбрать команду Add Class Module. Методы, свойства и события можно добавлять к классам вручную или исполь¬
190 Создание объектов в Visual Basic зуя мастер Class Builder в Visual Basic. Надстройка Class Builder автоматизирует процедуры работы с классами. Дополнительную информацию относительно расширения Class Builder Visual Basic см. ниже, в разделе "Использование Class Builder". 8.2.2. Создание экземпляра класса Модули класса отличаются от стандартных модулей следующими характеристиками: • модули класса должны быть явно созданы прежде, чем они могут использоваться; • можно создавать несколько экземпляров модуля класса. В проекте, который определяет класс, экземпляр класса можно создавать операторами Dim и Set, как показано в следующем примере: Dim objObjectl As Classl Dim objObject2 As Classl Set objObjectl = New Classl Set obObject2 = New Classl Примечание: Класс — шаблон для объекта. Объект — экземпляр класса. В примере, приведенном выше, objObject1 и objObject2 — объекты типа Class1. Можно использовать также более компакт¬ ный синтаксис Dim objObject1 As New Class1, но, чтобы ясно показать, где инициируется экземпляр класса, рекомендуется использовать оператор Set. Информацию относительно использования оператора SetcM. в разделе "Третий шаг: созда¬ ние объектов" главы 7 "СОМ и создание клиентов ActiveX". 8.2.3. События модуля класса Модули класса имеют два встроенных события: Initialize и Terminate. Чтобы добавить программный код к событиям модуля класса, нужно открыть окно програм¬ много кода для класса и щелкнуть Class в раскрывающемся списке Object. Событие Initialize Событие Initialize происходит при создании экземпляра класса, но до установки значения любого свойства. Событие Initialize используется для инициализации используемых клас¬ сом данных, как показано в следующем коде: Private Sub Class Initialize() ' Инициализация данных i = 5 End Sub Событие Initialize можно использовать также для загрузки форм, используемых классом. Событие Terminate Событие Terminate происходит, когда объектная переменная выходит из области определе¬ ния или устанавливается в Nothing. Это событие можно использовать для сохранения информации, выгрузки формы или выполнения действий, которые должны произойти при завершении существования объекта. Private Sub Class Terminate() ' Любой код завершения. End Sub
Гпава 8. Создание программных компонентов ActiveX 191 8.2.4. Создание методов Для создания метода для объекта необходимо внутри модуля класса описать процедуры Public Sub или Function. При создании экземпляра модуля класса процедуры Public Sub и Function будут доступны как методы результирующего объекта. В следующем фрагменте кода создается метод, который выводит на экран дату. Это описание следует поместить в модуль класса: Public Sub ShowDate() MsgBox "Сегодня: " & Now() End Sub В одну из процедур формы можно внести вызов процедуры ShowDate() уже как метода класса: Private Sub Form Load() Dim objObjectl As New Classl obj Objectl.ShowDate End Sub При загрузке формы будет выведено сообщение с текущей датой. Рис. 8.1. Сообщение из метода класса. В этом примере создается метод, который принимает число и возвращает квадрат числа: Public Function SquareNum(Num As Integer) As Integer SquareNum = Num * Num End Function В этом фрагменте создается экземпляр класса и вызываются методы ShowDate и SquareNum: Dim Demol As Classl Set Demol = New Classl Demol.ShowDate i = Demol.SquareNum(Num:=5)
192 Создание объектов в Visual Basic Методы можно создавать вручную или с помощью мастера Class Builder. Добавить метод можно также, открыв окно программного кода и затем выбрав команду Add Procedure в меню Tools. Откроется окно диалога Add Procedure, в котором вводятся общие атрибуты создаваемой процедуры. После закрытия этого окна диалога в модуле создается заготовка для процедуры. Рис. 8.2. Окно диалога Add Procedure и заготовка для новой процедуры. В окне Object Browser можно просмотреть свойства и методы, которые определены для класса. Рис. 8.3. Методы нового класса в окне Object Browser. 8.2.5. Создание свойств Описать свойство для объекта можно двумя способами: определить переменные public или создать внутри модуля класса public процедуры Property.
Гпава 8. Создание программных компонентов ActiveX 193 Переменные Public обеспечивают сохранение значения свойства. Процедуры Property по¬ зволяют выполнить программный код, когда значение свойства устанавливается или отби¬ рается. Использование для создания свойств переменных Public В следующем фрагменте кода определяется строковое свойство User (переменные public определяются в разделе General Declarations модуля класса): Public User As String В следующем примере создается экземпляр Class1 и устанавливается значение свойства User: Dim Demol As Classl Set Demol = New Classl Demol.User = "Степанков" Создание умолчательного свойства Установить значение умолчательного свойства для объекта можно без явного обращения к этому свойству. Например, свойство Text в Visual Basic — умолчательное свойство для элемента управления TextBox. Установить его можно так: Textl.Text = "Visual Basic" или Text = "Visual Basic" Чтобы создать умолчательное свойство: 1. Открыть модуль класса, содержащий свойство. 2. В меню Tools выбрать Procedure Attributes. 3. В окне диалога Procedure Attributes щелкнуть кнопку Advanced. 4. В раскрывающемся списке Name выбрать свойство, которое требуется установить как умолчательное. 5. В раскрывающемся списке Procedure ID выбрать (Default) (рис. 8.4). 8.2.6. Использование процедур Ргорег^удля создания свойств Процедуры Property используются, если при установке или отборе значений свойства требуется выполнить некоторый программный код. При помощи процедур Property можно решать следующие задачи: • выполнить процедуру при изменении или чтении значения свойства; • ограничить свойство некоторым набором допустимых значений; • сделать свойство доступным только для чтения. Процедуры Property чаще всего создаются парами. Например, можно создать процедуру Set или Let, предназначенную для установки значения свойства, и процедуру Get, которая будет возвращать значение. Этим двум процедурам дается одинаковое имя, которое является также именем свойства. Создание свойства В следующем фрагменте кода создаются процедуры Property Let и Property Get, которые назначают строковое значение и возвращают значение свойства User (процедуры описыва¬ ются в модуле класса):
194 Создание объектов в Visual Basic Рис. 8.4. Окно диалога Procedure Attributes. Private gsUser As String Public Property Let User (s As String) gsUser = Ucase(s) End Property Public Property Get User () As String User = gsUser End Property Установка и получение значения свойства В следующем примере создается экземпляр Class1 и устанавливается и возвращается свойство User: Dim Demol As Classl Set Demol = New Classl Demol.User = "Степанков" ' Вызов процедуры Let Print Demol.User ' Вызов процедуры Get Для создания свойства, которое возвращает стандартный тип данного, определяются про¬ цедуры Property Get и Property Let. Для создания свойства тип данного Object необходимо определить процедуры Property Get и Property Set. При чтении свойства выполняется процедура Property Get. При установке свойства выпол¬ няется процедура Property Let. Процедура Property Let всегда содержит по крайней мере один параметр, который представ¬ ляет значение для свойства. Этот параметр должен всегда быть последним в списке параметров.
Гпава 8. Создание программных компонентов ActiveX 195 Для создания свойства только для чтения необходимо определить процедуру Property Get без соответствующей процедуры Property Let или Property Set. 8.2.7. Использование Class Builder В Visual Basic имеется надстройка Class Builder, которая автоматизирует процесс формирова¬ ния классов. С помощью Class Builder можно визуально определять классы и их интерфейсы. Рис. 8.5. Окно надстройки Class Builder. Порядок подключения и использования Class Builder: 1. В MeHioAdd-lns Bbi6paTbAdd-ln Manager. 2. В списке Available Add-Ins выбрать Visual Basic Class Builder Utility и щелкнуть ОК. 3. В меню Add-Ins выбрать Class Builder Utility. 4. Добавить новый класс к проекту и затем добавить к классу методы, свойства и события. При нажатии соответствующей кнопки или выборе команды меню File | New открываются окна построителей семейства классов, классов, методов, свойств и событий (рис. 8.6). 8.3. Работа с программными компонентами ActiveX В этом разделе показывается, каксделать модули классадоступными приложениям-клиен- там, таким, как ActiveX EXE и ActiveX DLL. Когда модули класса становятся доступными внешним приложениям-клиентам, они превращаются в программные компоненты ActiveX. 8.3.1. Выбор типа программного компонента В Visual Basic можно формировать программные компоненты, которые будут работать как in-process (ActiveX DLL) или out-of-process (ActiveX EXE). Компоненты in-process и out-of-process Компоненты in-process позволяют получить более быстрый доступ к их объектам, чем компоненты out-of-process. Это объясняется тем, что компоненты in-process подключаются к адресному пространству приложения-клиента и выполнять маршаллинг вызываемых свойств и методов через границу процесса не требуется. Компоненты out-of-process исполь¬ зуют отдельные потоки выполнения, нежели их клиенты. Они, однако, могут быть более гибкими, так как выполняются вне адресного пространства процесса клиента.
196 Работа с программными компонентами ActiveX Рис. 8.6. Окно построителя метода Method Builder с окном описания параметров. Дополнительную информацию относительно различий между компонентами in-process и out-of-process см. в разделе "Определение расположения компонентов сервера" главы 7 "СОМ и создание клиентов ActiveX". Шаблоны проектов компонентов При создании нового проекта Visual Basic можно выбирать среди ряда шаблонов проектов. Для создания программного компонента нужно в окне диалога New Project выбрать шаблон ActiveX EXE или ActiveX DLL (рис. 8.7). При выборе типа проекта устанавливается ряд умолчательных значений свойств проекта, важных для создания программных компонентов. Примечание: Впоследствии тип проекта можно изменить, изменяя свойства проекта. 8.3.2. Установка свойств проекта При создании нового проекта ActiveX DLL или ActiveX EXE можно установить ряд свойств проекта, установки которых воздействуют при выполнении компонента. Устано¬ вить свойства можно в окне диалога Project Properties (команда меню Project | Project Properties) (рис. 8.8). Все описанные ниже опции находятся на вкладке General. Project Type Список Project Type обеспечивает четыре опции: Standard EXE, ActiveX EXE, ActiveX DLL и ActiveX Control. При создании нового проекта ActiveX DLL или ActiveX EXE Visual Basic устанавливает свойство Project Type автоматически.
Гпава 8. Создание программных компонентов ActiveX 197 ШаЬлоны проектов программных компонентов Рис. 8.7. Стандартные шаблоны Visual Basic. Рис. 8.8. Вкладка General окна диалога Project Properties.
198 Работа с программными компонентами ActiveX Тип проекта определяет порядок использования некоторых других опций проекта. Напри¬ мер, когда выбран тип проекта Standard EXE, установки на вкладке Component недоступны. Startup Object Для большинства компонентов ActiveX EXE и ActiveX DLL в поле Startup Object устанавли¬ вается (None). Если требуется, чтобы код выполнялся при загрузке компонента, а не при создании экземпляра класса, для свойства Startup Object можно установить Sub Main. При этом к проекту потребуется добавить стандартный модуль и в этом модуле описать проце¬ дуру Sub под именем Main. Project Name Поле Project Name указывает имя, которое приложение-клиент будет использовать для обращения к компоненту. В следующем примере показан фрагмент кода из приложения-клиента, в котором создается экземпляр класса clsPassWord в программном компоненте Server2: ' Приложение-клиент поддерживает библиотеки типов Dim x As Server2.clsPassWord Set x = New Server2.clsPassWord ' Приложение-клиент не поддерживает библиотеки типов Dim x As Object Set x = CreateObject ("Server2.clsPassWord") Project Description Поле Project Description позволяет ввести краткое описание программного компонента Acti¬ veX и объектов, которые он обеспечивает. Содержимое этого поля появляется внизу окна диалога References для любого компонента, который выбран в списке Available References. Эта строка также появляется в панели описания внизу окна Object Browser (см. рис. 1.7). Unattended Execution Флажок Unattended Execution указывает, что компонент предназначен для выполнения без взаимодействия с пользователем. Автоматические компоненты не имеют пользовательского интерфейса. Функции и действия периода выполнения, такие каксообщения, которые обычно требуют взаимодействия с пользователем, в этом режиме записываются в журнал событий. 8.3.3. Установка свойств модуля класса После установки свойств проекта для программного компонента ActiveX можно установить свойства для каждого модуля класса в компоненте, чтобы определить характер действия классов. Свойство Name Свойство Name используется приложениями-клиентами при создании экземпляра класса. Например, если класс называется Class1 и находится в проекте Project1, код создания экземпляра этого класса в приложении-клиенте мог бы выглядеть следующим образом: Dim x As Projectl.Classl Set x = New Projectl.Classl Свойство Instancing Свойство Instancing определяет, может ли приложение, внешнее по отношению к проекту, создавать новые экземпляры класса, и если да, то как будут создаваться эти экземпляры.
Гпава 8. Создание программных компонентов ActiveX 199 Примечание: Свойство Instancing в Visual Basic 5.0 включает все функциональные возможности свойства Public из Visual Basic 4.0. Для компонентов ActiveX EXE и ActiveX DLL доступные значения свойства Instancing различ¬ ны, как показано на следующей иллюстрации: Рис. 8.9. Опции свойства Instancing для компонентов ActiveX EXE и ActiveX DLL. Описание каждой из установок свойства Instancing см. в разделе "Характеристики компонен¬ тов сервера" главы 7. 8.3.4. Компиляция компонента После формирования программного компонента ActiveX его можно скомпилировать. Компо¬ нент компилируется как файл .exe или .dll, в зависимости от установок в окне диалога Project Properties. Идентификатор библиотеки типов При компиляции компонента ActiveX EXE или ActiveX DLL Visual Basic создает для него уникальный идентификатор библиотеки типов, который записывается в системный реестр при регистрации компонента. Значение поля Project Compatibility на вкладке Component окна диалога Project Properties устанавливается по умолчанию. Эта установка побуждает Visual Basic повторно использо¬ вать тотже идентификатор библиотеки типов при каждой компиляции программного компо¬ нента. Если проводится изменение, которое является несовместимым с версией сервера, специ¬ фицированной в поле Project Compatibility (например, при удалении свойства), Visual Basic выводит на экран предупреждение и генерирует новый идентификатор библиотеки типов. Информацию относительно типов совместимости, доступных в Visual Basic, см. в разделе "Совместимость версий".
200 Тестирование программных компонентов ActiveX 8.3.5. Регистрация компонента Прежде чем программный компонент ActiveX может быть использован, его необходимо зарегистрировать в системе. При запуске компонента ActiveX в режиме разработки происходит его временная регистра¬ ция. Окончательно компонент регистрируется при: • первом запуске; • установке с помощью программы Setup; • при запуске из командной строки с параметром /Regserver. Visual Basic регистрирует файл ActiveX DLL при его компиляции. Для регистрации файла DLL можно также использовать программу Regsvr32.exe, как показано в следующей строке: Regsvr32.exe dlll.dll Для установки ссылки на файл DLL в приложении-клиенте можно использовать окно диало¬ га References. Чтобы удалить вхождение системного реестра для компонента ActiveX EXE, необходимо запустить его с командной строки с параметром /UnRegserver: Serverl.Exe /UnRegserver Для удаления из системного реестра вхождения ActiveX DLL можно запустить Regsvr32.exe с опцией /u и именем файла DLL, как показано в следующем примере: Regsvr32.exe /u dlll.dll 8.4. Тестирование программных компонентов ActiveX Microsoft Visual Basic предлагает два сценария для тестирования и отладки компонентов: один для компонентов in-process и другой — для компонентов out-of-process. По первому сценарию выполняется тестирование компонента внутри единственного экземпляра Visual Basic. Во втором сценарии необходимо запустить две копии среды разработки. В этом разделе показано, как тестировать компоненты ActiveX DLL и ActiveX EXE, а также преимущества установки ссылки на библиотеку типов. Здесь же рассматривается иницииро¬ вание ошибки в приложении-клиенте с целью обеспечения клиента информацией ошибки. 8.4.1. Установка испытательного проекта Первый шаг в тестировании программного компонента ActiveX — создать испытательный проект, в котором будет использоваться этот компонент. Тестирование ActiveX DLL Чтобы протестировать компонент ActiveX DLL, можно добавить к группе проекта ActiveX DLL проект Standard EXE и протестировать компонент in-process внутри единственного экземп¬ ляра Visual Basic. Затем можно перейти непосредственно от испытательного компонентного кода к программному коду компонента in-process. Тестирование ActiveX EXE Для тестирования компонента ActiveX EXE необходимо запустить компонент внутри одного экземпляра Visual Basic, а испытательное приложение запустить во втором экземпляре Visual Basic. В этом случае непосредственно перейти от одного компонента к другому нельзя, но можно использовать все инструментальные средства отладки другого экземпля¬ ра Visual Basic.
Гпава 8. Создание программных компонентов ActiveX 201 8.4.2. Установка ссылки на библиотеку типов При формировании компонента и обеспечении классов для использования клиентами ком¬ пилятор Visual Basic автоматически генерирует библиотеку типов. Разработчики клиента могут использовать Object Вгои^егдпя просмотра предоставляемых компонентом возможностей. Подключиться к компонентам в клиенте можно, используя библиотеку типов и окно диалога References. Преимущества установки ссылки на библиотеку типов При установке ссылки на библиотеку типов компонента для разработчиков клиента обеспе¬ чивается три преимущества: • раннее связывание. Установка ссылки на библиотеке типов во время разработки акти¬ вирует раннее связывание. Раннее связывание позволяет Visual Basic получить инфор¬ мацию относительно методов и свойств, доступных из компонента во время компиляции, а не в период выполнения. (Связывание — процесс перевода объекта в состояние выполнения так, чтобы могли быть вызваны операции (например, редактирование), обеспечиваемые приложением объекта. Тип связывания определяет быстродействие обращения к методам объекта с использованием объектной переменной). Когда исполь¬ зуется раннее связывание, вызовы компонента очень эффективны, так как при этом может использоваться быстрый тип связывания vtable; • контроль синтаксиса. Синтаксис вызовов компонента активируется во время разработки; • доступ к Help. Разработчики клиента имеют доступ к любой контекстно — чувствитель¬ ной помощи, которую обеспечил разработчик компонента. Информацию относительно использования раннего связывания и связывания vtable см. в разделе "Введение в связывание" главы 7 "СОМ и создание клиентов ActiveX". 8.4.3. Отладка компонента После открытия испытательного проекта и установления ссылки на компонент его можно отлаживать, как любое другое приложение Visual Basic. При этом можно перемещаться между приложением-клиентом и компонентом и использовать стандартные средства отлад¬ ки: устанавливать точки останова, проходить через код пошагово, использовать контроль¬ ные выражения и такдалее. Обработка потери ссылки В ходе отладки компонентов можно будет видеть следующее сообщение об ошибке: "Con¬ nection to type library or object library for remote process has been lost. Press OK for dialog to remove reference" (Связь с библиотекой типов или библиотекой объектных модулей для удаленного процесса прервана. Нажмите OK для вывода окна диалога удаления ссылки). Это сообщение указывает, что глобальный уникальный идентификатор (GUID) библиотеки типов компонента изменился и испытательный проект не может найти библиотеку типов. Чтобы очистить отсутствующую ссылку, нужно нажать OK в окне сообщения. В окне диалога References рядом с именем компонента появится MISSING. Нужно очистить флажок отсут¬ ствующего компонента и затем нажать ОК. Информацию относительно библиотек типов и средств просмотра объектов см. раздел "Объекты Автоматики" в главе 7 "СОМ и создание клиентов ActiveX". Информацию относительно того, как СОМ использует идентификаторы GUID, см. раздел "Взаимодействие клиента с сервером" в главе 7.
202 Тестирование программных компонентов ActiveX 8.4.4. Способы обработки ошибок Управление ошибками требует тесной связи между клиентами и компонентами. Если воз¬ можно, компонент и клиенты должны сами обрабатывать ошибки, вместо вывода на экран сообщений пользователю. Когда приложение-клиент вызывает метод объекта, обеспечиваемого компонентом, в мето¬ де могут использоваться следующие два способа обеспечения информации ошибки: • инициирование ошибки, которую должно обработать приложение-клиент. В этом случае в клиенте используются стандартные операторы обработки ошибок или: • возвращение кода ошибки, которую приложение-клиент должно протестировать и обра¬ ботать. Инициирование ошибок В программном компоненте метод, вызываемый приложением-клиентом, вызывает метод Raise объекта Err, чтобы инициировать ошибку в приложении-клиенте. Клиент после этого выполняет процедуру обработки ошибки. Разработчики приложений-клиентов могут также реализовать оперативную обработку оши¬ бок, используя оператор On Error Resume Next или подпрограммы обработки ошибок с оператором On Error Goto. Использование возвращаемого значения В программном компоненте метод, вызываемый приложением-клиентом, возвращает зна¬ чение клиенту. Клиент исследует возвращаемое значение, чтобы определить, произошла ли ошибка и если да, то какая. Применяя этот тип обработки ошибок, разработчики приложений-клиентов должны исполь¬ зовать оперативную обработку ошибок. После вызова метода программный код всегда должен тестировать возвращаемое значение. 8.4.5. Инициирование ошибок выполнения В этом разделе рассматривается инициирование и обработка ошибок выполнения с исполь¬ зованием метода Raise объекта Err. Также показано, как опции, устанавливаемые для режима прерывания (останова), могут воздействовать на обработку ошибок при передаче ошибок клиенту. Инициирование ошибки в клиенте При создании компонента ActiveX можно обеспечивать передачу сообщения об ошибке приложению-клиенту. Для инициирования ошибки в клиенте нужно вызвать метод Raise из подпрограммы обработки ошибок метода компонента. Метод Raise имеет следующий синтаксис: объект. Raise номер, источник, описание, help_cfiadn, help_KOHmeKcm Элементы синтаксиса метода Raise:
Гпава 8. Создание программных компонентов ActiveX 203 Элемент Описание объект Обязательный. Всегда объект Err. номер Обязательный. Целое число Long, которое представляет идентифика¬ тор и происхождение ошибки. Ошибки Visual Basic (встроенные и поль¬ зовательские) располагаются в интервале номеров 0 — 65535. При установке в модуле класса для свойства Number значения пользова¬ тельской ошибки, номер ошибки прибавляется к константе vbObjectError. Например, чтобы сгенерировать ошибку номер 999, сле¬ дует назначить для свойства Number объекта Err значение vbObjectError + 999. Результирующий номер возвращается в приложение-клиент. Это гарантирует, что пользовательские номера ошибок не пересекутся со встроенными ошибками Visual Basic. источник Необязательный. Строковое выражение, содержащее имя объекта или приложения, которое генерирует ошибку. Если значение не установле¬ но, используется программный идентификатор текущего проекта Visual Basic. описание Необязательный. Строковое выражение, содержащее описание ошиб¬ ки. Если не указано, проверяется номер ошибки. Если номер может быть сопоставлен с ошибкой выполнения Visual Basic, возвращается описа¬ ние этой ошибки Visual Basic. Если такого соответствия не найдено, возвращается сообщение "Application-defined or object-defined error" (Ошибка, определенная в приложении или объекте). help_4>aCm Необязательный. Полный путь к файлу, содержащему помощь по дан¬ ной ошибке. Если не указано, Visual Basic использует полный путь к файлу помощи Visual Basic. help_KOHmeKcm Необязательный. Идентификатор контекста помощи по данной ошибке в файле помощи. В следующем примере кода показана обработка ошибок от компонента: Код в компоненте: Dim Salaryl As Single Public Property Let Salary(ByVal newSalary As Single) If newSalary < 0 Then Err.Raise 12345 + vbObjectError, , "Жалование должно быть положительным" Else Salaryl = newSalary End If End Property Public Property Get Salary() As Single Salary = Salaryl End Property Код в приложении-клиенте: Private Sub Commandl Click() Dim x As Company.Employee ' Объектная переменная ' нового служащего компании On Error GoTo HandleError Set x = New Company.Employee
204 Использование событий x.Salary = -50 ' Оклад нового служащего MsgBox x.Salary Exit Sub HandleError: If Err.Number = 12345 + vbObjectError Then MsgBox "Жалованье должно быть положительным" End If End Sub Останов на ошибке Порядок ввода Visual Basic режима останова при возвращении программным компонентом ошибки можно изменить установкой опций Error Trapping на вкладке General окна диалога Options. Значения этих опций полезно знать, так как они могут обусловливать останов приложения на ошибке, даже если для данной ошибки создана процедура обработки. В следующей таблице приведены три опции установки точек прерывания: Опция Описание Break on All Errors Перевод проекта в режим прерывания обусловливает любая ошибка Break in Class Module Перевод проекта в режим прерывания обусловливаетлюбая необ¬ рабатываемая ошибка, возникшая в строке программного кода в модуле класса. При отладке проекта сервера ActiveX путем запу¬ ска испытательной программы-клиента ActiveX издругого проекта, следует установить эту опцию в проекте сервера ActiveX, чтобы вводить режим останова на ошибках в модулях класса, вместо передачи ошибок в испытательную программу. Break on Unhandled Errors Если процедура обработки ошибки активна, ошибка обрабатывается без ввода режима останова. Если активной процедуры обработки ошибок не имеется, ошибка обусловливает перевод проекта в режим останова. Необрабатываемая ошибка в модуле класса обусловит перевод проекта в режим останова в строке кода класса. 8.5. Использование событий Для передачи клиентам сообщений о произведенных действиях программные компоненты могут использовать события. Чтобы установить это отношение, в клиенте необходимо специфицировать, что, когда происходит определенное действие, информацию обеспечи¬ вает компонент. Например, в клиенте может требоваться получение информации, когда изменилось значе¬ ние базы данных или когда поступило сообщение. Такое уведомление может передать компонент. 8.5.1. Создание событий класса Для инициирования события из программного компонента необходимо проделать следую¬ щие шаги: 1. Объявитьсобытие. 2. Сгенерировать событие.
Гпава 8. Создание программных компонентов ActiveX 205 Объявление события Событие объявляется в разделе Declarations модуля класса с помощью ключевого слова Event. Это делает событие видимым для клиентов, которые используют компонент: Public Event Status(ByVal StatusText As String) Инициирование события Когда требуется сгенерировать событие для приложения-клиента, вызывается оператор RaiseEvent и передается имя события и все требуемые для события параметры. В следую¬ щем фрагменте кода инициируется событие Status: ' Метод, выполняющий обработку заказа Public Sub SubmitOrder() RaiseEvent Status("npoBepKa состояния кредита...") ' Задержка, моделирующая проверку EndTime = Timer + 2 Do While Timer < EndTime DoEvents Loop RaiseEvent Status("06pa6oTKa заказа...") ' Некоторая обработка EndTime = Timer + 2 Do While Timer < EndTime DoEvents Loop End Sub Этот подход можно использовать для передачи информации статуса в приложение-клиент при выполнении долготекущего метода. 8.5.2. Обработка событий в приложении-клиенте При обработке события, которое обеспечивается программным компонентом ActiveX, необ¬ ходимо проделать следующие шаги: 1. ОбъявитьпеременнуюУУ№Еуеп1з. 2. Создать процедуру обработки события. 3. Создать экземпляр класса, который определяется переменной WithEvents. Объявление переменной WithEvents Переменная WithEvents объявляется для хранения ссылки на объект, который будет обес¬ печивать уведомление о событии. Для этого вводится стандартный оператор Dim и ключе¬ вое слово WithEvents, как в следующем примере: Dim WithEvents Order As Projectl.Classl После объявления переменной WithEvents она появляется в окне программного кода как объект, вместе с ассоциированными событиями (рис. 8.10). Написание программного кода события В процедуры, ассоциируемые с переменной WithEvents, вносится программный код, пред¬ назначенный для обработки сообщений событий:
206 Использование событий Рис. 8.10. После объявления переменной WithEvents она появляется в окне редактора кода как объект. Private Sub Order Status(ByVal StatusText As String) Debug.Print StatusText ' Печать в окне Immediate End Sub Создание экземпляра объекта При создании экземпляра объекта, который обеспечивает события, и при сохранении этого экземпляра в переменной, описанной с ключевым словом WithEvents, любые события, генерируемые объектом, будут автоматически переданы в соответствующую процедуру обработки события. В следующем фрагменте кода создается экземпляр объекта Order и вызывается метод SubmitOrder, который затем инициирует события (рис. 8.11): Private Sub Commandl Click() Set Order = New Projectl.Classl Order.SubmitOrder End Sub Информацию относительно использования асинхронных сообщений в клиентах см. в разделе "Сообщения сервера с использованием событий" главы 7 "СОМ и создание клиентов ActiveX". 8.5.3. Выполнение с помощью событий асинхронных вызовов Если предвидится выполнение программным компонентом долготекущих операций, эти операции можно реализовать как асинхронный метод. Обычно, когда клиент выполняет метод в компоненте, клиент должен дождаться заверше¬ ния обработки, прежде чем он может продолжать выполнение. Когда используется асинх¬ ронный метод, клиент может продолжать работать, в то время как компонент также работает в фоновом режиме. Для создания асинхронного метода: 1. Создать метод в компоненте, который активирует таймер на форме. Это позволит немедленно возвращать управление приложению-клиенту, если в процеду¬ ре не выполняется никакой обработки.
Гпава 8. Создание программных компонентов ActiveX 207 Рис. 8.11. Генерирование событий экземпляром объекта. 2. В событии Timer вызвать другой метод компонента, который выполняет операцию, тре¬ буемую компонентом. 3. Когда этот метод заканчивает обработку, сгенерировать для клиента событие, чтобы сообщить ему, что метод завершил обработку. 4. В клиенте добавить программный код к процедуре возвращаемого события. Приложение-клиент вызывает метод сервера, который запускает фоновый процесс. За¬ тем по завершении обработки клиент от программного компонента получает событие. Примечание: Асинхронные программные компоненты, предназначенные для автоматического вы¬ полнения, не могут содержать формы. В этих компонентах для реализации функциональных возможностей таймера без использования в форме элемента управления Timer можно применить функции Windows API SetTimer и KillTimer. Отмена процедуры события Когда программный компонентобеспечивает асинхронные методы, требуется предоставить пользователям способ отменить выполнение этих методов до их завершения. Чтобы позволить в клиенте отменить продолжительный асинхронный метод, можно доба¬ вить метод статуса или прогресса, который принимает параметр Cancel. Если, например,
208 Реализация интерфейса клиент во время выполнения метода устанавливает параметр Cancel в True, компонент останавливает асинхронный метод. Например, можно в приложении-клиенте добавить сле¬ дующий программный код: Dim WithEvents x As Objectl Sub.... x.DoAsynchronousTask CancelDialog.Show ' Вывести на экран форму с кнопкой "Отмена" End Sub Sub x InProgress(PercentDone, bCancel) ' В процессе выполнения изменять строку прогресса bCancel = CancelDialog.bCancel End Sub В компоненте соответствующий программный код будет выглядеть примерно так: Dim bCancel as Boolean Event InProgress(ByVal pd as Long, ByRef cancel as Boolean) Private Sub ...(...) bCancel = False RaiseEvent InProgress(percent, bCancel) If bCancel Then ' Снять задачу End If End Sub В коде, приведенном выше, принимается, что пользовательский интерфейс приложения- клиента включает окно диалога, содержащее кнопку "Отмена". В обоих примерах кода переменная Boolean bCancel используется для установки флага, который указывает, нажал ли пользователь кнопку "Отмена". Если в любое время пользователь нажимает кнопку "Отмена", флаг bCancel в процедуре Sub устанавливается в True и логика оператора If в процедуре события InProgress отменяет выполнение задачи. Примечание: В событии InProgress использование ключевого слова ByVal для передачи параметра означает, что изменение параметра, которое производится в клиенте, не будет замечено компо¬ нентом. Использование ключевого слова ByRef, наоборот, означает, что компонент будет видеть изменение значения. 8.6. Реализация интерфейса Интерфейсы — группы функций, формирующие механизмы связи, через которые сообща¬ ются компоненты клиента и сервера. Интерфейсы предоставляют стандартизованный до¬ ступ к методам и свойствам (функциональным возможностям), обеспечиваемым серверами. Интерфейс определяет поведение объекта, создаваемого из класса. Реализация этих функциональных возможностей включает три задачи: 1. Создание абстрактного класса.
Гпава 8. Создание программных компонентов ActiveX 209 2. Разработка компонента, который использует абстрактный класс. 3. Разработка приложения-клиента, которое использует компонент. В этом разделе показано, как определять и реализовывать интерфейсы и как через интер¬ фейсы обеспечить преемственность функций компонента, позволяющую ему продолжать работать с клиентами после модернизаций. 8.6.1. Использование интерфейсов Для определения интерфейса используется абстрактный класс, а при его реализации интерфейс применяется кдополнительным классам, в которых разными способами конкре¬ тизируется поведение интерфейса. Использование абстрактных классов Назначение абстрактного класса — обеспечить шаблон для интерфейса, который затем применяется в других классах. Абстрактный класс не содержит никакого программного кода реализации интерфейса — он содержит лишь объявления. При конкретизации интерфейса вводится ключевое слово Implements и имя абстрактного класса в разделе Declarations других модулей класса. Фактическая реализация интерфейса выполняется уже внутри этих классов. Выгоды реализации интерфейса абстрактного класса: • это позволяет многократно использовать программный код; • это позволяет получать неограниченное количество разных реализаций для сходных видов объектов (полиморфизм классов); • это позволяет начать разработку объектов с минимальными функциональными возможно¬ стями, постепенно в ходе эксплуатации объектов придавая им дополнительные функции. Поддержка более поздних версий компонентов При использовании для создания интерфейса абстрактного класса разработчик специфици¬ рует, какие функции сможет предоставить объект. При этом должно быть гарантировано, что приложения-клиенты, разрабатываемые с использованием компонента, всегда будут работать, так как оригинальный интерфейс будет поддерживаться. Оригинальный интерфейс может расширяться, но оригинальные возможности, на которые первоначально ориентировался разработчик приложения-клиента, останутся доступными клиенту. Это защитит авторов клиента от проблем, вызванных модернизацией компонента, и в то же время позволит разработчикам расширять компоненты. Информацию, связанную с версиями компонентов, см. в разделе "Совместимость версий". Информацию относительно работы интерфейсов см. в разделе "Использование интерфей¬ сов" главы 7 "Создание клиентов ActiveX". Шаги реализации интерфейса Шаги реализации интерфейса на базе абстрактных классов в Visual Basic: 1. Созданиеабстрактныхклассов. а) Открыть новый проект ActiveX EXE или ActiveX DLL. б) В модуле класса добавить требуемые свойства и методы интерфейса. в) Специфицировать имя класса для интерфейса. г) В меню File выбрать команду Make < проект >, чтобы построить исполняемый файл проекта.
210 Реализация интерфейса Библиотека типов для результирующего файла .exe или DLL будет содержать инфор¬ мацию, требуемую оператором Implements в классах компонента, создаваемого из абстрактного класса. В следующем фрагменте кода для класса создаются шаблоны для двух пользователь¬ ских методов: ' Программный код методов для абстрактного модуля класса IPayroll Public Sub Calculate() ' Здесь пока нет никакой программной реализации End Sub Public Sub Deposit() ' Здесь - некоторая общая программная реализация End Sub 2. Разработка компонента с использованием абстрактных классов. а) Добавить в компоненте ссылку на библиотеку типов для абстрактных классов. б) Используя оператор Implements, применить интерфейс, определенный в абстрактном классе, к другим классам. в) Во вторичных классах добавить к процедурам свойств и методов программный код реализации. г) Скомпилировать компонент. В следующем примере показан программный код реализации для класса, в котором используются пользовательские методы, объявленные в предыдущем примере: ' Этот класс обеспечивает создание объектов, в которых ' реализуется ' абстрактный класс IPayroll Implements IPayroll Private Sub IPayroll_Calculate() ' Программный код реализации метода абстрактного класса End Sub Private Sub IPayroll Deposit() ' Здесь - расширение программной реализации метода ' применительно к этому типу объекта End Sub Таким образом, можно разрабатывать разные классы, в которых различными способами реализуются пользовательские свойства и методы, но используется один абстрактный класс. 3. Разработка приложения-клиента, в котором используется компонент. а) В приложении-клиенте добавить ссылку на компонент. б) В приложении-клиенте добавить ссылку на библиотеку, которая содержит абстракт¬ ные классы. в) Скомпилировать приложение. г) Создать программу Setup, которая установит клиент, компонент и библиотеку типов, если компонент работает в режиме out-of-process.
Гпава 8. Создание программных компонентов ActiveX 211 8.7. Прочие аспекты программных компонентов В этом разделе описываются различные способы улучшения и расширения функциональ¬ ных возможностей программных компонентов. 8.7.1. Использование именованных констант Именованная константа — именованный программный элемент, который сохраняет посто¬ янное значение в течение выполнения программы и может использоваться вместо лите¬ ральных значений. Например, если требуется создать окно сообщения, которое включает кнопки Yes и No, для параметра можно использовать именованную константу vbYesNo вместо литерального значения. Именованные константы упрощают чтение и сопровождение программного кода. Создание именованных констант Для определения пользовательского набора именованных констант создается перечисле¬ ние, включающее константы. В следующем примере кода показано, как создать перечисление и использовать именован¬ ную константу с простым методом: ' Объявление константы перечисляемого типа Public Enum Temp Cold = -5 Warm = 18 Hot = 30 End Enum Public Sub ReportTemp(x As Temp) If x < Cold Then MsgBox "Оденьтесь потеплей" End If End Sub Члены перечисления могут быть доступны пользователям компонента, если перечисление объявлено как Public и включено в один из модулей public, который определяет класс. Хотя перечисление объявляется в модуле, который определяет класс, в библиотеке типов он имеет глобальную область определения. Примечание: Значения членов перечисления могут не быть последовательными или непрерывными. Примечание: Во избежание конфликтов имен членов перечисления, в имя члена рекомендуется вводить уникальный префикс из символов нижнего регистра, который идентифицирует тип и компонент, которому принадлежит перечисление. Например, встроенное перечисление VbDayof- Week в Visual Basic содержит числовые константы с английскими названиями дней недели — vbMonday, vbTuesday и т. д. 8.7.2. Информация о компоненте и Help В целях облегчения использования программных компонентов для каждой из функций — членов класса можно добавлять описательную текстовую и контекстно-чувствительную подсказку. Примечание: Функция-член — одна из группы связанных функций, которые формируют интерфейс класса.
212 Прочие аспекты программных компонентов Для обеспечения этой информации необходимо заполнить соответствующие поля в окнах диалога Procedure Attributes и Project Properties (см. рис. 8.4). Эта информация будет после этого доступна как контекстно-чувствительная подсказка в окне Object Вгои^егдпя текущего проекта и в любом приложении-клиенте, которое исполь¬ зует данный программный компонент. Примечание: Если свойство определено как переменная Public, установить для него описания нельзя, но можно ввести описания для свойств, определенных через процедуры Property. Чтобы ввести информацию помощи для метода или свойства: 1. Открыть проект для программного компонента ActiveX. 2. Открыть окно редактора кода для модуля класса. 3. В меню Tools выбрать Procedure Attributes. 4. Заполнить поля Description и Help Context ID для каждой процедуры. 8.7.3. Глобальность данных В приложении Visual Basic данные, объявленные как Public в стандартном модуле, стано¬ вятся глобальными и будут доступны в любом месте приложения. Глобальные данные компонента могут или не могут использоваться приложением-клиен- том, в зависимости от того, как компилируется сервер — как исполняемый файл или DLL, и в зависимости от значения свойства Instancing класса. Исполняемый модуль ActiveX При создании исполняемого файла ActiveX и установке для свойства Instancing класса значения MultiUse исполняемый файл может обслуживать несколько клиентов. При первом запросе экземпляра этого класса сервер будет запущен. При следующем запросе экземпляра этого класса сервер уже будет выполняться и просто создаст новый экземпляр класса. Оба экземпляра класса будут работать с одними и теми же глобальными данными. Если создается исполняемый файл ActiveX и для свойства Instancing класса устанавлива¬ ется значение SingleUse, при каждом последующем запросе нового экземпляра данного класса будет запускаться новая копия сервера. Глобальные данные в данном случае не могут разделяться между экземплярами исполняемого файла. ActiveX DLL Если создается ActiveX DLL, для свойства Instancing необходимо установить значение MultiUse (или PublicNotCreatable). Компонент-сервер выполняется в том же пространстве процесса, что и приложение-клиент. Для каждого приложения-клиента используется отдельный экземпляр DLL, и глобальные данные не могут быть разделены между клиентами. Однако, если одно приложение-клиент создает несколько экземпляров класса, все экземпляры используют один экземпляр DLL и совместно используют все глобальные данные. 8.7.4. Объявление методов Friend Если требуется, чтобы объекты программного компонента взаимодействовали друг с дру¬ гом, но разработчик не хочет делать их доступными приложениям-клиентам, можно исполь¬ зовать ключевое слово Friend, чтобы объявить метод таким образом, что его область определения будет доступна только другим объектам в компоненте.
Гпава 8. Создание программных компонентов ActiveX 213 Методы Public в классе могут вызываться другими объектами, но они могут также вызывать¬ ся клиентами. Методы Private не могут вызываться снаружи компонента, и они также невидимы для других объектов внутри компонента. Методы, объявленные с ключевым словом Friend ("друзья"), видимы другим объектам в компоненте, но невидимы для клиентов, так как методы Friend не добавляются к библиотеке типов и не становятся частью public интерфейса. Примечание: С ключевым словом Friend можно объявлять также процедуры Property. Процедуры Property, которые формируют свойство, могут иметь разные уровни видимости. В следующем примере метод VB класса Class1 вызывается процедурой в классе Class2: ' Программный код в Classl ' может вызываться из других модулей класса, ' но не извне проекта Friend Sub VB() MsgBox "Visual Basic" End Sub ' Код в Class2 Public Sub HiVB() Dim x As New Classl x.VB End Sub ' Код в модуле формы (модуль класса, ' имеющий внешнее представление) Private Sub Form Load() Dim xl As New Class2 x1.HiVB End Sub Рис. 8.12. Вызов метода Friend.
214 Прочие аспекты программных компонентов 8.7.5. Создание объектной модели Объектная модель определяет отношение между объектами в программном компоненте. Некоторые объекты зависят от других объектов. Эти зависимые объекты существуют только внутри контекста другого объекта. Например, в Microsoft Excel объект Button (кнопка) не может существовать сам по себе. Он существует только внутри объекта Worksheet (рабочий лист). Для создания объекта Button в приложении-клиенте не может использоваться функ¬ ция CreateObject или оператор Set объект = New класс. Новый объект Button создается методом Add, который обеспечивает объект Worksheet. В Visual Basic можно создавать программный компонент ActiveX, который формирует неко¬ торую объектную модель. Определяя отношения между объектами, которые используются в программе, объектная модель организует объекты, упрощая программирование. Создание объектной модели для компонента ActiveX включает следующие шаги: 1. Создать объект высшего уровня, установив для свойства Instancing класса значение SingleUse или MultiUse. 2. Создать зависимые объекты, установив свойство Instancing кпасса равным PublicNotCreatable. Для объекта высшего уровня можно описать метод, который создает зависимый объект и возвращает ссылку на вновь созданный объект. 8.7.6. Хранение объектов в семействах Создание семейства объектов позволяет хранить связанные элементы вместе. В Visual Basic объект Collection — стандартный объект. Он может быть создан таким же образом, как и другие объекты: Dim Employees As New Collection Объекты типа Collection имеют стандартные методы Add и Remove (добавить и удалить) и свойство Count (количество объектов в семействе). В следующем фрагменте кода создает¬ ся новый объект Employee, который добавляется к семейству Employees: Public Sub AddEmp (s As String, i As Integer) Dim Emp As New Employee ' Создать объект для нового служащего Emp.FName = s Emp.ID = i Employees.Add Item:=Emp, Key:=Emp.ID ' Добавить служащего с его номером End Sub Хранение связанных объектов в семействе позволяет работать с этими объектами как с единицей или группой. Например, как показано в следующем примере, семейство Employe¬ es из предыдущего примера можно использовать для распечатки списка всех служащих: Private Sub cmdPrintEmployees Click() For Each x In Employees Print x.FName, x.ID Next x End Sub 8.7.7. Совместимость версий Visual Basic обеспечивает совместимость версий, что позволяет модернизировать компо¬ ненты, поддерживая совместимость с программами, скомпилированными с более ранними версиями компонента. Опции совместимости можно установить, выбрав Project Properties в меню Project и затем открыв вкладку Component окна диалога Project Properties.
Гпава 8. Создание программных компонентов ActiveX 215 В разделе Version Compatibility можно выбрать одну из трех опций, перечисленных в следующей таблице: Опция Результат No Compatibility Каждый раз при компиляции компонента генерируется новая информация библиотеки типов, включая новые идентификаторы классов интерфейсов. Между версиями компонента не сохраняется никакого наследования. Прило¬ жения, которые компилировались с предыдущей версией компонента, не смогут использовать последующие версии. Эту опцию совместимости следу¬ ет включать при открытии нового проекта или если устанавливать совмести¬ мость с более ранней версией компонента не требуется. Project Compatibility При каждой компиляции компонента генерируется новая информация библи¬ отеки типов, но идентификатор библиотеки типа остается прежним, поэтому испытательные проекты могут обрабатывать ссылки на проект компонента. Эту опцию совместимости следует включать при открытии нового проекта. Binary Compatibility При компиляции компонента Visual Basic создает новые идентификаторы классов и интерфейсов, только в случае необходимости, и сохраняет инфор¬ мацию идентификаторов классов и интерфейсов из предыдущей версии. Программы, скомпилированные с более ранней версией, продолжают рабо¬ тать. Эту опцию совместимости следует использовать, когда необходимо гарантировать, что модернизации компонента не повлияют на работу клиен¬ тов, скомпилированных с более ранней версией компонента. Visual Basic предупреждает разработчика, когда изменения в программном коде могут обусловить несовместимость новой версии с ранее скомпилированными приложениями. Рис. 8.13. Вкладка Component окна диалога Project Properties.
216 Пример: Создание программного компонента Информацию относительно идентификаторов интерфейсов см. в разделе "Взаимодействие клиента с сервером" главы 7 "СОМ и создание клиентов ActiveX". 8.7.8. Управление занятым компонентом При вызове программного компонента приложение-клиент может получить сообщение "Component Busy", означающее, что сервер занят. Например, это происходит, когда компо¬ нент выполняет продолжительную операцию, а клиент также пытается загрузить его зада¬ нием. Настроить вывод этого сообщения пользователям можно, используя свойства объекта App (например, OLEServerBusyRaiseError, OLEServerBusyTimeout или OLEServerBusyMsgText). В следующем фрагменте кода показано, какустановить пользовательский заголовок и текст сообщения. Эти установки переопределяют установки в окне диалога Component Busy. Public Const App Title = "Приложение проверки кредита" App.OLEServerBusyMsgTitle = App_Title App.OLEServerBusyMsgText = "Приложение не отвечает по причине чрезмерной загрузки сети. Если пауза продлится более пяти минут, можно отменить этот запрос и повторить попытку позже" 8.8. Пример: Создание программного компонента В этом примере создается программный компонент, который предоставляет один объект. Объект CreditCard будет использоваться для моделирования проверки и подтверждения приобретения товара через кредитную карточку. В следующей таблице представлены используемые интерфейсы: Имя Назначение Тип CardNumber Номер карточки Свойство ExpireDate Дата закрытия карточки Свойство PurchaseAmount Сумма покупки Свойство Approve Подтверждение кредита Метод 8.8.1. Создание программного компонента 1. Создать новый проект ActiveX DLL. При выборе проекта ActiveX DLL автоматически устанавливаются свойства модуля класса и проекта. 2. Установить свойства проекта, как показано в следующей таблице: Свойство Установка Project Name CC Project Description Объект "Кредитная карточка" Unattended Execution Установить флажок 3. Установить для свойства Name модуля класса значение CreditCard. 4. Сохранить модуль класса как Cc.cls и проект как Cc.vbp.
Гпава 8. Создание программных компонентов ActiveX 217 8.8.2. Создание свойств и методов 1. В модуле класса, используя переменные Public, создать два свойства с информацией из следующей таблицы: Имя свойства Тип данного CardNumber lnteger ExpireDate Date Информацию относительно создания свойств и методов см. в разделе "Создание Свойств". 2. Используя процедуры Property, создать свойство под именем PurchaseAmount: а) Создать private переменную уровня модуля, которая будет хранить значение суммы покупки. б) В процедуре Property Get вернуть значение этой переменной. в) В процедуре Property Let проверить, чтобы возвращаемое значение переменной было больше нуля. Если значение больше нуля, присвоить переменной сумму приобрете¬ ния. Если оно меньше нуля, установить переменную в ноль. Дополнительную информацию относительно процедур свойств см. в разделе "Использо¬ вание процедур Property для создания свойств". 3. Используя функцию Public, создать метод Approve, который возвращает значение типа Boolean. Если проверка кредитной карточки прошла успешно, этот метод должен вернуть значе¬ ние True; если с кредитом имеются проблемы — значение False. Для проверки кредитной карточки можно использовать следующую логику: Если ... то ... PurchaseAmount < 1000 And ExpireDate > Now() Approve = True PurchaseAmount >= 1000 And ExpireDate <= Now() Approve = False 4. Сделать CardNumber умолчательным свойством для класса CreditCard (в окне Procedure Attributes). Программный код для модуля класса CreditCard должен выглядеть примерно следующим образом: Option Explicit Public CardNumber As Integer Public ExpireDate As Date Private msngAmount As Single Public Property Get PurchaseAmount() As Single PurchaseAmount = msngAmount End Property Public Property Let PurchaseAmount(ByVal sngAmount As Single) If sngAmount > 0 Then msngAmount = sngAmount ' Сохранить в private переменной модуля Else ' Сумма покупки меньше нуля недействительна; сбросить в ноль msngAmount = 0 End If End Property Public Function Approve() As Boolean
218 Пример: Определение и использование событий ' Логика для проверки операции по кредитной карточке If msngAmount < 1000 And ExpireDate > Now() Then Approve = True Else MsgBox "С вашим кредитом - проблемы" Approve = False End If End Function 5. Сохранить проект. 6. Скомпилировать проект как Cc.dll. Этот файл .dll автоматически активирует опцию Project Compatibility в окне диалога Project Properties. Это гарантирует, что в случае проведения изменений в проекте, GUID останется тем же и ссылки из приложения-клиента не будут потеряны. 8.8.3. Создание приложения-клиента 1. Чтобы добавить новый проект к проекту CreditCard, выбрать Add Project в меню File. 2. Когда будет запрошен тип проекта, выбрать Standard EXE и затем щелкнуть Open. Этот проект будет использоваться как клиент, который тестирует компонент. 3. В окне диалога References добавить ссылку на проект Cc. 4. Объявить переменную уровня модуля под именем cc1 типа Cc.CreditCard. 5. Добавить к форме кнопку "Подтверждение" (элемент управления CommandButton) и текстовое поле "Сумма покупки" (TextBox). 6. В процедуре обработки события Click для элемента управления CommandButton доба¬ вить следующий программный код: Set ccl = New Cc.CreditCard ' Объект класса CreditCard из проекта Cc.dll ccl.ExpireDate = "1/1/99" ccl.PurchaseAmount = Textl.Text ccl.CardNumber = 1234 MsgBox ccl.Approve 7. В окне Project Group (Project Explorer) щелкнуть правой кнопкой мыши Project1 и затем выбрать Set as Start Up в контекстном меню (рис. 8.14). Эта команда устанавливает Form1 как форму запуска для проекта. 8. Запустить приложение, ввести значение в поле "Сумма покупки" и нажать кнопку "Под¬ тверждение". Можно также нажать F8, чтобы запустить приложение-клиент в режиме "шаг с заходом" (Step lnto) и пройти пошагово через программный код. В момент установки свойства PurchaseAmount и вызова метода Approve выполнение фактически заходит в проект CreditCard. 9. Попытайтесь ввести значение PurchaseAmount на 2000. Метод Approve должен вернуть False (рис.8.15). 8.9. Пример: Определение и использование событий В этом примере события используются для передачи приложению-клиенту информации прогресса выполнения обработки методом Approve.
219 Рис. 8.15. Сообщение из метода компонента. 8.9.1. Определение и использование события Status 1. В модуле класса CreditCard в начало процедуры Approve добавить следующий програм¬ мный код: Public Event Status(ByVal StatusText As String) ' В разделе Declaration Dim sngEndTime As Single RaiseEvent Status("fl03B0H в банк...") ' Моделирование задержки при дозвоне в банк sngEndTime = Timer + 2 Рис. 8.14. Установка проекта запуска для группы проектов. Сообщение компонента - Сообщение клиента
220 Пример: Определение и использование событий Do While Timer < sngEndTime DoEvents ' Уступить ресурсы другим процессам Loop RaiseEvent Status("06pa6oTKa кредитной карточки...") ' Моделирование задержки при обработке карточки sngEndTime = Timer + 2 Do While Timer < sngEndTime DoEvents ' Уступить ресурсы другим процессам Loop В этом коде вводятся две двухсекундные задержки, моделирующие время, необходимое для дозвона в банк и обработки информации кредитной карточки. Перед каждой задерж¬ кой генерируется событие, сообщающее приложению-клиенту относительно текущего статуса обработки. 2. В модуле класса CreditCard объявить событие Status с одним строковым параметром. 3. Создать новую версию Cc.dll. 4. В приложении-клиенте добавить надпись, в которой будет отображаться информация статуса (см. рис. 8.16) 5. В приложении-клиенте добавить объявление переменной cc1 с ключевым словом WithEvents: Dim WithEvents ccl As CC.CreditCard ' В разделе Declaration модуля формы При этом Visual Basic добавляет в окно редактора кода новый объект с одной новой процедурой события, именованной Status (см. рис. 8.16). 6. В событии Status вывести на экран текст статуса в элементе управления Надпись (в примере — Label2): Private Sub ccl Status(ByVal StatusText As String) Label2.Caption = StatusText End Sub 7. Сохранить группу проектов и протестировать приложение. Каждое из сообщений статуса должно быть показано в надписи в течение двух секунд. Рис. 8.16. Создание события в программном компоненте.
Гпава 9. Создание элементов управления ActiveX 221 Глава 9. Создание элементов управления ActiveX Элемент управления ActiveX — объект, который помещается в форму для расширения возможностей взаимодействия пользователя с приложением. С элементами управления ActiveX связаны события, и они могут быть включены в другие элементы управления. Эти элементы управления имеют расширение имени файла .ocx. Любые элементы управления ActiveX, созданные в Visual Basic, могут использоваться в приложении-клиенте ActiveX, например в другом приложении Visual Basic, в Microsoft Office и Internet Explorer. 9.1. Введение в элементы управления ActiveX 9.1.1. Классы элементов управления Элементы управления — объекты многократного использования, которые включают визу¬ альные элементы и программный код. В процессе разработки приложения элементы управ¬ ления должны быть помещены в некоторый тип контейнера — форму или непосредственно приложение. Элемент управления, который создается в Visual Basic, известен как класс элемента управ¬ ления, который действует как шаблон для этого элемента управления. При размещении элемента управления в форме создается объект — экземпляр класса этого элемента управления (чтобы распределить и инициализировать структуры данных объекта в памяти), как показано на следующей иллюстрации: Рис. 9.1. Создание экземпляра класса элемента управления. 9.1.2. Элементы управления — компоненты Элементы управления могут компилироваться в элементы управления — компоненты, также известные как файлы .ocx. Элемент управления — компонент может обеспечивать больше чем один вид элемента управления. Проект элемента управления ActiveX в Visual Basic содержит один или больше файлов .ctl, каждый из которых определяет отдельный класс элемента управления. При компиляции проекта элемента управления создается файл .осхдля элемента управления — компонента. Единственный файл .ocx может содержать несколько элементов управления, как показано на рис. 9.2. 9.1.3. Элементы управления ActiveX и программные компоненты Элементы управления отличаются от программных компонентов. Программный компонент — приложение, которое предоставляет некоторые функциональ¬ ные возможности, которые могут многократно использоваться другим приложением через Класс элемента управления Экземпляр элемента управления
222 Введение в элементы управления ActiveX Составляющие Компонент .ocx элементы управления Рис. 9.2. Компонент .ocx и составляющие элементы управления. Компонент .ocx Формирует пользовательский интерфейс События генерируются действиями пользователя Рис. 9.3. Элементы управления и программные компоненты. Автоматику. Элементы управления — компоненты содержат визуальные элементы, кото¬ рые могут генерировать события, основанные на действиях пользователя (рис. 9.3). 9.1.4. Объект UserControl Объект UserControl — основа для формирования элементов управления. Каждый элемент управления ActiveX, который создается с помощью Visual Basic, содержитобъект UserControl. Объекты UserControl содержат модули программного кода и визуальные дизайнеры. При открытии UserControl в режиме разработки объект выводится в окне визуального дизайнера. Визуальный дизайнер можно использовать как контейнер для размещения в объекте User¬ Control дополнительных элементов управления, как если бы это была форма Visual Basic (рис. 9.4). Файлы, ассоциируемые с объектом UserControl Исходный текст и значения свойства для объекта UserControl хранятся в текстовых файлах с расширением .ctl. Файл .ctl эквивалентен файлу Visual Basic .frm, который используется для хранения аналогичной информации для формы. Графические элементы, которые не могут быть сохранены как текст, хранятся в файлах с расширением .ctx. Формат файла .ctx эквивалентен формату файла .frx, который использу¬ ется для хранения графических элементов в формах. Программный компонент Решает некоторые реальные задачи, предоставляя клиенту свои свойства методы и события Приложение-клиент Использует свойства, методы и события компонента
Гпава 9. Создание элементов управления ActiveX 223 Рис. 9.4. Объект UserControl и его окно кода. 9.1.5. Тиражирование элементов управления ActiveX Способ распространения элемента управления зависит от того, как элемент управления будет использоваться. Элемент управления можно тиражировать либо как компилирован¬ ный компонент, либо включать исходный текст элемента управления как часть приложения. Элемент управления ActiveX может использоваться во многих разных типах приложений, таких, как приложения Microsoft Office, Internet Explorer и формы Visual Basic. Элементы управления ActiveX можно использовать с локальными проектами или загружать их на Web-страницу. Тиражирование элементов управления как компилированных компонентов Чтобы иметь возможность распространять с приложением компилированный элемент управления — компонент (файл .ocx), необходимо создать элемент управления ActiveX как public класс. Подключить компилированный компонент можно через программу Setup приложения. Тиражирование элементов управления в виде исходного текста Файл .ctl можно включать в любой проект Visual Basic. При построении приложения исход¬ ный текст элемента управления компилируется как часть исполняемого файла приложения. Преимущества распространения элементов управления в виде исходного текста: • не требуется тиражировать и устанавливать файл .ocx; • поддерживается независимость версий, так как версия исходного текста элемента управ¬ ления компилируется в приложение. Недостатком распространения элементов управления в виде исходного текста является требование дополнительного дискового пространства, так как каждое приложение включает весь исходный текст для элемента управления.
224 Создание пользовательского интерфейса элемента управления 9.1.6. Шаги создания элемента управления ActiveX При формировании элемента управления ActiveX выполняются следующие шаги: 1. Создать пользовательский интерфейсдля элемента управления. 2. Создать и установить свойства и методы элемента управления. 3. Определить порядок реакции элемента управления на события. 4. Добавить страницы свойств для элемента управления. 5. Отладить и испытать элемент управления. 9.2. Создание пользовательского интерфейса элемента управления Процедура создания пользовательского интерфейса элемента управления ActiveX подобна построению стандартной формы Visual Basic. На полотне контейнера помещаются элемен¬ ты управления и затем вводится программный код, который определяет поведение этих элементов управления. Однако в отличие от формы элемент управления действует как компонент внутри приложе¬ ния. Приступая к разработке элемента управления, полезно изучить реализацию существу¬ ющих элементов управления. Например, если разрабатывается элемент управления, который принимает ввод, можно просмотреть свойства, методы и события, обеспечиваемые стандартным элементом управления TextBox. 9.2.1. Добавление составляющих элементов управления Элемент управления ActiveX включает объект UserControl и составляющие элементы управления. Составляющий элемент управления — экземпляр элемента управления, который помеща¬ ется в объект UserControl. При размещении элемента управления ActiveX в форме, созда¬ ется экземпляр объекта UserControl, вместе с экземплярами других составляющих элементов управления, помещенных в объект UserControl. На следующей иллюстрации показан объект UserControl, в который помещены несколько составляющих элементов управления: Рис. 9.5. Элемент управления ActiveX и его конструктивы. Использование составляющих элементов управления В UserControl можно использовать любой стандартный элемент управления Visual Basic, за исключением элемента управле¬ ния OLE Container. Если требуется использовать подключаемые (не встроенные) элементы управления, их нужно внести в проект через окно диалога Components (см. рис. 1.3).
Гпава 9. Создание элементов управления ActiveX 225 9.2.2. Настройка размера элемента управления Заранее нельзя предусмотреть, как пользователи элемента управления будут работать с ним на экране, поэтому при написании программного кода для элемента управления необ¬ ходимо рассмотреть различные сценарии установления его размеров. Факторы, которые определяют вывод элемента управления на экран, включают объем доступного экранного пространства, настройки пользователя и контейнера элемента управ¬ ления. Следующие сценарии описывают общие способы изменения размеров элементов управле¬ ния: • пользователь изменяет размер элемента управления и его составляющих элементов управления в период выполнения; • разработчик формы, которая включает элемент управления, изменяет размер элемента управления и его составляющих элементов управления во время разработки. Пользователь может также изменить размер формы, которая содержит объект UserControl, состоящий, например, из командной кнопки, нескольких текстовых полей и простого списка. Если к событию Resize не добавлен соответствующий программный код, при уменьшении пользователем размера формы текстовые поля и список могут быть видны не полностью. Примечание: Контейнеры сами по себе не могут обрабатывать ошибки, возникающие во время события Resize, и в этом случае работа приложения, использующего элемент управления, может быть нарушена. Следовательно, обработку ошибок необходимо обеспечить в процедурах обработ¬ ки события Resize. 9.2.3. Настройка пользовательского интерфейса Событие Resize можно использовать для управления изменением размера элементов управления и подстройки их вида. Установка размеров составляющихэлементов управ¬ ления регулируется изменением текущих значений соответствующих свойств объекта UserControl. В следующем фрагменте кода при изменении размера объекта UserControl подстраивается ширина текстового поля: Private Sub UserControl Resize() Const MinWide = 2000 If UserControl.ScaleWidth < MinWide Then Textl.Width = 1000 Else ' Масштабировать поле в соответствии с размером UserControl Textl.Width = UserControl.ScaleWidth - Textl.Left End If End Sub 9.2.4. Создание элемента управления — контейнера Некоторые элементы управления могут действовать как контейнеры для других элементов управления. Например, можно использовать элемент управления Рамка (Frame) Visual Basic как контейнер для любых составляющих элементов управления. При выборе элемен¬ та управления Рамка в форме и при его перемещении все составляющие элементы управ¬ ления переместятся с контейнером. Чтобы можно было использовать экземпляр элемента управления ActiveX в качестве кон¬ тейнера для элементов управления другого разработчика, необходимо установить в True свойство ControlContainer объекта UserControl.
226 Создание пользовательского интерфейса элемента управления Производительность элемента управления — контейнера Если другим разработчикам разрешается помещать элементы управления в экземпляры элемента управления ActiveX, это существенно воздействует на производительность эле¬ мента управления. Размещаемые элементы управления располагаются в слое над всеми составляющими элементами управления, которые являются частью объекта UserControl. Схема элемента управления ActiveX загружается в память, и среда Windows использует эту схему для вырисовывания разных частей элемента управления ActiveX как графических объектов. Все это снижает быстродействие элемента управления. По этим причинам необходимо тщательно взвесить, целесообразно ли использовать эле¬ мент управления ActiveX в качестве контейнера для других объектов. Семейство ContainedControls Для выполнения операций с любым из размещенных элементов управления можно исполь¬ зовать семейство ContainedControls экземпляра элемента управления ActiveX, который служит контейнером для других элементов управления. Свойство ContainedControls возвращает семейство элементов управления, которые разра¬ ботчик или конечный пользователь может добавлять к элементу управления ActiveX в период выполнения. При создании элемента управления это свойство недоступно, а в период выполнения доступно только для чтения. В следующем фрагменте кода показано, как использовать семейство ContainedControls для получения имен элементов управления, содержащихся в элементе управления ActiveX: Dim CtrContained As Object For Each CtrContained In UserControll.ContainedControls MsgBox CtrContained.Name Next В этом случае, если экземпляр элемента управления ActiveX содержит две командные кнопки и свойство ControlContainer элемента управления установлено в True, элемент управления выведет на экран имена кнопок. 9.2.5. Добавление окна About Элементы управления ActiveX могут иметь свойство About. Чтобы добавить к элементу управления окно About: 1. Добавить к проекту форму About. 2. Добавить процедуру для вывода формы на экран. 3. В окне Procedure Attributes установить Procedure ID этой процедуры к AboutBox. Чтобы вывести на экран окно About для элемента управления, нужно щелкнуть кнопку с многоточием (...) в строке свойства About (рис. 9.6). 9.2.6. Специфицирование пиктограммы для панели элементов Для пользовательского элемента управления можно специфицировать растровый рисунок, которым элемент управления будет представлен на панели элементов Visual Basic, как показано на рис. 9.7. Растровые рисунки панели элементов должны быть размером 16 X 15 пикселей. Если специфицируется рисунок другого размера, он будет масштабироваться к стандартному размеру, что обычно приводит к искажению образа.
Гпава 9. Создание элементов управления ActiveX 227 Рис. 9.6. Окно About и его место в проекте. Рис. 9.7. Кнопка пользовательского элемента управления на панели элементов. Чтобы специфицировать растровый рисунок объекта UserControl, необходимо установить его свойство ToolboxBitmap.
228 Тестирование элемента управления 9.3. Тестирование элемента управления В ходе разработки элемента управления ActiveX необходимо проводить тестирование его функциональных возможностей. Разработчик, который будет использовать этот элемент управления ActiveX, должен иметь возможность работать с ним в режиме разработки. Так как элемент управления сам по себе не может быть запущен, для его тестирования потре¬ буется создать другой проект. События в элементе управления ActiveX будут вести себя по-разному, в зависимости от порядка его инициирования. Понимание этого поведения поможет разработчику правильно организовать отладку элементов управления. 9.3.1. Создание испытательного проекта При отладке элемента управления (в противоположность объектам других типов), при создании экземпляра элемента управления во время разработки некоторые части програм¬ много кода элемента управления фактически выполняются. Для выполнения программного кода в режиме разработки имеется ряд причин, в частности то, что разработчик при этом может устанавливать свойства элемента управления (то есть взаимодействует с ним). Так как элемент управления ActiveX не может выполняться автономно, то для тестирования проекта элемента управления необходимо создать другой проект .exe. Visual Basic позволя¬ ет загрузить два или больше проектов в группу проектов, которая сохраняется с расшире¬ нием .vbg. Для запуска и тестирования элемента управления используется форма в другом проекте. Для добавления испытательного проекта к группе проектов: 1. В меню File выбрать Add Project или нажать кнопку со списком Add Project на панели инструментов. Команды Open Project или New Project выбирать нельзя, так как они закроют проект элемента управления. 2. В окне диалога Add Project дважды щелкнуть пиктограмму Standard EXE, чтобы добавить проект .exe к группе проектов. В окне Project Explorer теперь будут видны оба проекта. Заголовок окна Project Explorer указывает имя группы проекта (см. рис. 9.6). Чтобы запустить программный код элемента управления во время разработки, необходимо закрыть визуальный дизайнер элемента управления. При этом Visual Basic выводит пиктог¬ рамму для элемента управления в панели элементов, что дает возможность размещать экземпляры элемента управления в форме-контейнере. 9.3.2. Отладка элемента управления и обработка ошибок После создания для элемента управления ActiveX испытательного проекта можно тестиро¬ вать и отлаживать элемент управления таким же образом, как это делается для компонента in-process. Различие между отладкой проекта элемента управления ActiveX и компонента in-process в том, что программный код компонента может выполняться в то время, когда клиент находится в режиме разработки. В обоих случаях процесс отладки происходит между компонентом и клиентом внутри одной интегрированной среды разработки (IDE). Это позволяет проходить пошагово через код клиента с заходом в компонент.
Гпава 9. Создание элементов управления ActiveX 229 Информацию относительно отладки элемента управления ActiveX см. в разделе "Тестиро¬ вание программных компонентов ActiveX" главы 8 "Создание программных компонентов ActiveX". 9.3.3. Экземпляры и события элементов управления Для успешного тестирования элементов управления полезно разобраться с поведением событий объекта UserControl. Элемент управления ActiveX — клиент, который работает в форме или контейнере другого типа. Следовательно, его события ведут себя несколько по-другому, нежели события эле¬ мента управления в форме стандартного проекта .exe. События в экземплярах элементов управления При создании элементов управления в форме или другом контейнере объект UserControl действует как шаблон для создания экземпляра класса элемента управления. В процессе создания элемента управления происходит ряд событий. Эти события и порядок, в котором они происходят, зависят от конкретных действий пользователя или системы, которые вы¬ полняются в течение периода существования экземпляра элемента управления. В следующей таблице суммируется, какие события происходят в процессе создания эле¬ мента управления: Действие пользователя Тип экземпляра элемента управления События Помещает элемент управле¬ ния в форму. Создается экземпляр пе¬ риода разработки. Initialize, lnitProperties, Resize, Paint Во время разработки запуска¬ ет приложение, содержащее элемент управления. Экземпляр периода раз¬ работки разрушается, и создается экземпляр пе¬ риода выполнения. WriteProperties, Terminate, Initialize, ReadProperties, Resize, Paint Во время разработки выходит из приложения, содержащего элемент управления. Экземпляр периода вы¬ полнения разрушается и создается. Terminate, Initialize, ReadProperties, Resize, Paint Закрывает форму, содержа¬ щую элемент управления. Экземпляр периода разра¬ ботки разрушается. WriteProperties, Terminate Запускает скомпилированное приложение. Создается экземпляр пе¬ риода выполнения. Initialize, ReadProperties, Resize, Paint 9.4. Предоставление свойств, методов и событий Как и в случае с любым стандартным элементом управления в приложении Visual Basic, элемент управления ActiveX обеспечивает свои функциональные возможности, предостав¬ ляя свойства, методы и события. Процесс создания свойств, методов и событий для элемента управления подобен созданию их для программных компонентов. Выполнить многие из процедур, ассоциированных с предоставлением свойств, методов и событий, можно с помощью мастера ActiveX Control Interface Wizard. Ниже приводится информация относительно использования процедур Property для созда¬ ния свойств, делегирования этих свойств нескольким элементам управления, а также сохра¬ нения и получения значений свойств.
230 Предоставление свойств, методов и событий 9.4.1. Построение свойств Примечание: Контейнер для элемента управления ActiveX первоначально уже обеспечивает ряд умолчательных свойств, так что разработчик должен решить, какие потребуются дополнитель¬ ные свойства. Создание свойства Для создания свойств для элементов управления используются процедуры Property. Про¬ цесс создания свойства для элемента управления подобен созданиюсвойства для програм¬ много компонента. Дополнительную информацию см. в разделе "Использования процедур Property для создания свойств" главы 8 "Создание программных компонентов ActiveX". Для элементов управления нельзя использовать переменные public для хранения значения свойства. Для передачи в контейнер уведомления о том, что значение свойства изменилось, используется метод PropertyChanged объекта UserControl внутри оператора PropertyLet или PropertySet. Синтаксис метода PropertyChanged: o6beKm.PropertyChanged имя_свойства Элементы синтаксиса: Элемент Описание объект Имя объекта — в данном случае объекта EserControl. имя_свойства Строковое выражение, представляющее имя свойства, зна¬ чение которого изменено элементом управления. В следующем фрагменте кода показана процедура Property, в которой определяется свой¬ ство Name: Public Property Get Name() As String Name = txtName.Text End Property Public Property Let Name(ByVal NewName As String) txtName.Text = NewName PropertyChanged "Name" End Property Предоставление свойств составляющих элементов управления Когда пользователь работает с элементом управления, свойства объекта UserControl и всех составляющих элементов управления, по умолчанию, во время разработки не доступны. Однако свойства можно сделать доступными через существующие свойства объекта User¬ Control или составляющих элементов управления. Например, если создается элемент управления, который содержит элемент управления Label и элемент управления TextBox, то, используя процедуры Property, можно предостав¬ лять свойства объекта UserControl или составляющих элементов управления. В следующем фрагменте кода показано, как предоставить свойство Caption элемента управления Label, который является составляющим элементом управления объекта UserControl: Public Property Get Caption() As String Caption = lblName.Caption End Property
Гпава 9. Создание элементов управления ActiveX 231 Public Property Let Caption(ByVal NewCaption As String) lblName.Caption = NewCaption PropertyChanged "Caption" End Property Когда экземпляр объекта UserControl помещается в форму, свойство Caption для этого экземпляра становится доступным в окне свойств. Разработчик, который используетданный элемент управления, может установить текстовое значение, который появится в надписи. Делегирование свойства нескольким элементам управления Через механизм делегирования можно спроецировать свойство элемента управления на свойство более чем одного составляющего элемента управления. Например, если для объекта UserControl устанавливается пользовательский цвет символа, этот цвет можно распространить на составляющие элементы управления, как показано в следующем примере кода: Public Property Get ForeColor() As OLE_COLOR ForeColor = Controll.ForeColor End Property Public Property Let ForeColor(ByVal NewfColor As OLE_COLOR) Dim ctlElement As Object Controll.ForeColor = NewfColor For Each ctlElement In Controls If(TypeOf ctlElement Is Label) Or (TypeOf ctlElement Is CheckBox) _ Then ctlElement.ForeColor = NewfColor Next PropertyChanged "ForeColor" End Property 9.4.2. Добавление методов Пользовательские методы можно создать или делегировать составляющим элементам управления точно так же, как это делается для свойств. Создание метода Процедура создания методов для элементов управления в целом аналогична созданию методов для программных компонентов — в модуле программного кода объекта UserControl объявляется процедура Public Sub или Function, которая затем вызывается в контейнере, в котором создается элемент управления класса UserControl. Дополнительную информацию относительно создания методов см. в разделе "Создание методов" главы 8 "Создание программных компонентов ActiveX". В следующем фрагменте кода в элементе управления UserControl1 создается метод, кото¬ рый при загрузке формы выводит на экран дату: Public Sub ShowDate() MsgBox "Date is: " & Now() End Sub Private Sub Form Load() UserControll.ShowDate End Sub
232 Предоставление свойств, методов и событий Предоставление методов составляющих элементов управления В приложении также можно предоставлять методы любого составляющего элемента управ¬ ления, который является частью пользовательского элемента управления; приложение-кон- тейнер может вызывать эти методы. В следующем фрагменте создается метод IDFocus, который вызывается в событии Click кнопки в форме-контейнере: Public Sub IDFocus() txtEmpID.SetFocus End Sub Private Sub cmdSetIdFocus Click() Controll.IDFocus End Sub В этом примере элемент управления txtEmpID — составляющий в объекте UserControl. Когда пользователь щелкает кнопку в форме контейнера, фокус будет автоматически установлен на поле txtEmpID в объекте UserControl. 9.4.3. Использование общих свойств контейнера Разработчик элемента управления не всегда может предвидеть, контейнер какого типа будет использоваться. Следовательно, проектировать элемент управления следует таким образом, чтобы он мог правильно функционировать в контейнерах разных типов. Чтобы гарантировать согласованность между элементом управления и контейнером, можно ис¬ пользовать общие свойства контейнера. Контейнеры содержат общие свойства, которые обеспечивают им правильное поведение при размещении элементов управления. Общие свойства гарантируют, что пользователь элемента управления увидит ожидаемые визуальные атрибуты и действия независимо от контейнера. Например, BackColor — одно из стандартных общих свойств формы Visual Basic. Контейнер предлагает для элемента управления цвет фона, который соответствует цвету контейнера. Событие AmbientChanged Событие AmbientChanged происходит при изменении общего свойства. Чтобы пользова¬ тельский элемент управления реагировал на изменения значений общих свойств контейне¬ ра во время разработки, необходимо поместить программный код в процедуру события AmbientChanged. Это событие имеет один параметр, PropertyName, который идентифици¬ рует изменившееся свойство. Объект Ambient Объект Ambient позволяет читать значения различных общих свойств. Например, в следующем примере показано, как использовать объект Ambient в процедуре события AmbientChanged: Private Sub UserControl AmbientChanged(PropertyName As String) If PropertyName = "BackColor" Then UserControl.BackColor = Ambient.BackColor End If End Sub В этом примере, если разработчик, который использует элемент управления, изменяет свойство BackColor контейнера, цвет фона экземпляра элемента управления также соответ¬ ственно изменяется на цвет контейнера.
Гпава 9. Создание элементов управления ActiveX 233 Поддержка свойства Enabled Свойство Enabled — также общее свойство. Чтобы правильно поддерживать это свойство объекта UserControl, необходимо составить программный код для процедур Property свой¬ ства Enabled и затем ассоциировать этот код со свойством Enabled. Так как контейнер ответственен за активацию и деактивацию элементов управления, необ¬ ходимо ассоциировать свойство Enabled с идентификатором процедуры Enabled, гаранти¬ руя этим, что элемент управления не конфликтует с другими свойствами. Чтобы ассоциировать свойство Enabled с идентификатором процедуры Enabled, нужно выбрать Procedure Attributes в меню Tools и затем выбрать Enabled из списка Procedure ID. 9.4.4. Хранение и получение значений свойств Экземпляры элементов управления непрерывно создаются и разрушаются, поэтому следу¬ ет гарантировать сохранение значений свойств. При создании элемента управления необ¬ ходимо включить программный код, который будет сохранять и отбирать значения свойств элемента управления. Для хранения и получения информации состояния объекта при каждом вызове объекта используется объект PropertyBag, который передается через события ReadProperties и WriteProperties. В следующем фрагменте кода с помощью объекта PropertyBag выполняется сохранение текущих значений свойств для метода WriteProperty: Private Sub UserControl WriteProperties(PropBag As PropertyBag) PropBag.WriteProperty "Caption", Caption, Username End Sub Чтение значения свойства выполняется с использованием события ReadProperties и метода ReadProperty объекта PropertyBag. Метод ReadProperty принимает два параметра: строку, содержащую имя свойства, и значе¬ ние по умолчанию. Если значение свойства было сохранено, метод ReadProperty возвраща¬ ет это значение. Если значение свойства не было сохранено, метод возвращает значение по умолчанию. В следующем примере показано, как использовать метод ReadProperty для возвращения сохраненного значения свойства Caption: Private Sub UserControl ReadProperties(PropBag As PropertyBag) ' Обработка недействительных значений свойства On Error Resume Next Caption = PropBag.ReadProperty "Caption", Username ' ... Обработка других свойств End Sub Умолчательные значения свойств При чтении и записи значений свойств важно обеспечить некоторые значения по умолча¬ нию. Visual Basic записывает строку кода в файле контейнера элемента управления (.frm, .dob, .pag или .ctl), только если значение свойства отличается от значения по умолчанию, которое предусмотрел разработчик. В результате применения значений по умолчанию размеры файлов уменьшаются, а производительность приложения повышается.
234 Предоставление свойств, методов и событий 9.4.5. Использование именованных констант В Visual Basic версии 5.0 можно использовать перечисления, чтобы обеспечивать для компонента именованные константы. Перечисления обеспечивают удобный способ группи¬ рования набора связанных именованных констант и ассоциирования их с постоянными значениями. Значения перечисления при написании программного кода для элемента уп¬ равления можно получить в раскрывающемся списке при активированной функции Auto List Members (вкладка Editor окна диалога Options). Члены перечисления будут доступны пользователям элемента управления, если перечис¬ ление объявлено как Public. Перечисление можно использовать в любом public модуле, который определяет класс, в таком, как модуль класса, UserControl или UserDocument. В следующем фрагменте кода определяется перечисление, которое содержит именован¬ ные константы, представляющие температуры кипения по Цельсию для различных ве¬ ществ: Public Enum TempBoilCelsius msubWater = 100 ' Вода msubIron = 2750 ' Железо msubNitrogen = -195.8 ' Азот msubGold = 2807 ' Золото End Enum Это перечисление можно использовать, например, как тип данного свойства Temp, как показано на следующей иллюстрации: Рис. 9.8. Значения перечисления в списке Auto List Members. 9.4.6. Инициирование событий элемента управления Примечание: Информацию относительно инициирования событий см. также в разделе "Использо¬ вание событий” главы 8 "Создание программных компонентов ActiveX”. Чтобы инициировать событие из элемента управления, вначале нужно объявить событие, а затем, используя оператор RaiseEvent, вызвать событие.
Гпава 9. Создание элементов управления ActiveX 235 В следующем примере к объекту UserControl добавляется событие Click: ' Объявить public событие Click без параметров Public Event Click() В следующей строке инициируется событие Click: RaiseEvent Click Предоставление событий составляющих элементов управления В отличие от предоставления свойств и методов делегированием, событие составляющего элемента управления предоставляется генерированием пользовательского события. Чтобы предоставить события элемента управления объекта UserControl: 1. Объявить в объекте UserControl новое событие. 2. В событии составляющего элемента управления инициировать новое событие. В следующем программном коде предоставляется событие KeyPress из элемента управле¬ ния TextBox: ' Код для элемента управления TextBox Public Event KeyPressl(KeyAscii As lnteger) Private Sub Textl KeyPress(KeyAscii As lnteger) RaiseEvent KeyPressl (KeyAscii) End Sub Обратите внимание, что параметры процедуры события также передаются клиенту. ' Код для клиента элемента управления: Private Sub ClientControl KeyPressl(KeyAscii As lnteger) ' Преобразование символа в верхний регистр. ' Так как параметр KeyAscii передается ByRef, он может быть ' изменен в клиенте. KeyAscii = Asc(UCase(Chr(KeyAscii))) End Sub 9.4.7. Использование мастера ActiveX Control Interface Wizard B Visual Basic имеется мастер ActiveX Control Interface Wizard, который упрощает задачу создания элементов управления. Этот мастер позволяет определить свойства, методы и события, которые составят определение интерфейса элемента управления. ActiveX Control Interface Wizard позволяет проецировать функциональные возможности создаваемого элемента управления на объект UserControl или составляющие элементы управления. Впоследствии умолчательные соответствия можно изменить. Кроме того, этот мастер генерирует исходный программный код интерфейса, включая: • реализацию свойств в коде процедур Property; • реализацию методов в коде процедур Sub и Function; • программный код инициирования выбранных событий. Мастер генерирует правильные параметры и типы данных для стандартных событий и программный код передачи событий.
236 Предоставление свойств, методов и событий Рис. 9.9. Мастер ActiveX Control Interface Wizard — экран выбора компонентов интерфейса. В списках перечислены свойства, методы и события, которые первоначально доступны для использования в интерфейсе. Предварительно выбраны (правый список) компоненты, которые поддерживаются большинством элементов управления. Рис. 9.10. Мастер ActiveX Control Interface Wizard — экран ввода пользовательских компонентов интерфейса, уникальныхдля элемента управления.
Гпава 9. Создание элементов управления ActiveX 237 Рис. 9.11. Мастер ActiveX Control Interface Wizard — экран соответствий. Здесь можно спроеци ровать свойства, методы и события создаваемого элемента управления (список Public Name) на компоненты интерфейса составляющих элементов управлени (списки Control и Member). Рис. 9.12. Мастер ActiveX Control Interface Wizard — экран установки атрибутов компонентов, для которых не было установлено соответствий в предыдущем экране .
238 Создание страниц свойств 9.5. Создание страниц свойств Страницы свойств (окна диалога Property Pages) обеспечивают альтернативу организации свойств элементов управления ActiveX. При наличии страниц свойств пользователь может просмотреть связанные свойства в окне диалога картотечного вида. Это дает большую гибкость, чем использование окна свойств. Например, если создается свойство Font, которое имеет несколько разных значений, для каждого из них можно создать страницу свойств, вместо вывода значений в раскрывающем¬ ся списке в окне свойств. 9.5.1. Создание интерфейса страниц свойств Для создания страниц свойств вначале для каждой страницы создаются элементы интер¬ фейса (вкладки и кнопки в окне диалога Property Pages создаются Visual Basic). Рис. 9.13. Пользовательское окно диалога Property Pages: вкладки "Общие" и "Редактирова¬ ние" — пользовательские, "Font" и "Color" — стандартные. Чтобы добавить страницу свойств к проекту элемента управления: 1. В меню Project выбрать Add Property Page. 2. На вкладке New окна диалога Add Property Page дважды щелкнуть пиктограмму Property Page. После этого на экран выводится визуальный дизайнер, который можно использовать для размещения элементов управления, как если бы это была стандартная форма (рис. 9.14). 9.5.2. Программирование поведения страниц свойств Страницы свойств и формы внешне похожи друг на друга, и процедуры их создания подобны. Однако для страниц свойств и для форм используются разные события, и в результате функционируют они по-разному.
Гпава 9. Создание элементов управления ActiveX 239 Рис. 9.14. Окно дизайнера страницы свойств с элементами управления. Событие SelectionChanged Событие SelectionChanged происходит при открытии страницы свойств, когда набор эле¬ ментов управления изменяется. Это событие используется для установки и редактирования значений элементов управления, в которых выводятся значения свойств. В следующем фрагменте кода значение свойства Interval элемента управления Timer уста¬ навливается равным значению в текстовом поле на странице свойств: Private Sub PropertyPage SelectionChanged() txtTimerInterval.Text = SelectedControls(0).Interval End Sub Семейство SelectedControls Семейство SelectedControls содержит все элементы управления в контейнере, которые были выбраны пользователем элемента управления. Семейство может содержать несколь¬ ко экземпляров элемента управления. Для определения количества выбранных элементов управления используется свойство Count семейства SelectedControls. Возвращаемое значение больше 1 указывает, что в контейнере было выбрано несколько элементов управления. Свойство Changed Чтобы сообщить Visual Basic об изменениях, проведенных в свойствах на странице свойств, нужно установить в True свойство Changed объекта PropertyPage. При этом становится доступной кнопка Apply в окне диалога Property Pages. Например, следующий программный код информирует Visual Basic, что в текстовом поле на странице свойств было изменено значение свойства Interval: Private Sub txtTimerInterval Change() Changed = True End Sub
240 Создание страниц свойств Событие ApplyChanges Для переноса измененных значений свойств в выбранные элементы управления использу¬ ется событие ApplyChanges. Событие ApplyChanges происходит в следующих ситуациях: • щелчок кнопки OK для закрытия окна диалога Property Pages; • щелчок кнопки Apply; • выбор другой вкладки в окне диалога Property Pages. В следующем фрагменте кода объявляется переменная objControl, предназначенная для хранения ссылки на выбранный элемент управления, и применяются изменения свойства Interval страницы свойств элемента управления: Private Sub PropertyPage ApplyChanges() Dim objControl As Variant For Each objControl In SelectedControls objControl.Interval = txtTimerInterval.Text Next End Sub 9.5.3. Установление отношений страниц свойств В проекте элемента управления ActiveX может использоваться одна или более страниц свойств. Однако вначале между элементом управления и страницей свойств надо установить связь. Подключение страниц свойств к элементу управления Для ассоциирования одной или больше страниц свойств с элементом управления исполь¬ зуется окно диалога Connect Property Pages. Чтобы вывести это окно диалога на экран, нужно в окне свойств элемента управления дважды щелкнуть свойство PropertyPages или нажать кнопку с многоточием (...) в строке свойства. Рис. 9.15. Подключение страниц свойств к элементу управления.
Гпава 9. Создание элементов управления ActiveX 241 Ассоциирование свойства со страницей свойств Некоторые свойства представляют собой объекты с собственными свойствами. Другие свойства содержат массив значений. Когда свойство слишком сложно, чтобы его можно было установить в окне свойств, то для вывода на экран всех значений свойства можно использовать страницу свойств. Ассоциируя свойство со страницей свойств, можно привлекать все инструменты, которые делают свойство более доступным. Например, свойство, которое ассоциируется со страни¬ цей свойств, можно идентифицировать кнопкой с многоточием (...). При щелчке этой кнопки открывается ассоциированная страница свойств. Чтобы ассоциировать страницу свойств со свойством: 1. В окне Project Explorer выбрать объект UserControl и нажать кнопку View Code либо щелкнуть правой кнопкой мыши объект UserControl и затем в контекстном меню выбрать View Code, чтобы открыть окно редактора кода. 2. В меню Tools выбрать команду Procedure Attributes и в окне Procedure Attributes нажать кнопку Advanced. При этом на экран выводятся дополнительные опции (см. рис. 8.4). 3. В окне Name выбрать свойство, которое требуется ассоциировать со страницей свойств. 4. В списке Use this Page in Property Browser выбрать страницу свойств и затем щелкнуть кнопку Apply или ОК. 9.5.4. Использование стандартных страниц свойств Стандартные страницы свойств позволяют использовать существующие компоненты для построения привычного пользовательского интерфейса. Эти интерфейсы дают пользовате¬ лям возможность работать со сложными свойствами, например, имеющими отношение к стилю шрифта или цвету. Visual Basic обеспечивает следующие стандартные страницы свойств: • StandardFont; • StandardColor; • StandardPicture. При создании свойства типа Font, OLE_COLOR или Picture окно свойств автоматически ассоциирует эти свойства с соответствующей стандартной страницей свойств. В окне свойств кнопка с многоточием ( ... ) в строке любого из этих свойств указывает, что, когда пользователь щелкнет кнопку, будет открыта стандартная страница свойств. Если требуется, чтобы стандартные страницы свойств Visual Basic были представлены в окне диалога Property Pages, их необходимо подключить, используя окно диалога Connect Property Pages (см. рис. 9.13 и 9.15). 9.6. Тиражирование элемента управления В этом разделе затрагиваются вопросы распространения пользовательских элементов управления, а также показано, как использовать мастер Application Setup Wizard для паке¬ тирования всех требуемых компонентов приложения для тиражирования. 9.6.1. Лицензирование элементов управления Для обеспечения защиты элементов управления ActiveX Visual Basic предоставляет воз¬ можности лицензирования. Лицензирование элементов управления не позволяет сторон¬ ним разработчикам использовать экземпляры данного элемента управления в приложениях и при создании других элементов управления.
242 Тиражирование элемента управления Visual Basic обеспечивает поддержку лицензирования элементов управления путем компи¬ ляции ключа лицензии в файл .ocx. Программа Setup элемента управления записывает этот ключ в системный реестр. Когда пользователь во время разработки пытается создать экземпляр элемента управле¬ ния, программа Setup проверяет в системном реестре значение ключа лицензии. Если ключ не найден, экземпляр элемента управления во время разработки создаваться не будет. Однако, если скомпилированное приложение включаетлицензированный элемент управле¬ ния, пользователь может создавать версию элемента управления периода выполнения без ключа лицензии. Чтобы можно было использовать лицензированные составляющие эле¬ менты управления как часть элемента управления, пользователи элемента управления должны иметь установленные составляющие элементы управления или ключ лицензирова¬ ния должен быть включен с программой Setup элемента управления. Добавление лицензирования Для добавления лицензирования к элементу управления необходимо на вкладке General окна диалога Project Properties установить флажок Require License Key (см. рис. 8.8). При компиляции файла .ocxVisual Ваэюсоздает файл .vbl, который содержитдля компонен¬ тного элемента управления ключ лицензирования. Application Setup Wizard добавляет этот ключ в тиражируемый пакет. 9.6.2. Создание программы установки элемента управления Если элемент управления ActiveX, созданный в Visual Basic, планируется распространять, то для него необходимо создать программу установки. Использование Application Setup Wizard Самый простой способ создания программы установки — использовать мастер Application Setup Wizard, так как это гарантирует, что все файлы, необходимые для запуска приложе¬ ния, будут упакованы и затем их можно будет безопасно тиражировать. Application Setup Wizard работает одинаково, независимо от того, создается программа установки для компонента ActiveX или для любого другого компонента Visual Basic. Если требуется обеспечить поддержку лицензирования, возможно, придется включить дополни¬ тельные файлы поддержки для составляющих элементов управления, а также файл .vbl. Если приложение включает большое количество файлов, учет этих файлов может стать сложной задачей. Application Setup Wizard обеспечивает простой и удобный способ учета файлов и создания программы Setup. Чтобы создать программу Setup для компонентов элемента управления ActiveX: 1. В свойствах элемента управления специфицировать, требуется ли включать для элемен¬ та управления поддержку лицензирования. 2. Скомпилировать файл .ocx. 3. Запустить Application Setup Wizard. Использование программой Setup файла лицензирования Если для элемента управления специфицирована поддержка лицензирования, Application Setup Wizard создает программу Setup, которая автоматически регистрирует все файлы .vbl в системном реестре. Мастер также запрашивает, какие файлы .vbl требуется установить на компьютере пользователя.
Гпава 9. Создание элементов управления ActiveX 243 Если требуется установить файл .vbl, Application Setup Wizard обеспечивает умолчательную папку-адресат. Умолчательная опция — Do not install this file (Не устанавливать этот файл), так как обычно разработчик имеет в виду, что пользователь должен иметь зарегистрирован¬ ный файл лицензии, но его не обязательно нужно устанавливать на компьютере. Эта опция гарантирует, что разработчики смогут включать лицензированные элементы управления в свои приложения, в то время как пользователи приложений смогут обратиться только к экземпляру элементов управления периода выполнения. Application Setup Wizard (файл Setupwiz.exe) обычно размещается в директории \VB\Setup- kit\Kitfil32\ при установке Visual Basic. При его запуске пользователю последовательно предоставляются экраны, в которых он может выбрать и указать: • проект и его опции: создать программу Setup, создать Setup для загрузки через Internet и др.; • метод тиражирования — дискеты, общая директория, дисковые директории (Disk1, Disk2 и т. д.); • включаемыедрайверыбазданных; • включаемые серверы — компоненты ActiveX, локальные и удаленные; • включаемые лицензионные компоненты; • другие данные.
244 Документы ActiveX Глава 10. Создание и использование документов ActiveX Компонентная Объектная Модель обеспечивает поддержку документов ActiveX (прежде известных как объекты-документы OLE). Документ ActiveX — специальный тип объекта ActiveX, который может быть помещен и активирован внутри контейнеров документов ActiveX, таких, например, как Microsoft Internet Explorer. Документы ActiveX — расширение технологии составного документа (связывание и внедре¬ ние объектов). Однако документы ActiveX включают новые возможности, которые позволя¬ ют повысить функциональность приложения за счет использования преимуществ Internet и расширения возможностей пользовательского интерфейса. 10.1. Документы ActiveX Документы ActiveX составляют основной элемент набора технологий, совокупно именуемых ActiveX. Хотя документы ActiveX и внедренные объекты могут показаться очень похожими, важно понять их некоторые ключевые различия. Первоначально документы ActiveX представляли оригинальную технологию Microsoft, используемую в приложении Binder (Подшивка), поставляемом с Microsoft Office для Windows 95. Это приложение позволяло пользователям группировать набор связанных документов Office вместе в одном приложении, независимо от приложения Office или типа документа. В рамках технологии СОМ объекты ActiveX и контейнеры документов ActiveX поддерживают дополнительные интерфейсы, которые позволяют создавать объекты-документы (или формы). 10.1.1. Контейнеры документов ActiveX Технология документов OLE, на которой базируются документы ActiveX, позволяет разме¬ щать объекты внутри приложения-контейнера. Приложение-контейнер также называется контейнером документа ActiveX. Основной аспект функциональности документа ActiveX — его воздействие на пользователь¬ ский интерфейс. Документ ActiveX заполняет область отображения контейнера и придает контейнеру способность трансформировать себя, в результате чего он выглядит и действу¬ ет как приложение-сервер. Например, объект Рабочий лист Microsoft Excel может вызываться изнутри Internet Explorer или другого приложения-контейнера. Примечание: Работать с документами ActiveX можно в контейнере документа ActiveX. Документ ActiveX— компонент, который существует только внутри клиента. Контейнер документа ActiveX — обычно автономное приложение. Например, при запуске Microsoft Word это приложение формирует контейнер для объекта-документа. При запуске документа Word из Internet Explorer Word работает как сервер, который предоставляет документ другому контейнеру. При запуске документа .bmp из Word в качестве сервера выступает Paint. Информацию относительно типов доступных контейнеров документов см. ниже, в разделе "Internet Explorer и Office Binder".
Гпава 10. Создание и использование документов ActiveX 245 Рис. 10.1. Документ .doc, открытый в Internet Explorer. Элементы интерфейса сервере (MicrosoftWord) добавляются к интерфейсу контейнера. 10.1.2. Документы ActiveX и внедренные объекты Документы ActiveX значительно расширили возможности визуального редактирования сво¬ их предшественников — объектов-документов OLE. Визуальное редактирование — процесс редактирования внедренного объекта внутри окна контейнера с использованием инстру¬ ментальных средств сервера. Вместо активирования только одного внедренного объекта документ ActiveX может представлять весь документ в среде приложения-сервера. Пример этих расширенных возможностей — сравнение между объектом Word, внедренным в другом приложении, таком как Microsoft Excel, и документом ActiveX, созданным в Word, который открывается в Internet Explorer. В случае сдокументом ActiveX пользователь имеет возможность просматривать и печатать, например, заголовки и колонтитулы документа. Для внедренного объекта Word такая возможность недоступна. Это объясняется тем, что доку¬ менты ActiveX реализуют дополнительные интерфейсы, которые расширяют функциональ¬ ные возможности внедренных объектов и позволяют делегировать инструменты сервера приложению-клиенту. В последнем случае Word действует как приложение-сервер, предо¬ ставляя документ ActiveX приложению-клиенту (Internet Explorer) (рис. 10.2). 10.1.3. Преимущества документов ActiveX Документы ActiveX обеспечивают ряд преимуществ и расширяют возможности как пользо¬ вателя, так и разработчика приложения.
246 Документы ActiveX Рис. 10.2. Различия между внедренным объектом и документом ActiveX. Документы ActiveX позволяют загружать в приложение-контейнер документы разных типов. При этом внешние проявления связи междудокументом и приложением сводятся к миниму¬ му. Это означает, что пользователям не требуется знать, какое приложение оперирует с какими типами данных. Так как этот аспект прозрачен для пользователей, они могут сосре¬ доточиваться на решении своих задач, уделяя меньше внимания аспектам работы непос¬ редственно приложения. Широко доступными приложениями-контейнерами для документов ActiveX являются сред¬ ства просмотра работы с Web, такие, как Internet Explorer и NetScape Navigator. Документы ActiveX могут выполняться на локальных компьютерах. Это позволяет обработ¬ ку, связанную с интенсивными вычислениями, производить локально, что уменьшает ин¬ формационную загрузку сетей. Web играет важную роль в расширении использования документов ActiveX. Используя документы ActiveX на Web, пользователи работают с информацией любого формата через общие инструменты средств просмотра. Наиболее важное преимущество использования документов ActiveX для разработчиков — возможность применить имеющиеся навыки программирования. Разработчики могутсозда- вать документы ActiveX, используя привычные язык и среду программирования, такие, как Microsoft Visual Basic 5.0, Microsoft Visual Java++ и Microsoft Visual C++. Например, в Visual Basic можно создать документ ActiveX, не прибегая к написанию программного кода для документа HTML. 10.1.4. Internet Explorer и Office Binder Ниже кратко рассматриваются приложения Internet Explorer версий 3.0 и 4.0 и Microsoft Office Binder, которые могут использоваться как контейнеры для документов ActiveX. Internet Explorer 3.0 В Microsoft Internet Explorer версии 3.0 можно загружать документ ActiveX таким образом, что среда работы пользователя будет подобна приложению-серверу, но с добавлением функ¬ циональных возможностей Internet. Например, пользователи могут просматривать и модифицировать форму регистрации зака¬ зов, загруженную Internet Explorer, точно так же, как если бы это была форма в автономном приложении Visual Basic. Они могут также перейти к другой форме или странице, введя другое значение URL (Uniform Resource Locator — адрес ресурса) в окне Address или щелкнув кнопку или гиперссылку.
Гпава 10. Создание и использование документов ActiveX 247 На следующей иллюстрации показан документ ActiveX, в данном случае форма Visual Basic, которая была активирована в Internet Explorer 3.0. Рис. 10.3. Документ ActiveX, загруженный в Internet Explorer. Microsoft Office Binder Microsoft Office Binder — контейнер широкого применения. Это приложение напоминает электронную скрепку — оно позволяет пользователям группировать и редактировать свя¬ занные документы. Пользователи могут работать с документами ActiveX, собирая активное содержание Office Binder. Например, Binder может содержать набор документов проекта, который включает документы Word, финансовые рабочие листы анализа Excel, различные диаграммы и схем¬ ные решения. Все документы хранятся в единственном файле, где пользователи могут открывать каждый тип документа индивидуально, причем запускать соответствующие при¬ ложения нет необходимости. Отдельные документы проекта Binder могут быть распечатаны в одном задании печати со сквозной нумерацией страниц. Microsoft Internet Explorer 4.0 Версия 4.0 приложения Internet Explorer объединит элементы Windows 95 Explorer (Провод¬ ника) с функциями Internet Explorer 3.0 в единую оболочку, которая напоминает Windows Explorer. Эта оболочка, включающая новые инструментальные средства Internet, будет обес¬ печивать интеграцию данных локального компьютера и данных из Internet. Пользователям больше не нужно будет использовать один интерфейс для Windows Explorer и другой — для Internet.
248 Документы ActiveX Windows Explorer, объединенный c Internet Explorer, также будет контейнером документов ActiveX. Пользователи смогут открыть любое приложение, которое поддерживает интер¬ фейсы документа ActiveX, непосредственно из Windows Explorer. Например, пользователи смогут открывать средства просмотра HTML (такие, как Internet Explorer) из Windows Explorer. Web-страница, написанная в HTML, будет рассматриваться как тип документа — такой же, как документ Word или рабочая книга Microsoft Excel. 10.1.5. Документы ActiveX в Visual Basic В Visual Basic документ ActiveX создается добавлением объекта UserDocument в окне дизайнера, обеспечиваемого Visual Basic для документов ActiveX. Объект UserDocument — основа для всех документов ActiveX. Объект UserDocument Объект UserDocument по функциональным возможностям подобен объекту UserControl, включая поддержку свойств и методов. Как и объект UserControl, объект UserDocument может генерировать события, поддерживает обратные вызовы и обеспечивает асинхрон¬ ные уведомления от сервера. Объект UserDocument также реализует интерфейсы, которые позволяют применять его внутри контейнера документа. Информацию относительно объекта UserControl см. в разделе "Введение в элементы управ¬ ления" главы 9 "Создание элементов управления ActiveX". Относительно сообщений от серверов см. в разделе "Получение сообщений от серверов" главы 7 "Создание клиентов ActiveX". Рис. 10.4. Проект пользовательского документа ActiveX в окне Project Explorer. Проект на рис. 10.4 состоит из пользовательского документа, который добавлен к проекту документа ActiveX и представляет объект UserDocument. К проекту можно добавлять допол¬ нительные пользовательские документы, а также формы и модули. Дизайнер документа ActiveX При открытии пользовательского документа в режиме разработки он появляется в окне дизайнера. Работа в окне дизайнера документа ActiveX подобна работе с формой. Дизайнер можно использовать для формирования визуальных аспектов документа ActiveX, например, раз¬ мещением элементов управления на полотне объекта UserDocument.
Гпава 10. Создание и использование документов ActiveX 249 Рис. 10.5. Пользовательский документ в окне дизайнера. 10.2. Работа с проектами документов ActiveX Для создания документа ActiveX открывается проект ActiveX. Для создания новых проектов ActiveX Visual Basic предоставляет соответствующие шаблоны; в проект ActiveX можно преобразовать также существующий проект Standard EXE. Пользователи могут получать доступ к документу ActiveX из разных точек входа и из ряда приложений-контейнеров. Следовательно, в приложении документа ActiveX должен быть программный код обработки ошибок. Написание кода для обработки ошибок и действий пользователя требуют понимания того, как в течение существования документа ActiveX работают события. 10.2.1. Элементы проектадокументаАсНуеХ Документ ActiveX может быть создан как .exe или .dll файл. В любом случае проект ActiveX для документа ActiveX по умолчанию должен содержать по крайней мере один объект UserDocument. При создании файлов одного из этих типов к объекту UserDocument добав¬ ляются элементы управления, дополнительные формы и программные модули, а затем для элементов управления добавляется программный код. При компиляции проекта ActiveX будет создан файл .exe или .dll, а также файл документа Visual Basic (.vbd). Чтобы открыть документ ActiveX в средстве просмотра, таком как Internet Explorer, пользователь должен иметь возможность обратиться к файлу .vbd. Следующие два типа файлов также входят в состав пользовательского документа: Файлы .dob Visual Basic хранит пользовательские документы в текстовых файлах с расширением .dob. Эти файлы содержат исходный текст и значения свойств объекта UserDocument и элементов управления. Файлы .dox Все графические элементы Visual Basic хранит в файлах с расширением .dox. Эти ресурсы, например растровые рисунки, используются для офор¬ мления элементов управления объекта UserDocument.
250 Работа с проектами документов ActiveX Файлы .dob и .dox определяют вид и интерфейс документа ActiveX, включая свойства, события и методы. Эти два файла аналогичны файлам .frm и .frx проекта Standard EXE соответственно. 10.2.2. Создание проекта документа ActiveX Для создания документа ActiveX в Visual Basic можно либо открыть новый проект ActiveX, либо преобразовать существующий проект Standard EXE. Создание нового проекта документа ActiveX Для создания нового проекта ActiveX Visual Basic обеспечивает шаблоны ActiveX Document DLL и ActiveX Document EXE. 'Документы ActiveX Рис. 10.6. Шаблоны проектов для документов ActiveX. Преобразование существующего проекта Standard EXE Для преобразования существующего проекта Standard EXE в проект документа ActiveX можно использовать мастер ActiveX Document Migration Wizard. При запуске мастера он преобразует выбранные формы проекта в документы ActiveX и изменяет тип проекта на ActiveX EXE или ActiveX DLL. Мастер ActiveX Document Migration Wizard можно также использовать для преобразования форм проекта, отличного от Standard EXE, в проект документа ActiveX, но опция преобразо¬ вания типа проекта будет недоступна. Чтобы преобразовать существующий проект в проект ActiveX: 1. В меню Add-Ins подключить мастер ActiveX Document Migration Wizard (команда Add-In Manager) и затем запустить его. 2. В экране Form Selection мастера выбрать форму, которую требуется преобразовать, и щелкнуть Next.
Гпава 10. Создание и использование документов ActiveX 251 3. В экране Options выбрать следующие опции: а) Comment out invalid code. б) Remove original forms after conversion. в) Convert to an ActiveX EXE (если исходный проект не Standard EXE, этой опции не будет). 4. В экране Finished щелкнуть переключатель No запроса, требуется ли выводить отчет работы мастера, затем установить флажок Save current settings as default (Сохранить текущие установки как умолчательные) и нажать Finish. 10.2.3. Компиляция проектадокументаАсНуеХ При создании документа ActiveX как компонента in-process (.dll) или out-of-process (.exe) компонент функционирует как сервер Автоматики. Сервер Автоматики позволяет другому приложению — контейнеру ActiveX загружать, программировать и активировать документ. При компиляции или запуске проекта Visual Basic создает файл документа (.vbd). Файл .vbd — структурированная область хранения OLE. Это означает, что данные в файле могут быть доступны и управляемы через стандартные интерфейсы OLE. Информацию по интерфейсам см. в разделе "Использование интерфейсов" главы 7 "Создание клиен¬ тов ActiveX". Чтобы открыть документ ActiveX, например, в окне Internet Explorer, поль¬ зователи должны обратиться к файлу .vbd. Таким образом, при компиляции проекта документа ActiveX создаются два исполняемых файла: .exe (или .dll) и .vbd. 10.2.4. Размещение документа ActiveX в контейнере Прежде чем можно будет использовать документ ActiveX, его необходимо поместить в контейнер. Соединение документа ActiveX с контейнером (загрузка) играет ключевую роль в определении событийного поведения документа ActiveX. Загрузка позволяет документу ActiveX реализовать свои функциональные возможности. Контейнер документа содержит семейство гнезд, которые он использует для назначения документам ActiveX в период выполнения. Гнездо содержит адрес окна в контейнере, в которое помещен документ. Когда документ загружен, контейнер становится для документа клиентом и устанавливает соединение между контейнером, гнездом и документом согласно внутренней реализации. После этого становится доступным свойство Parent документа ActiveX, которое возвращает ссылку на контейнер. После того как происходит загрузка, для документа ActiveX становятся доступными свойства контейнера и объекта Visual Basic Hyperlink. Свойства и методы объекта НурегПпкдокумента ActiveX используются для передачи в контейнер запроса на переход кдругому URL. 10.2.5. События пользовательскогодокумента В период существования объекта UserDocument события, которые происходят, и порядок, в котором они происходят, зависят от ряда факторов, включая: какой контейнер используется, был ли документ загружен и какие действия пользователь выполняет внутри контейнера. В этом разделе описываются события, которые происходят при использовании в качестве контейнера средства просмотра Internet Explorer. Ниже описываются события, которые могут происходить в течение существования документа ActiveX:
252 Работа с проектами документов ActiveX Событие Описание Initialize Событие Initialize происходит при каждом создании или обновлении эк¬ земпляра документа ActiveX. Это — всегда первое событие, которое имеет место в период существования документа ActiveX. lnitProperties Событие lnitProperties происходит, когда документ ActiveX уже загружен в контейнер документа, но значения свойств документа еще не были сохра¬ нены. При сохранении значений свойств событие lnitProperties заменяет¬ ся событием ReadProperties. ReadProperties Событие ReadProperties происходит при сохранении свойства с исполь¬ зованием объекта PropertyBag. Terminate Событие Terminate происходит непосредственно перед разрушением до¬ кумента ActiveX. В Internet Explorer 3.0 в кэше хранится четыре документа ActiveX. Когда пользователь загружает или осуществляет навигацию к пятому документу, один из документов ActiveX удаляется из кэша. Ис¬ пользуя событие Terminate, можно удалить все глобальные объектные ссылки, установив их в Nothing. Show Событие Show происходит в одной из следующих ситуаций: — Когда пользователь открывает документ ActiveX, который был распо¬ ложен в контейнере. — Когда пользователь нажимает в Internet Explorer кнопку Back или Forward, чтобы вернуться к документу ActiveX в списке History. Hide Событие Hide происходит в одной из следующих ситуаций: — Когда пользователь выходит из документа, непосредственно перед событием Terminate. — Когда Internet Ехр1огегзавершен, в то время какдокументеще просмат¬ ривается или все еще находится внутри кэша активных документов. Функциональные возможности событий Show и Hide зависят от конкретного контейнера. Информацию относительно различий в их поведении см. в следующем разделе. 10.2.6. Различия между контейнерами документов Разработчик заранее не может знать, в какой контейнер пользователь поместит документ ActiveX, поэтому он должен спланировать различные ситуации использования документа. Например, возможно, придется сообщить пользователям, что выбранный контейнер не обеспечивает некоторых функций, требуемых для нормальной работы с документом Acti¬ veX, и предложить альтернативный контейнер. Ниже приводятся некоторые важные различия между контейнерами: • Internet Explorer кэшируетдокументы в памяти, в то время как Microsoft Office Binder— нет; • в Office Binder при добавлении нового раздела к подшивке из класса документа ActiveX создается новый объект. При этом всегда будет происходить событие lnitProperties вместо события ReadProperties; • в Internet Explorer события Show и Hide происходят, как описано в предыдущем разделе. 10.2.7. Определение типа контейнера документа Для определения контейнера документа ActiveX вводится оператор TypeName со свойством Parent объекта UserDocument, как показано в следующем примере: Dim strContainer As String strContainer = TypeName(UserDocument.Parent)
Гпава 10. Создание и использование документов ActiveX 253 Для Internet Explorer строковое значение, возвращенное свойством Parent, — IWebBrowserApp. Событие Show происходит, когда документ ActiveX уже размещен в контейнере, так что это событие можно использовать для определения используемого контейнера. Когда документ загружен, свойства контейнера становятся доступными.В следующем фрагменте кода про¬ веряется, возвращено ли свойством Parent объекта UserDocument строковое значение IWeb¬ BrowserApp, и выводится сообщение пользователю: Private Sub UserDocument Show() Dim strContainer As String strContainer = TypeName(UserDocument.Parent) If strContainer = "IWebBrowserApp" Then MsgBox "Подтверждение: Этот документ" & " работает с Internet Explorer " & "3.0 или выше" Else MsgBox "К сожалению, этот документ может работать " & "с Internet Explorer 3.0 или выше" End If End Sub Примечание: Как и другие компоненты, созданные с помощью Visual Basic 5.0, документы ActiveX могут передавать события и обратные вызовы клиенту, обеспечивая асинхронные вызовы клиен¬ та. Информацию относительно сообщений сервера см. в разделе "Получения сообщений от Серве- ров”главы 7 ''COM и создание клиентов ActiveX”. Относительно реализации событий в серверах см. в разделе "Использование событий” главы 8 "Создание программных компонентов ActiveX”. 10.3. Тестирование и отладка документов ActiveX Тестирование и отладка документов ActiveX по сравнению с созданием стандартных проектов включает некоторые дополнительные вопросы. Основной момент заключается в том, что пользователь имеет ряд альтернативных способов просмотра и работы с документом ActiveX. В то же время он может столкнуться с некоторыми ограничениями, касающимися выбора контейнера документа. В этом разделе обсуждается, как разработчик может подготовиться к различным ситуациям, которые могут возникнуть при взаимодействии пользователя с докумен¬ том ActiveX. Здесь также показано, как перевести в режим останова стандартный проект, когда контейнер — Internet Explorer, и как при этом использовать средства отладки Visual Basic. 10.3.1. Запуск проекта в Visual Basic При проектировании документа ActiveX имеется два выбора. Можно проектировать документ ActiveX для выполнения, по умолчанию, в отдельном контейнере либо выбрать приложение, обеспечивающее контейнер для вывода на экран объектов документа. Эти выборы полезны, так как на этапе разработки еще неизвестно, какой контейнер будет использоваться. Чтобы гарантировать, что пользователи, которые не располагают приложением — контей¬ нером для документа, все же смогут использовать проектируемое приложение, и иметь возможность тестировать его в контейнере, в документе ActiveX необходимо предусмотреть черты средства просмотра. 10.3.2. Тестирование документа ActiveX в контейнере Для тестирования документа ActiveX в приложении-контейнере запускать его следует с использованием файла .vbd. Открывать документ ActiveX непосредственно из Visual Basic нельзя.
254 Многодокументные проекты Для запуска документа ActiveX в контейнере: 1. Создать ассоциацию файла для файла .vbd и приложения-контейнера. 2. Переключиться в Visual Basic и запустить приложение. Пользовательские документы и формы не будут видимы, так как вывод из проекта сосредоточен в файле .vbd. 3. Переключиться в My Computer или Windows Explorer и запустить файл .vbd. Это обуслов¬ ливает загрузку файла .vbd в приложение-контейнер. 4. Удостоверившись, что файл .vbd загружен в приложение-контейнер правильно, закрыть контейнер, переключиться в Visual Basic и явно завершить приложение. 10.3.3. Определение среды периода выполнения Чтобы протестировать, запускается ли приложение в автономном режиме, к стандартному модулю проекта можно добавить процедуру Sub Main и в ней выполнить соответствующее действие. В следующем фрагменте свойство StartMode объекта App используется для проверки, запустилось ли приложение в автономном режиме. Если это так, приложение выводит на экран форму: If App.StartMode = vbModeStandalone Then frmContainer.Show End If Этот программный код открывает приложение в автономном режиме. Основываясь на результате тестирования режима запуска приложения, для приложения можно обеспечить также способность действовать как контейнер документа. Придать приложению черты сред¬ ства просмотра позволяет, например, элемент управления WebBrowser. Для тестирования проекта в автономном режиме: 1. Добавить к проекту стандартный модуль с процедурой Sub Main(). 2. В меню Project выбрать Project Properties. 3. На вкладке General установить для Startup Object значение Sub Main. 4. На вкладке Component установить для опции Start Mode значение Standalone и щелкнуть ОК. 5. Запустить и протестировать приложение. 10.4. Многодокументные проекты Большинство проектов документов ActiveX состоит из двух или больше связанных докумен¬ тов. Если для проекта документа ActiveX в качестве контейнера используется средство просмотра, необходимо обеспечить возможности для навигации между несколькими доку¬ ментами. Следует также установить систему сообщений, с помощью которой можно иден¬ тифицировать открытый документ. Зная, какой документ открыт, приложение документа ActiveX сможет выполнить соответствующее действие. 10.4.1. Определение навигационныхтребований кдокументу При проектировании документа ActiveX необходимо установить, как документ будет исполь¬ зовать возможности приложения, предполагаемого в качестве контейнера. Например, в документе, разработанном для эксплуатации в Internet Explorer, вероятно, должны исполь¬ зоваться его возможности навигации между страницами HTML.
Гпава 10. Создание и использование документов ActiveX 255 Документ ActiveX, сохраненный в Microsoft Office Binder, не будет работать таким же обра¬ зом, как документ, который выполняется в Internet Explorer. Вместо навигации междудоку- ментами или страницами в В^егосуществляется навигация между разделами. Примечание: Добавить новый объект UserDocument к проекту можно выбором команды Add User¬ Document в меню Project. Затем в окне диалога UserDocument нужно выбрать пиктограмму User Document. Простой сценарий с несколькими документами Если пользователи проекта документа ActiveX будут работать с двумя документами, поль¬ зователь должен иметь возможность открыть второй документ, щелкнув кнопку на первом документе. Если приложение-контейнер — Internet Explorer, для перемещения от одного документа к другому следует использовать метод NavigateTo объекта Hyperlink, как показано в следую¬ щем примере кода: Private Sub cmdMoveTo_Click() ' Принимая, что документ называется UserDoc2 UserDocument.Hyperlink.NavigateTo "с:\projects\UserDoc2.vbd" End Sub Примечание: Если контейнер не поддерживает гиперссылки (например, как Microsoft Binder), сис¬ темный регистр определяет приложение, которое поддерживает гиперссылки, и для обработки запроса запускает альтернативное приложение. 10.4.2. Использование глобальных ссылок Важное различие между формами и документами ActiveX заключается в том, что заранее неизвестно, как пользователь будет вызывать документ ActiveX. В Internet Explorer, напри¬ мер, пользователь может открывать документ ActiveX из различных точек входа, скажем из списка Favorites (Избранное) или через кнопку быстрого доступа на рабочем столе. Для управления способом поддержания связи друг с другом документов ActiveX можно использовать глобальные переменные. Глобальные переменные также позволяют делать свойства одного документа доступными другому документу. Один из способов идентифицировать документ ActiveX для другого документа ActiveX — использовать глобальную переменную. Переменная устанавливается какобъектная ссылка надокументАсйуеХ так, чтобы значение ее выступало как некий сигнал междудокументами. На следующей иллюстрации глобальная переменная действует как почтовый ящик между двумя документами. Рис. 10.7. Глобальная переменная — объектная ссылка на Документ 1 и Документ 2.
256 Многодокументные проекты Установка глобальной переменной предполагает объявление ее в модуле кода. В следую¬ щем фрагменте показано объявление глобальной переменной gDoc1 — объектной ссылки на документ Doc1: Public gDocl As String Для проверки и уничтожения глобальных ссылок, установленных другими документами ActiveX, можно использовать события Show и Hide. Разрушение глобальных ссылок осво¬ бождает память и системные ресурсы, используемые для хранения ссылки. Обнаружение объектной ссылки Свойства public одного документа ActiveX могут быть доступны другим документам ActiveX. Чтобы сделать свойства глобально доступными, необходимо проверить, установлена ли глобальная переменная на объект, который содержит свойство public, представляющее документ ActiveX. В следующем фрагменте кода для проверки факта установки глобальной ссылки gDoc1 на объект используется оператор Is Nothing. Если ссылка установлена, свойства public документа ActiveX доступны и в надписи в форме выводится свойство strProp1 из документа Doc1. Если ссылки на объект нет, объектная ссылка разрушается и выводится соответствующее сообщение. Private Sub UserDocument Show() If Not gDocl Is Nothing Then lblCaption.Caption = gDocl.strPropl Set gDocl = Nothing ' Это важно! Необходимо установить ' переменную в Nothing, чтобы уничтожить ссылку на ' глобальную переменную Else MsgBox "Вначале необходимо открыть UserDocument Docl" End if End Sub Использование события Hide для уничтожения ссылок При использовании Internet Explorer событие Hide происходит при одном из двух обстоя¬ тельств: оно происходит всякий раз, когда пользователь переходит из документа в другое место или непосредственно перед событием Terminate. Событие Hide используется для уничтожения всех глобальных объектных ссылок перед навигацией кдругому документу, как в следующем примере: Private Sub UserDocument Hide() If Not gDocl Is Nothing Then Set gDocl = Nothing End if End Sub 10.4.3. Созданиесвойств Как и в случае с объектом UserControl, для создания свойств public для объектов UserDocu¬ ment можно использовать процедуры Property. Ниже приводится пример создания свойства public и обращения к свойству из другого документа ActiveX.
Гпава 10. Создание и использование документов ActiveX 257 Создание свойств Public При создании свойства public это свойство предоставляется, так что другие приложения могут устанавливать или получать значения. В следующем фрагменте кода показано предоставление свойства strProp1 как свойства public документа ActiveX Doc1. Это позволяет через свойство Text элемента управления TextBox управлять сохранением и выводом строки: Public Property Get strPropl() As String strPropl = txtDocl.Text End Property Public Property Let strPropl(ByVal NewstrPropl As String) txtDocl.Text = NewstrPropl End Property Обращение к свойству Public Преимущество создания глобальной объектной переменной для обращения к конкретному документу ActiveX в том, что эту ссылку можно использовать для получения доступа к public свойствам и методам документа. В следующем примере документ ActiveX Doc1 содержит кнопку Передать (Transfer). В событии Click для кнопки Transfer объектная переменная gDoc1 устанавливается в Me, создавая ссылку на Doc1. Документ Doc1 имеет свойство только для чтения User, которое содержит имя текущего пользователя. ActiveX документ Satellite может использовать ссылку gDoc1 для получения доступа к свойству User документа ActiveX Doc1. Private Sub cmdTransfer Click() Set gDocl = Me Hyperlink.NavigateTo App.Path & "\Satellite.vbd" End Sub Private Sub UserDocument Show() Dim strUser As String strUser = gDocl.User ' Вывести имя пользователя End Sub Устойчивость свойств Устойчивость данных — способность компонента хранить и отбирать данные. Создание механизма сохранения свойств документа ActiveX избавляет пользователей от необходи¬ мости неоднократно вводить в приложение одни и те же данные. Некоторые контейнеры, такие как Internet Explorer и Microsoft Office Binder, позволяют сохранять данные, производя запись в интерфейс приложения. Для сохранения данных в файле (файл .vbd или другой вид файла, в зависимости от приложения) используется объект PropertyBag. Объект PropertyBag объявляется как часть описания событий WriteProperties и ReadProper¬ ties и имеет два метода:
258 Многодокументные проекты Метод Действие WriteProperty Записывает сохраняемое значение в объект PropertyBag. ReadProperty Возвращает сохраненное значение из объекта PropertyBag. Уведомление контейнера об изменении Первый шаг в сохранении свойства — известить контейнер об изменении значения свойст¬ ва. Это можно выполнить, используя метод PropertyChanged объекта UserDocument. В следующем фрагменте кода показан метод PropertyChanged в событии Change элемента управления TextBox. Он сообщает контейнеру, что значение свойства изменилось и, в случае Internet Explorer, запрашивает пользователя сохранить изменения до завершения метода. Private Sub txtDocl Change() PropertyChanged End Sub Обычно всякий раз при изменениях значения свойства и сохранении их в PropertyBag, чтобы гарантировать, что новое значение будет успешно сохранено, необходимо вызвать метод PropertyChanged. Запись свойства в файл .vbd В ответ на метод PropertyChanged устанавливается флаг, который обеспечивает сообще¬ ние контейнеру. После этого происходит результирующее событие WriteProperties. Метод WriteProperty можно использовать для сохранения свойства в файле .vbd или в любом расположении, которое обеспечивает контейнер. Этот процесс показан в следую¬ щем фрагменте кода: Private Sub UserDocument WriteProperties(PropBag As VB.PropertyBag) ' Запись свойства в PropertyBag PropBag.WriteProperty "txtDocl", txtDocl.Text, "Запись завершена" End Sub Чтение свойств Событие lnitProperties происходит только в том случае, если не имеется свойств документа ActiveX, сохраненных с использованием PropertyBag. В предыдущем примере при следую¬ щем открытии документа ActiveX произошло бы событие ReadProperties и, через объект PropertyBag, были бы сохранены данные с использованием метода ReadProperty. В этой процедуре выполняется получение данных, сохраненных в предыдущем примере: Private Sub UserDocument ReadProperties (PropBag As VB.PropertyBag) ' Чтение свойства в элемент управления TextBox txtDocl.Text = ReadProperty("txtDocl", _ " Данные получены ") End Sub
Гпава 10. Создание и использование документов ActiveX 259 10.5. Пользовательский интерфейс и пользовательский документ Работа с документом ActiveX очень сходна с работой с формой. Для реализации требуемых функциональных возможностей используются те же свойства, что и для формы. Этот раздел посвящен описанию возможностей расширения пользовательского интерфейса документов ActiveX. Эти возможности включают применение свойств масштабирования, которые управляют экранным отображением в документе ActiveX, а также применение меню. 10.5.1. Установка свойств пользовательского документа Объект UserDocument — специальный тип формы. Он включает все свойства, доступные для формы, плюс ряд специальных свойств. Дополнительные свойства определяют пове¬ дение, специфичное при работе внутри контейнера документа. Установка свойств MinHeight и MinWidth При работесдокументом АсйуеХдоступны все свойства масштабирования, которые приме¬ няются для формы. Пользователи могут изменять размер окна приложения-контейнера, поэтому разработчик не имеет контроля над объемом экранного пространства, которое контейнер предоставляет документу ActiveX. Однако для документа ActiveX можно определять минимальные требо¬ вания пространства и вводить внутри контейнера полосы прокрутки, когда документ превы¬ шает эти требования. Чтобы специфицировать, когда требуется добавить полосы прокрутки, нужно установить свойства MinHeight и MinWidth объекта UserDocument, как показано в следующем примере: Private Sub UserDocument Resize() UserDocumentl.MinHeight = 4000 UserDocumentl.MinWidth = 9000 End Sub Обычно свойства MinHeight и MinWidth нужно специфицировать. Если эти свойства явно не установлены, а используются умолчательные установки высоты и ширины объекта UserDo¬ cument, полосы прокрутки будут выводиться на экран и после изменения размера документа пользователем, когда вся информация помещается на полотне документа. Так как это обычно нежелательно, свойства MinHeight и MinWidth следует специфицировать. 10.5.2. Добавление меню к пользовательскому документу С помощью утилиты Menu Editor для документа ActiveX в Visual Basic можно создавать пользовательские меню. Ниже на примере реализации пользовательского окна About меню Help показано, как к документу можно добавить меню. Для всех документов ActiveX желательно обеспечить окно About. Информация в этом окне обычно дает пользователям информацию относительно разработчика и версии документа, данных авторского права и вопросов лицензирования. В Visual Basic окно About добавляется через окно диалога Add Form (рис. 10.8). В умолчательной форме About для документа следует установить соответствующие значе¬ ния свойства Caption для формы и элементов управления Label (рис. 10.9).
260 Пользовательский интерфейс и пользовательский документ Рис. 10.8. Открытие новой формы About в окне диалога Add Form. Рис. 10.9. Умолчательная форма About, добавляемая к проекту через окно диалога Add Form.
Гпава 10. Создание и использование документов ActiveX 261 Создание меню Help При создании для документа ActiveX пользовательского меню Help оно автоматически объединяется с контейнером. Устанавливая значение свойства NegotiatePosition, можно указать, где меню Help документа ActiveX будет показано внутри меню Help контейнера. Для создания меню и подменю Help и для команды About можно использовать окно Menu EditorVisual Basic. После этого к событию Click меню About можно добавить следующий программный код: Private Sub mnuAbout Click() frmAbout.Show vbModal ' Открыть форму About как модальное окно End Sub Рис. 10.10. Вывод формы About документа выбором пункта менюдокумента в строке меню приложения-контейнера.
262 Использование гнезд Глава 11. Создание приложений для Internet Visual Basic можно использовать для создания приложений-клиентов, которые позволяют осуществлять доступ к Internet. Эти приложения могут предоставлять ряд возможностей для пользователей Web, включая просмотр Web-страниц, участие в сеансах конференций и перемещение файлов между компьютерами, которые работают под разными операционны¬ ми системами. В этой главе описывается создание приложений-клиентов, которые обеспечивают эти воз¬ можности. Здесь также показано, как установить и управлять приложением Personal Web- Server, чтобы можно было легко тестировать создаваемые приложения-клиенты. 11.1. Использование гнезд Гнездо (socket) — двунаправленный логический терминал (выход), через который два приложения или процесса могут обмениваться данными. Например, гнезда используются для реализации приложений конференций. Ниже представлены некоторые подробности архитектуры гнезд и показано, как, используя гнезда, организовать связь между серверами и клиентами. Гнезда обеспечивают механизм сетевой межпроцессной связи для TCP/IP и Internet. Серве¬ ры и клиенты гнезда реализуются с использованием элемента управления Winsock. 11.1.1. Функциигнезд Гнездо имеет следующие три существенных функции: • интерфейс, к которому привязывается гнездо (специфицируется адресом IP); • номер порта, на который гнездо будет передавать данные или с которого оно будет принимать данные; • тип гнезда (stream или datagram соответственно протоколам TCP и UDP). Основное различие между типами гнезд stream и datagram — их состояние соединения. Тип stream (поток), или TCP, — состояние, основанное на соединении. Оно подобно телефонной транзакции, в которой, прежде чем может осуществляться разговор, пользователь должен установить соединение. Тип гнезда datagram, или UDP, — состояние связи без соединения. Оно подобно радиопе¬ редаче, в том смысле, что явное, один-к-одному, соединение между сервером и клиентом не устанавливается. В этом случае сервер прослушивает на определенном известном порте все установленные сетевые интерфейсы, а клиент инициирует связь из определенного интерфейса, используя любой доступный порт. 11.1.2. Применениягнезд Обычно гнезда используются для создания приложений следующих типов: • приложения-клиенты, которые собирают информацию пользователя перед передачей ее центральному серверу; • приложения-серверы, которые функционируют как центральный пункт сбора данных от нескольких пользователей; • приложения для организации конференций.
Гпава 11. Создание приложений для Internet 263 11.1.3. Элемент управления Winsock Элемент управления Winsock, невидимый для пользователя, обеспечивает простой доступ к сетевым сервисам TCP и UDP. Он может использоваться разработчиками в Microsoft Access, Visual Basic, Visual C ++ или Visual FoxPro. Применяя его при написании приложений клиент/сервер, не требуется понимать подробности организации TCP или вызывать модули Winsock API низкого уровня. Устанавливая свойства и вызывая методы элемента управле¬ ния Winsock, можно легко соединяться с удаленной машиной и обмениваться данными в обоих направлениях. Рис. 11.1. Элемент управления Winsock в форме. Выбор протокола Тип применяемого протокола определяется характеристиками создаваемого приложения. Например, в выборе подходящего протокола связи помогут ответы на следующие вопросы: 1. Требуется ли в приложении уведомление или подтверждение отсервера или клиента при приеме или передаче данных? Если да, то следует выбрать протокол TCP, который требует установления явного соединения. 2. Будут ли передаваться большие массивы данных (например, графические образы или звуковые файлы)? После установления соединения протокол TCP контролирует его и гарантирует целостность данных. Такой тип соединения, однако, отбирает много систем¬ ных и сетевых ресурсов и поэтому более дорог. 3. Будут ли данные передаваться порциями или только за один сеанс? Например, если это всего лишь сообщение другому компьютеру о завершении некоторых операций, то, вероятно, можно удовлетвориться протоколом UDP. Протокол UDP больше подходитдля передачи небольших объемов данных. Общий порядок работы с TCP Протокол TCP (Transfer Control Protocol) позволяет создавать и поддерживать соединение с удаленным компьютером. Используя это соединение, оба компьютера могут адресовать данные между собой. Если создается приложение-клиент, необходимо знать имя компью- тера-сервера или адрес IP (свойство RemoteHost), а также порт (свойство RemotePort), который оно будет "прослушивать". Затем вызывается метод Connect. Если создается приложение-сервер, устанавливается порт прослушивания (свойство Local- Port) и вызывается метод Listen. Когда компьютер-клиент запрашивает соединение, проис¬ ходит событие ConnectionRequest. Для установления соединения внутри процедуры события ConnectionRequest вызывается метод Accept. После того как соединение установлено, любой из компьютеров может передавать и полу- чатьданные. Чтобы передатьданные, вызывается метод SendData. Всякий раз при получе¬
264 Использование гнезд нии данных происходит событие DataArrival. Для отбора данных следует внутри процедуры события DataArrival вызвать метод GetData. Общий порядок работы с UDP UDP (User Datagram Protocol) — протокол без соединения. В отличие от операций TCP компьютеры не устанавливают соединение. Кроме того, приложение UDP может быть как клиентом, так и сервером. Чтобы передать данные, сначала нужно установить свойство LocalPort компьютера-клиен- та. Затем компьютер-сервер должен только установить в свойстве RemoteHost адрес Inter¬ net компьютера-клиента, а в свойстве RemotePort — тот же порт, что и в свойстве LocalPort компьютера-клиента, и вызвать метод SendData, чтобы начать передавать сообщения. На компьютере-клиенте посланные сообщения принимаются с помощью метода GetData внут¬ ри процедуры события DataArrival. Добавление элемента управления Winsock к проекту Если элемента управления Winsock еще нет на панели элементов, его можно добавить к проекту через окно диалога Components: 1. В меню Project выбрать Components. 2. На вкладке Controls выбрать Microsoft Winsock Control 5.0 и нажать ОК. 11.1.4. Базовые операции с элементом управления Winsock Ниже представлены методы, свойства и события, используемые для соединения серверов и клиентов через элемент управления Winsock, а также показано, как создавать между двумя компьютерами соединение равноправных узлов. Программирование сервера при использовании элемента управления Winsock предполага¬ ет выполнение следующих шагов: 1. Используя свойство Protocol, специфицировать протокол, который сервер будет исполь¬ зовать при взаимодействии с клиентами. 2. Используя свойство LocalPort, специфицировать порт, через который сервер будет взаи¬ модействовать с клиентами. 3. Используя метод Listen, установить способ прослушивания входящих запросов соедине¬ ний от клиентов. 4. Используя событие ConnectionRequest, запрограммировать действия по принятию или отклонению запросов соединений. Дополнительную информацию относительно этого процесса см. ниже, в разделе "Програм¬ мирование сервера Winsock". Процедура программирования клиента при использовании элемента управления Winsock в целом аналогична программированию сервера: 1. Используя свойство RemoteHost, специфицировать имя удаленной машины, с которой клиент будет поддерживать связь. 2. Используя свойство RemotePort, специфицировать порт удаленной машины, через кото¬ рый клиент будет сообщаться с удаленной машиной. 3. Используя метод Connect, инициировать соединение между клиентом и удаленной машиной. Дополнительную информацию относительно этого процесса см. в разделе "Программиро¬ вание клиента Winsock".
Гпава 11. Создание приложений для Internet 265 После установления связи между клиентом и сервером между ними могут передаваться данные. Процедура передачи данных требует следующих шагов: 1. Использовать метод SendData в клиенте и сервере для передачи данных на другой компьютер. 2. Использовать метод GetData в процедуре события DataArrival в клиенте и сервере для приема данных из другого компьютера. Информацию относительно передачи данных между клиентом и сервером см. в разделе "Прием и передача данных". Программирование приложения равноправных узлов Более простой подход к написанию приложения с использованием гнезд заключается в создании приложения равноправных узлов, так как приложение равноправных узлов не требует явного соединения. Для программирования первого входа-выхода: 1. Используя свойство RemoteHost, специфицировать имя удаленной машины, с которой первый вход-выход будет поддерживать связь. 2. Используя свойство RemotePort, специфицировать порт на удаленной машине, через который первый вход-выход будет поддерживать связь с удаленной машиной. 3. Используя метод Bind, соединить локальный порт с удаленным портом, используя ло¬ кальный адрес Internet Protocol (IP). Для программирования второго входа-выхода требуются следующие шаги: 1. Используя свойство RemoteHost, специфицировать имя удаленной машины, с которой будет сообщаться второй вход-выход. 2. Используя свойство RemotePort, специфицировать порт на удаленной машине, через который второй вход-выход будет поддерживать связь с удаленной машиной. 3. Методом Bind соединить локальный порт с удаленным портом, используя локальный адрес IP. 11.1.5. Программирование сервера Winsock При создании приложения-сервера с элементом управления Winsock элемент управления настраивается для прослушивания на обозначенном порте сообщений от клиентов. Когда клиент делает запрос соединения, сервер может принять запрос и установить соединение. Установка свойства Protocol При создании сервера Winsock вначале необходимо определить тип сервера. Тип сервера устанавливается во время разработки или в период выполнения в свойстве Protocol. Значе¬ ние по умолчанию для этого свойства — TCP. Установка свойства LocalPort и вызов метода Listen После определения типа сервера для свойства LocalPort устанавливается некоторое целое число и вызывается метод Listen. Это может быть выполнено в событии Form_Load, как показано в следующем примере: Private Form Load() tcpServer.LocalPort = 1001 tcpServer.Listen End Sub
266 Использование гнезд Вызов события ConnectionRequest На заключительном шаге необходимо инициировать событие ConnectionRequest и прове¬ рить состояние сервера. Если порт сервера открыт, используя метод Accept, можно разре¬ шить соединение с клиентом. Например: Private Sub tcpServer ConnectionRequest (Index As Integer, ByVal requestID As Long) If Index = 0 Then intMax = intMax +1 Load tcpServer(intMax) tcpServer(intMax).LocalPort = 0 tcpServer(intMax).Accept requestID End If End Sub 11.1.6. Программирование клиента Winsock При программировании приложения-клиента с элементом управления Winsock специфици¬ руется имя удаленной машины и порт, через который будет осуществляться связь. Затем с помощью метода Connect устанавливается соединение с сервером. Специфицирование удаленной машины и удаленного порта Имя удаленной машины и порт прослушивания специфицируется в событии Form_Load клиента. При обращении к удаленной машине можно использовать или адрес Internet Protocol (121.111.1.1), или описательное имя. В следующем фрагменте кода используется описа¬ тельное имя: Private Sub Form Load() Winsockl.RemoteHost = "RemoteComputerName" Winsockl.RemotePort = 1001 End Sub Инициирование соединения После специфицирования удаленной машины и удаленного порта можно инициировать соединение с сервером. Для этого можно использовать событие Connect в событии Click командной кнопки, как показано в следующем примере: Private Sub cmdConnect Click() Winsockl.Connect End Sub 11.1.7. Приемипередачаданных Для передачи данных на удаленный компьютер используется метод SendData элемента управления Winsock. Передавать можно как строковые, так и двоичные данные. В следующем фрагменте кода на удаленный компьютер передается строка: Private Sub cmdSend Click() ' Передать данные, содержащиеся в текстовом поле Winsockl.SendData txtSendData.Text End Sub При передаче двоичных данных нужно заменить параметр метода SendData битовым массивом.
Гпава 11. Создание приложений для Internet 267 Отбор данных Для получения данных с удаленного компьютера в процедуре обработки события использу¬ ется метод GetData элемента управления Winsock, в котором отбираются данные, кэширо¬ ванные элементом управления. Синтаксис метода GetData: объект.GetData данные, [тип,] [тах_длина] Переменная данные имеет тип Variant, но, обеспечивая параметр тип, можно специфици¬ ровать формат, в котором требуется получить данные. Параметр тах длина определяет максимальный объем данных, которые могут быть загружены в переменную данные. В следующем фрагменте для получения данных используется событие DataArrival: Private Sub Winsockl DataArrival (ByVal bytesTotal As Long) Dim strData As String Winsockl.GetData strData, vbString ' Внести полученные данные в текстовое поле txtDisplay = txtDisplay & strData End Sub Параметр bytesTotal процедуры события DataArrival указывает количество отбираемых байт. 11.2. Установление соединений FTP и HTTP в Internet Протокол передачи файлов (FTP — FileTransfer Protocol) и Протокол передачи гипертекста (HTTP — Hypertext Transfer Protocol) — два наиболее широко используемых в Internet протокола. FTP позволяет пользователям находить и принимать по сети 1п1егпе1файлы всех типов, независимо от различий в операционных системах. Аналогично, HTTP позволяет пользователям находить, просматривать и загружать слюбой удаленной машины докумен¬ ты HTML. В этом разделе описывается использование элемента управления Internet Transfer для реализации в приложении-клиенте соединения FTP и HTTP. Здесь также показано, как программировать асинхронные и синхронные соединения. 11.2.1. Элементуправления lnternetTransfer В Visual Basic функциональные возможности FTP и HTTP реализуются с использованием элемента управления Internet Transfer. Этот элемент управления соединяет клиента с любым сервером, который поддерживает один из этих протоколов, и отбирает файлы, используя методы OpenURL или Execute. Функции сервера обычно обеспечиваются таким приложением, как Microsoft Internet Informa¬ tion Server или Personal Web-Server. Если элемента управления Internet Transfer еще нет на панели элементов, подключить его к проекту можно через окно диалога Components (рис. 11.2). 11.2.2. Базовые операции с элементом управления Internet Transfer Ниже представлены основные методы, свойства и события элемента управления Internet Transfer, используемые для реализации в клиенте функций FTP и HTTP. Примечание: Серверы FTP и HTTP прослушивают сообщения от клиентов. Обычно в этих серверах порт 21 назначают для входящих данных через FTP и используют другой порт для исходящих данных. Порт 80 используется для входящих и исходящих данных для HTTP.
268 Установление соединений FTP и HTTP в Internet Рис. 11.2. Элемент управления lnternetTransfer в форме. Методы OpenURL и Execute Для переноса данных с сервера в приложение-клиент используется либо метод OpenURL, либо метод Execute. Метод OpenURL — синхронный вызов, который открывает и возвращает документ, специ¬ фицированный пользователем, черезпротокол FTP или HTTP. Возвращенные данные могут отбираться как строковые или двоичные данные. Метод OpenURL — намного проще в программировании, чем метод Execute. Метод Execute — асинхронный запрос к удаленному серверу. Статус асинхронной операции обычно обеспечивается в событии StateChanged элемента управления lnternetTransfer. Метод Execute обеспечивает клиенту возможность выполнить широкий интервал файловыхопераций, таких, как передача, загрузка, удаление данных и прием распечаток каталогов. Метод Execute поддерживает такие команды HTTP, как GET, HEAD, POST и PUT, и также поддерживает такие команды FTP, как GET, PUT, SEND и DELETE. Хотя Execute обеспечивает больше функцио¬ нальных возможностей, чем OpenURL, он более сложен в программировании. Программирование асинхронных операций клиента включает следующие шаги: 1. Используя свойство AccessType, установить ссылку на допустимый сервер. 2. Используя метод Execute, начать передачуданных. 3. Используя событие StateChanged, в событии StateChanged проконтролировать состоя¬ ние соединения элемента управления. 4. Обработать ошибки, используя свойства ResponseCode и Responselnfo. 5. Методом GetChunk отобрать данные из буфера элемента управления. 6. Используя свойство StillExecuting, активировать асинхронную обработку. 7. Используя метод Cancel, остановить передачу данных, если пользователь хочет пре¬ рвать операцию до ее завершения. В асинхронном режиме клиент вводит запрос, но продолжает выполнять свою обработку, пока не возвращается ответ. Клиент может вводить несколько запросов и может обраба¬ тывать их в любом порядке, в котором они возвращаются. Асинхронная связь независима от сети, и клиенты могут вводить запросы, даже если в сети или удаленной системе возникают проблемы. Информацию относительно программирования клиента для асин¬ хронной работы см. в разделе "Программирование асинхронных операций".
Гпава 11. Создание приложений для Internet 269 Программирование синхронных операций клиента предполагает выполнение следующих базовых шагов: 1. Используя свойство AccessType, установить ссылку на сервер. 2. Используя метод OpenURL, начать переносданных. Информацию относительно программирования клиентов для выполнения синхронных опе¬ раций см. в разделе "Программирование синхронных операций". 11.2.3. Программирование асинхронных операций Установка свойства AccessType Чтобы специфицировать, как должен осуществляться доступ к серверу — непосредственно или через полномочный (proxy) сервер, вначале необходимо установить свойство AccessTy¬ pe элемента управления Internet Transfer. В следующем фрагменте кода показано, как установить свойство AccessType, используя константу icUseDefault. Для обращения к Inter¬ net через эту константу используются умолчательные установки системного реестра. Inetl.Accesstype = icUseDefault Использование метода Execute После установки способа доступа к серверу методом Execute инициируется запрос данных. Синтаксис метода Execute: объект. Execute url, операция, данные, заголовки Установки параметра операция для протокола HTTP: Элемент Описание объект Объектное выражение, содержащее ссылку на элемент управления Internet T ransfer. url Необязательный. Строка, содержащая URL, с которым элемент управления Internet Transfer должен соединиться. Если URL не специфицирован, берется значение из свойства URL элемента управления. операция Необязательный. Строка, содержащая тип (команду) выполняемой операции (перечень команд см. ниже). данные Необязательный. Строка, специфицирующая данные для операций (см. ниже). заголовки Необязательный. Строка, специфицирующая дополнительные заголовки, пе¬ редаваемые на удаленный сервер. Формат — имя заголовка: значение заголовка vbCrLf. Установки параметра операция для протокола FTP: Операция Описание GET Отбор данных из URL, специфицированного свойством URL. HEAD Передача заголовков запроса. POST Передача данных на сервер. Данные определяются параметром данные. Здесь содержимое параметра данные отличается от содержимого для команды GET, для которой в параметре данные специфицируются дополнительные инструкции. PUT Операция записи. Имя заменяемой страницы содержится в параметре данные.
270 Установление соединений FTP и HTTP в Internet Примечание: Для протокола FTP используется единственная строка, содержащая URL, а также имена операций и их параметры в параметре операция. Иными словами, параметры "данные” и "заголовки” здесь не используются. Параметры операций разделяются пробелами. Таким образом, синтаксис операции для FTP следующий: имя_операции файл1 файл2. Например, в следующем фрагменте в методе Execute со специфицированного URL выпол¬ няется прием двух файлов: Inetl.Execute "FTP://ftp.microsoft.com", "GET Filel.txt C:\Temp\File2.txt" Операция Описание CD file1 Переход к директории, специфицированной в file1. CDUP Переход кдиректории уровнем выше. Эквивалентно "CD.." CLOSE Закрыть текущее соединение FTP. DELETE file1 Удалить файл file1. DIR file 1 Поиск file1 (допускаются символы подстановки, но синтаксис их дикту¬ ет удаленный сервер). Если параметр file1 не указан, возвращается вся текущая рабочая директория. Для получения непосредственно данных используется метод GetChunk. GET file1 file2 Принять файл file1 и создать новый локальный файл file2. LS file1 Поиск файла file1 (допускаются символы подстановки, но синтаксис их диктует удаленный сервер). Для получения непосредственно данных используется метод GetChunk. MKDIR file1 Создать директорию file1. Успех операции зависит от привилегий пользователя на удаленном сервере. PUT file1 file2 Копировать локальный файл file1 в удаленное расположение, специ¬ фицированное в file2. PWD Вернуть имя текущей директории. Для получения непосредственно данных используется метод GetChunk. QUIT Завершает сеанс пользователя. RECV file1 file2 Принять удаленный файл file1 и создать новый локальный файл file2. Эквивалентно GET. RENAME file1 file2 Переименовать файл file1 в file2. Успех операции зависит от привиле¬ гий пользователя на удаленном сервере. RMDIR file1 Удалить директорию file1. Успех операции зависит от привилегий пользователя на удаленном сервере. SEND file1 file2 Копировать локальный файл file1 в удаленное расположение, специ¬ фицированное в file2. Эквивалентно PUT. SIZE file1 Вернуть размер директории file1. В следующем фрагменте кода метод Execute используется для получения листинга катало¬ га с сервера FTP: Inetl.Execute "ftp://ftp.microsoft.com", "DIR" Использование события StateChanged Для управления загрузкой данных и обеспечения механизма обработки ошибок необходимо внести программный код в процедуру события StateChanged.
Гпава 11. Создание приложений для Internet 271 Определять момент отбора данных можно, проводя проверку состояния icResponseComp- leted в событии StateChanged. Затем для приема данных используется метод GetChunk. В следующем фрагменте для тестирования состояния icResponseCompleted используется оператор Select Case: Private Sub Inetl StateChanged(ByVal State as Integer) Select Case Case icResponseCompleted ' Копировать данные методом GetChunk Case icError Inetl.Cancel ' Сообщить пользователю об ошибке и завершить ' асинхронную операцию End Select End Sub Использование метода GetChunk После наступления состояния icResponseCompleted методом GetChunk можно переместить данные из буфера элемента управления в расположение-адресат. Для этого можно вклю¬ чить программный код в строке icResponseCompleted оператора Case, как показано в следующем примере: Case icResponseCompleted Dim s As String ' Получить порцию данных s = Inetl.GetChunk(1024) Do While Len(s) > 0 txtOutput = txtOutput & s s = Inetl.GetChunk(1024) Loop Свойство StillExecuting Наконец, с помощью свойства StillExecuting нужно проверить состояние элемента управле¬ ния Internet Transfer. Когда элемент управления занят обработкой, например загрузкой файла из Internet, это свойство возвращает True и элемент управления не отвечает на другие запросы. В следующем примере показано использование функции DoEvents для передачи управле¬ ния операционной системе, с тем чтобы в очередь на обработку могли быть поставлены другие события: Inetl.Execute ... ' Здесь - выполнить операцию метода Execute While Inetl.StillExecuting DoEvents Wend ' Операция завершена Отмена асинхронной обработки Одним из преимуществ асинхронной обработки является то, что пользователь может пре¬ рвать операцию до ее завершения. Эту возможность можно обеспечить рядом способов. Например, пользователь может щелкнуть кнопку Отмена в не-модальной форме или нажать клавишу < Esc >. Независимо от способа для завершения операции в приложении нужно использовать метод Cancel элемента управления Internet Transfer.
272 Установление соединений FTP и HTTP в Internet В следующем фрагменте кода для завершения асинхронной операции пользователем используется событие Click командной кнопки: Private Sub cmdCancel Click() If Inetl.StillExecuting Then INetl.Cancel End If End Sub 11.2.4. Программирование синхронных операций Программирование синхронной загрузки включает установку типа доступа и вызов метода OpenURL. Синтаксис метода OpenURL: o6beKm.OpenURL strURL[, тип_данного\ Параметр strURL — любой допустимый URL FTP или HTTP. Если специфицировано имя файла, будет загружен файл. Если специфицировано имя каталога, будет загружен листинг каталога. Параметр тип_данного определяет тип возвращаемых данных — строковый (icString) или двоичный (icByteArray). В следующем фрагменте метод OpenURL используется для загрузки в текстовое поле с сервера Internet листинга каталога Microsoft FTP: Dim s As String s = Inetl.OpenURL("ftp://ftp.microsoft.com", icString) txtListing.Text = s Информацию относительно установки свойства AccessType см. в разделе "Программирова¬ ние асинхронных операций". 11.2.5. Использование элемента управления WebBrowser Элемент управления WebBrowser позволяет создавать средства просмотра для работы с файлами HTML или загрузки элементов управления ActiveX. Элементуправления WebBrowser— in-process сервер СОМ. Ондолжен применяться внутри некоторого другого процесса, но в него можно загружать документы Автоматики. Элемент управления WebBrowser реализует гиперссылки и предоставляет объекты-классы СОМ, которые могут использоваться другими компонентами. Элемент управления WebBrowser придает приложению-клиенту возможности просмотра документов, поиска и загрузки. Он позволяет пользователям просматривать узлы World Wide Web и папки в локальной файловой системе или сети. Элемент управления WebBrowser поддерживает навигацию посредством гиперссылок и перехода по URL. Элемент управления поддерживает список хронологии, который позволя¬ ет пользователям перемещаться вперед и назад по ранее посещенным сетевым узлам, папкам и документам. Элемент управления WebBrowser включает поддержку работы с документами HTML. Он также является контейнером для документов ActiveX и может загружать любой документ ActiveX. Внутри элемента управления WebBrowser могут быть открыты и оперативно отредактиро¬ ваны интенсивно форматированные документы, такие, как электронная таблица Microsoft Excel или документ Microsoft Word.
Гпава 11. Создание приложений для Internet 273 11.2.6. Применение элемента управления WebBrowser Некоторые из возможных применений элемента управления WebBrowser: • осуществление навигации и просмотр документов HTML в World Wide Web или внутрен¬ них сетях; • предоставление универсального окна, в котором пользователи могут редактировать все типы документов ActiveX; • создание настроенного приложения Web. Добавление элемента управления WebBrowser к проекту Visual Basic Если элемента управления WebBrowser еще нет на панели элементов, его можно подключить к проекту в окне Components. В этом окне нужно выбрать элемент Microsoft Internet Controls. Примечание: Первоначально при размещении элемента управления в форме он не имеет никакого видимого интерфейса, который должен быть построен разработчиком. Элемент управления Web¬ Browser обеспечивает лишь функциональность средства просмотра. 11.2.7. Основные операции с WebBrowser Ниже представлены методы, свойства и события элемента управления WebBrowser, кото¬ рые можно использовать для создания средства просмотра Web. Процедура активирования этих возможностей включает следующие шаги: 1. В методе Navigate специфицировать требуемый ресурсдля доступа. Ресурсдолжен быть указан в формате URL. 2. Разместить в элементе управления WebBrowser требуемые элементы управления и в событии NavigateComplete вывести в этих элементах управления имя и URL ресурса, используя свойства LocationURL и LocationName. 3. Используя методы GoBack, GoForward, GoSearch и GoHome элемента управления, запрог¬ раммировать процедуры навигации к узлам, включенным в списке History (хронология). 4. Используя свойство Busy, определить, находится ли элемент управления WebBrowser в процессе навигации к новому расположению или в процессе загрузки файла. С помощью метода Stop дать возможность отменить навигацию или загрузку до ее завершения. 5. С помощью методов Refresh и Refresh2 запрограммировать быструю перезагрузку стра¬ ницы, которая уже была показана. 6. Если выполняется загрузка из Web-страницы, используя события DownloadBegin, ProgressChange и DownloadComplete, показать на экране прогресс операции загрузки в строке состояния. 11.2.8. Программирование навигации в WebBrowser Большая часть работы при создании средства просмотра Web заключается в организации переходов от одной Web-страницы к следующей. Вначале для клиента необходимо специфицировать начальную страницу. Обычно это де¬ лается в событии Form_Load с помощью метода Navigate. В следующем фрагменте кода показано использование метода Navigate для перехода по URL: Private Form Load() WebBrowser.Navigate URL:="http://directoryl/pagel.htm" End Sub
274 Установление соединений FTP и HTTP в Internet Далее нужно вывести на экран URL и имя узла, к которому выполнен переход. Обычно это делается в событии NavigationComplete. В следующем фрагменте URL помещается в поле со списком на форме, а имя страницы выводится во второй панели строки состояния: Private Sub wb NavigateComplete(ByVal URL As String) cboURL = WebBrowserl.LocationURL sbMain.Panels(2) = WebBrowserl.LocationName End Sub Программирование кнопок навигации Следующий шаг — добавить программный коддля кнопок Назад, Вперед, Стоп и Обновить. Процедура здесь одинакова для всех четырех кнопок. Командные кнопки необходимо поме¬ стить в форму или панель инструментов и в событии Click для каждой кнопки внести оператор, который вызывает соответствующий метод. В следующем примере метод GoBack используется в событии Click кнопки Назад: Private Sub cmdGoBack Click() WebBrowserl.GoBack End Sub Остановка навигации Для остановки навигации используется свойство Busy и метод Stop. В следующем фрагменте кода показано, как программировать командную кнопку с помощью конструкции lf...Then для определения состояния элемента управления WebBrowser и оста¬ нова операции, если он занят: Private Sub cmdStop Click() If WebBrowserl.Busy Then WebBrowserl.Stop WebBrowserl.GoBack End If End Sub Перезагрузка страницы Чтобы перезагрузить страницу, которая уже была показана, можно использовать метод Refresh или метод Refresh2. Метод Refresh перезагружает страницу, которая в данный момент выведена на экран, отбирая данные из кэша компьютера клиента. Метод Refresh2 принимает параметр, определяющий уровень регенерации, которую нужно выполнить. При использовании метода Refresh2 страница может регенерироваться из кэша или с сервера, откуда она была загружена первоначально. В следующем примере кода метод Refresh используется для перезагрузки страницы, в данный момент отображаемой средством просмотра: Private cmdRefresh Click() WbBrowserl.Refresh End Sub Отображение прогресса загрузки Если в приложении реализуются возможности загрузки данных, то, используя события DownloadBegin, ProgressChange и DownLoadComplete, можнодать пользователю информа¬ цию относительно процесса загрузки.
Гпава 11. Создание приложений для Internet 275 Сначала для инициализации строки прогресса программируется событие DownloadBegin (используются элементы управления ProgressBar и StatusBar): Private Sub WebBrowserl DownloadBegin() ' Инициализировать ProgressBar pbMain.Move sbMain.Panels(l).Left, 10, _ sbMain.Panels(l).Width, sbMain.Height - 10 pbMain.Value = 0 pbMain.Min = 0 pbMain.Max = 100 pbMain.Visible = True End Sub Затем в событии ProgressChange вычисляется статус прогресса и это значение выводится на экран. Например: Private Sub wb ProgressChange(ByVal Progress As Long, ByVal ProgressMax As Long) ' Изменить состояние ProgressBar If Progress <> -1 And ProgressMax <> 0 Then pbMain.Value = Progress * 100 / ProgressMax End If End Sub Используя событие DownloadComplete, можно сообщить пользователю о завершении за¬ грузки. В следующем фрагменте по завершении загрузки строка прогресса установкой свойства Visible в False скрывается: Private Sub WebBrowserl DownloadComplete() ' Скрыть ProgressBar pbMain.Visible = False End Sub 11.3. Использование Автоматики с Internet Explorer С помощью элемента управления WebBrowser можно управлять всеми аспектами интерфейса средства просмотра. Однако в некоторых ситуациях, возможно, выгодней будет создать экзем¬ пляр Internet Explorer, чтобы избежать процедур программирования элемента управления. Ниже представлен объект lnternetExplorer и показано использование его через механизмы Автоматики. Так как объект lnternetExplorer очень похож по функциональным возможностям на элемент управления WebBrowser, здесь описываются дополнительные черты объекта lnternetExplorer. 11.3.1. 06beKTlnternetExplorer В Visual Basic можно создавать экземпляр Internet Explorer и использовать его как компонент ActiveX. Internet Explorer имеет объектную модель, методы и свойства которой предостав¬ ляются для использования другими приложениями. Объект lnternetExplorer реализован как in-process класс (на базе DLL) Компонентной Объек¬ тной Модели. Свойства объекта lnternetExplorer Internet Explorer поддерживает те же свойства и методы, что и элемент управления Web¬ Browser, наряду с несколькими, которые WebBrowser не поддерживает. Почти все эти дополнительные свойства относятся к пользовательскому интерфейсу.
276 Работа с Personal Web-Server В следующей таблице приведены дополнительные свойства, поддерживаемые объектом lnternetExplorer: Свойство Описание FullName Определяет полностью квалифицированный путь исполняемого файла, который содержит приложение Internet Explorer. FullScreen Указывает, является ли режим окна Internet Explorer полноэкранным или нормальным. MenuBar Определяет видимость строки меню Internet Explorer. Name Возвращает имя Internet Explorer Microsoft. StatusBar Определяет видимость строки состояния Internet Explorer. StatusText Устанавливает или возвращает текст для строки состояния. Toolbar Определяет видимость панели инструментов Internet Explorer. Объект lnternetExplorer также поддерживает метод Quit. Информацию относительно базовых методов, свойств и событий, доступных для объекта lnternetExplorer, см. в разделах "Основные операции с WebBrowser" и "Программирование навигации в WebBrowser". Чтобы Internet Explorer можно было использовать как компонент ActiveX, к проекту Visual Basic необходимо добавить ссылку на компонент Microsoft Internet Controls. Это можно сделать в окне диалога References (команда References меню Project). После установления ссылки объект lnternetExplorer можно использовать точно так же, как и любой другой объект в Visual Basic: устанавливать или возвращать свойства и вызывать методы объекта lnternetExplorer. В следующем фрагменте кода создается объектная переменная и экземпляр Internet Explorer: Dim browser As lnternetExplorer Set browser = CreateObject("InternetExplorer.Application") Как и другие компоненты ActiveX, при запуске объект Internet Explorer является невидимым. Чтобы сделать его видимым, необходимо установить в True свойство Visible. В следующем примере выполняется навигация к узлу Web www.Microsoft.com: browser.Visible = True browser.Navigate "http://www.Microsoft.com" Этот и предыдущий код можно внести либо в процедуру Sub Main() стандартного модуля проекта, либо в процедуру события элемента управления в форме, например, кнопки. 11.4. Работа с Personal Web-Server Microsoft Personal Web-Server для Windows 95 превращает любой компьютер Windows 95 в Web-сервер и позволяет выполнять простую публикацию личных Web-страниц. Простой в установке и управлении, Personal Web-Server (PWS) упрощает совместное использование информации в корпоративных внутренних сетях, а также в Internet. PWS оптимизирован для разработки, тестирования и развертывания Web-приложений. Personal Web-Server предназначен для использования на рабочей станции, и для его эксплуатации не предъявляется всех системных требований полного сервера Web. Personal Web-Server доступен из ряда источников — он поставляется с Windows 95 и может быть загружен через Internet.
Гпава 11. Создание приложений для Internet 277 11.4.1. Конфигурирование Personal Web-Server Для тестирования Personal Web-Server имеется несколько сценариев. Тестировать Personal Web-Server можно, когда он: • соединен с Internet; • соединен с внутренней сетью; • находится в автономной конфигурации. Конфигурирование Personal Web-Server для автономного компьютера Специальный случай установки и тестирования Personal Web-Server — выполнение его на автономном компьютере. Это позволяет тестировать приложения для Internet, даже если компьютер не соединен с Internet или внутренней сетью. Для выполнения описываемой ниже процедуры нужно иметь сетевой адаптер, сетевые драйверы и TCP/IP, установленные на компьютере, который будет работать в автономном режиме. Перед запуском процедуры необходимо установить Personal Web-Server. Примечание: Этупроцедуруне рекомендуется выполнять, если компьютер соединен с сетью, так как это обусловит проблемы для данного компьютера и других компьютеров в сети. Конфигурирование сетевых установок Перед запуском этой процедуры следует закрыть все открытые приложения. Изменения установок обретут силу после перезапуска компьютера. Примечание: В скобках — названия компонентов интерфейса локализованной версии Windows 95. 1. Открыть Control Panel (Панель управления) и дважды щелкнуть пиктограмму Network (Сеть). 2. В окне диалога Network открыть вкладку Configuration (Конфигурация). Выбрать компо¬ нент TCP/IP для сетевого адаптера, установленного на компьютере, и затем щелкнуть кнопку Properties (Свойства) (рис. 11.3.). 3. После завершения Шага 2 открывается окно диалога TCP/IP Properties (Свойства: TCP/IP). Чтобы назначить IP адрес компьютеру, открыть вкладку IP Address. Далее: а) Записать текущие установки, чтобы можно было вернуть компьютер к оригинальному состоянию. б) Выбрать опцию Specify an IP address (Указать адрес IP явным образом). в) Ввести в разделы поля определенный адрес IP (например, 123.45.6.78). г) Оставить поле Subnet Mask (Маска подсети) пустым; значение будет назначено автоматически (рис. 11.4). 4. Чтобы сделать автономный компьютер сервером WINS (Windows Integrated Name Server), открыть вкладку WINS Configuration (Конфигурация WINS). Далее: а) Записать текущие установки, чтобы можно было вернуть компьютер к оригинальному состоянию. б) Выбрать опцию Enable WINS Resolution (Включить распознавание WINS). в) В полях ввести Primary WINS Server (Главный сервер WINS) и Secondary WINS Server (Второй сервер WINS) тот же адрес, что и в Шаге Зв (123.45.6.78). г) Поле Scope ID (Код области) оставить пустым. д) Щелкнуть OK, чтобы подтвердить изменения установок (рис. 11.5).
278 Работа с Personal Web-Server Рис. 11.3. Экран окна диалога Network. Рис. 11.4. Установки окна диалога TCP/IP Properties для шага 3.
Гпава 11. Создание приложений для Internet 279 Рис. 11.5. Установки окна диалога окна TCP/IP Properties для шага 4. Рис. 11.6. Установки окна диалога TCP/IP Properties для шага 5.
280 Пример: Создание приложения для работы в Internet 5. Если требуется обеспечить возможность при тестировании приложений на автономном компьютере использовать имена компьютеров вместо адресов IP, следует также изме¬ нить установки конфигурации DNS. Чтобы изменить эти установки, нужно открыть вклад¬ ку DNS Configuration (Конфигурация DNS). Далее: а) Записать текущие установки, чтобы можно было вернуть компьютер к оригинальному состоянию. б) Выбрать опцию Enable DNS (Включить DNS). в) Ввести имя компьютера в поле Host (Главный компьютер). г) Оставить остальные поля пустыми (рис. 11.6). 6. Нажать OK, чтобы закрыть окно диалога Network (Сеть), и далее нажать Yes на запрос о перезапуске компьютера. 11.4.2. 3anycKPersonalWeb-Server 1. Открыть Control Panel, дважды щелкнуть пиктограмму Personal Web-Server и удостове¬ риться, что Personal Web-Server, службы FTP и HTTP работают. 2. Открыть вкладку Startup и удостовериться, что Personal Web-Server3anyLueH. Если нет — щелкнуть кнопку Start. 3. Открыть вкладку Services и удостовериться, что статус службы FTP — Running. Если нет — выбрать FTP из списка Services и щелкнуть кнопку Start. 4. На вкладке Services удостовериться, что статус службы HTTP — Running. Если нет — выбрать HTTP из списка Services и щелкнуть кнопку Start. 11.5. Пример: Создание приложения для работы в Internet В следующем примере реализуются положения и методы, рассмотренные в разделах главы. 11.5.1. Формирование с использованием WebBrowser приложения — средства просмотра На первом этапе создается новый проект, элементы пользовательского интерфейса — панель инструментов, строка состояния — и обеспечиваются возможности навигации в Web. В строке состояния также выводится строка прогресса (рис. 11.7). 1. Создать новый проект Standard EXE. 2. В основной форме добавить элементы управления Toolbar, lmageList, Statusbar и Prog- ressBar. Все эти элементы управления содержатся в компоненте Microsoft Windows Common Controls 5.0, который необходимо подключить к проекту. 3. Для элемента управления ProgressBar свойство Visible установить в False. 4. Добавить к форме элемент управления WebBrowser. Этот элемент управления содержит¬ ся в компоненте Microsoft Internet Controls. Проектирование панели инструментов 1. Через страницу свойств (окно диалога Property Pages) элемента управления Toolbar расположить в панели инструментов пять функциональных командных кнопок. Перед этим создать с левого края панели инструментов кнопку-заполнитель (стиль tbrPlaceholder) шириной, достаточной для размещения в панели инструментов поля со списком.
Гпава 11. Создание приложений для Internet 281 Рис. 11.7. Компоненты пользовательского интерфейса окна WebBrowser. 2. Добавить к панели инструментов поле со списком, в которое пользователи смогут вво¬ дить новые URL и в котором будут храниться более ранние URL. Добавить для поля со списком соответствующую надпись. 3. Добавить к элементу управления lmageList графические образы для пиктограмм кнопок. Ассоциировать Toolbar с элементом управления lmageList (вкладка General страницы свойств элемента управления Toolbar). Рис. 11.8. Добавление пиктограмм для кнопок панели инструментов.
282 Пример: Создание приложения для работы в Internet Назначение элементов управления панели инструментов: Элемент управления Назначение Кнопка "Стоп" Остановка асинхронной операции Web-Browser. Кнопка "Назад" Перейти к предыдущей странице, показанной в средстве просмотра Web. Кнопка "Вперед" Перейти к следующей странице по хронологии. Кнопка "Начальная страница" Перейти к начальной странице, специфицированной в сис¬ темном реестре. Кнопка "Поиск" Перейти к странице поиска в Web, специфицированной в системном реестре. Проектирование строки состояния 1. Установить для свойства AutoSize первой панели значение sbrContent. Это позволит регулировать размер панели, основываясь на размере выводимого текста, но с мини¬ мальной шириной, специфицированной свойством MinimumWidth. В этой панели будет выводиться элемент управления ProgressBar. 2. Вставить вторую панель, в которой будет выводиться заголовок текущей страницы, отображаемой в средстве просмотра. Установить для свойства AutoSize значение sbrSpring, чтобы размер базировался на доступной ширине строки состояния. 11.5.2. Программирование приложения Следующий шаг — написание для приложения исходного программного кода. Здесь же показан вывод в панели строки состояния строки прогресса операции и активирование других окон приложения. Примечание: В приводимом примере не описываются процедуры обработки ошибок. Однако при выполнении многих из операций, выполняемых приложением, могут происходить сбои, например при переходе по недостоверному URL. Поэтому для надежной работы в таких приложениях необходимо обеспечить обработку ошибок. Инициализация элемента управления WebBrowser 1. Добавить программный код перехода к начальной странице: а) Объявить строковую переменную уровня формы, которая будет содержать имя на¬ чальной страницы. б) В событии Form_Load в операторе с функцией GetSetting извлечь умолчательную начальную страницу из системного реестра. Значения параметров оператора пере¬ числены в следующей таблице: Параметр Значение appname IAwareApp section Startup key StartPage default HomePage.HTML в каталоге приложения (см. App.Path). в) Используя метод Navigate объекта WebBrowser, вывести начальную страницу на экран. г) В событии Form_Unload, используя оператор SaveSetting, сохранить имя начальной страницы в системном реестре.
Гпава 11. Создание приложений для Internet 283 2. Смасштабировать элемент управления WebBrowser в соответствии с размером формы: а) Добавить процедуру обработки для события Form_Resize. б) Настроить размер элемента управления WebBrowser так, чтобы он заполнил полотно формы между элементом управления Toolbar и элементом управления StatusBar. Программирование навигации в WebBrowser 1. Добавить код для обработки URL в поле со списком: а) Внести код в процедуру обработки события KeyPress поля со списком. б) Если значение KeyPress — возврат каретки (значение ASCII 13) и текст в поле редактирования поля со списком не пустая строка, использовать метод Navigate элемента управления WebBrowser для вывода специфицированного URL и метод Addltem — для добавления URL к списку. в) Добавить процедуру обработки события Click поля со списком. г) Выполнить навигацию к URL, выбранному в поле со списком. 2. Запрограммировать кнопки навигации: а) Если средство просмотра занято обработкой (свойство Busy), в событии ButtonClick панели инструментов для кнопки Стоп остановить текущую операцию и вернуться к предыдущему URL. б) В событии ButtonClick для кнопки Назад вызвать метод GoBack объекта WebBrowser. Используя соответствующие методы, повторить этот шагдля кнопок Вперед, Началь¬ ная страница и Поиск. В следующем примере показана обработка нажатий кнопок панели инструментов: Private Sub tlbWeb ButtonClick(ByVal Button As Button) Select Case Button.Key Case "Back" ' Выполнение перехода к предыдущей странице Case "Forward" ' Переход к следующей странице хронологии Case Else ' Обработка других случаев End Select End Sub Программирование элемента управления ProgressBar 1. Сделать ProgressBar подчиненным элемента управления Statusbar. Это позволит выво¬ дить элемент управления ProgressBar поверх элемента управления StatusBar и распола¬ гать его, основываясь на координатах элемента управления StatusBar: а) Добавить к проекту стандартный модуль. б) В стандартном модуле добавить оператор объявления для SetParent API. Так как это функция Win32, для написания правильного оператора Declare можно использовать API Text Viewer, который поставляется с Visual Basic (см. главу 6 "Работа с библиоте¬ ками динамической компоновки"). в) В событии Form_Load, используя SetParent API, установить в качестве родителя окна элемента управления ProgressBar окно элемента управления StatusBar.
284 Пример: Создание приложения для работы в Internet 2. В течение операции загрузки отображать и изменять элемент управления ProgressBar: а) Добавить процедуру обработки для события DownloadBegin элемента управления WebBrowser. б) Инициализировать элемент управления ProgressBar минимальным значением 0, мак¬ симальным значением 100 и начальным значением 0. в) Заполнить элементом управления ProgressBar первую панель элемента управления StatusBar и установить его свойство Visible в True. 3. По окончании загрузки скрыть элемент управления ProgressBar: а) Добавить процедуру обработки для события DownloadComplete элемента управления WebBrowser. б) Установить в False свойство Visible элемента управления ProgressBar. 4. Изменение элемента управления ProgressBar в течение операции загрузки: а) Добавить процедуру обработки для события ProgressChange элемента управления WebBrowser. б) Если параметр Progress — не -1 и параметр ProgressMax — не 0, установить свойство Value элемента управления ProgressBar равным проценту выполнения операции. Примечание: Процент выполнения вычисляется, как значение Progress, деленное на MaxProgress и умноженное на 100.
Гпава 12. Создание программы Setup и оптимизация приложения 285 Глава 12. Создание программы Setup и оптимизация приложения При распространении приложения в дистрибутивный пакет необходимо включить исполня¬ емый файл приложения, а также все сопутствующие файлы, требуемые для работы прило¬ жения, такие, как библиотеки DLL, пользовательские элементы управления и серверы Автоматики. Для правильной установки этих компонентов пользователей нужно обеспечить программой установки Setup. Помимо создания программы установки, в этой главе также рассматривается оптимизация производительности приложения и использование инструментальныхсредств, обеспечива- eMbixVisual Ваэюдпя повышения эффективности разработки приложения. Показано также, как использовать служебную программу удаления приложения, которая включается с про¬ граммами Setup, создаваемыми мастером Setup Wizard. 12.1. Создание программы установки Программа Setup должна обеспечить выполнение следующих задач: • копирование необходимых файлов на систему пользователя; • размещение файлов в соответствующих папках; • регистрация файлов; • создание группы для Program Manager или элемента или группы меню Start. Для создания программы Setup можно использовать Setup Wizard, обеспечиваемый Visual Basic (см. также раздел "Создание программы установки элемента управления" в главе 9). Visual Basic также включает пакет Setup Toolkit, который можно подключать к Setup Wizard для создания пользовательской программы Setup. Разработчик может также создавать свою собственную программу Setup, определять, какие файлы необходимы, компрессиро¬ вать файлы и вручную копировать файлы на диск или в папку Setup. 12.1.1. Использование мастера Setup Wizard Самый простой способ создания программы Setup — использовать мастер Setup Wizard. Setup Wizard запрашивает информацию относительно приложения и автоматически опре¬ деляет, какие файлы должны быть включены для тиражирования, сжимает файлы, копирует их на диск и создает программу Setup. Setup Wizard поддерживает следующие опции распространения приложения: • создание нескольких установочных гибких дисков. Setup Wizard может разбивать файлы, если они не умещаются на гибкий диск; • копирование файлов в отдельный установочный каталог на жестком диске для распреде¬ ления по сети или через CD-ROM; • распространение приложения по Internet с использованием механизма загрузки програм¬ много кода Microsoft Internet Explorer версии 3.0. Запустить Setup Wizard можно, выбрав файл Setupwiz.exe из папки \Setupkit\kitfil32 в дирек¬ тории установки Visual Basic. Для определения файлов, которые необходимо включить в программу Setup, Setup Wizard прослеживает ссылки и пользовательские элементы управления, включенные в проект. Затем Setup Wizard читает файл VB5Dep.ini в папке Windows, чтобы определить, какие файлы требуются для каждой ссылки или пользовательского элемента управления.
286 Создание программы установки Например, если в проекте установлена ссылка на элемент управления Microsoft Common Dialog, Setup Wizard включает в программе Setup соответствующий файл (Comdlg32.ocx). Примечание: Wizard Setup позволяет добавлять или удалять файлы из списка файлов, которые должны включаться в Setup. Если элементы управления, которые не использовались в приложении, появляются в экране шага Confirm Dependencies или если открывается экран Data Access Object, но известно, что ссылка на Объекты доступа к данным (DAO) не добавлялась, необходимо удалить неиспользуемые файлы — очистить флажки в списке. 12.1.2. Файлыустановки Диски Setup или папка дистрибутива на жестком диске, созданная Setup Wizard, будут содержать все файлы, необходимые для установки приложения в системе пользователя. Вот некоторые из необходимых файлов: Setup.exe Setup Wizard копирует Setup.exe с папки Visual Basic на дистрибутивные носители или в папку жесткого диска. Чтобы установить приложение, пользователь запускает Setup.exe. Setup.exe копирует файлы начальной загрузки, перечисленные в Setup.lst, и затем запуска¬ ет основную программу Setup (обычно, Setup1.exe). Setup.lst Setup Wizard создает файл Setup.lst. Этот файл содержит список файлов, требуемых приложением, а также общую информацию, например папки по умолчанию и требуемое дисковое пространство. Примерный файл Setup.lst может выглядеть следующим образом: [Bootstrap] Filel=l,,setupl.ex_,setupl.exe,$(WinPath),... [Files] Filel=l,,GRID32.ОС ,GRID32.OCX,$(WinSysPath),,$(Shared).. [Setup] Title=LoanSheet DefaultDir=$(ProgramFiles)\Loan Setup1 .exe Setup Wizard копирует основную программу установки, Setup1.exe, из папки Visual Basic на дистрибутивные диски или в папку жесткого диска. Setup1.exe копирует и регистрирует файлы и создает пиктограммы запуска. Программа Setup также увеличивает количество ссылок на разделяемые файлы в системном реестре. Программа установки создает файл журнала приложения (St5Unst.log), который копируется в папку приложения и включает следующую информацию: • созданные папки; • файлы, которые были установлены. В журнале отражаются случаи, когда файл не был скопирован, так как на диске была найдена более новая версия файла; • созданные вхождения системного реестра; • созданные группы Program Manager и вхождения меню Start; • DLL, EXE или OCX, которые были самозарегистрированы. Программа Setup также копирует служебную программу удаления приложения (St5Unst.exe) в папку Windows. Информацию относительно этой служебной программы см. в разделе "Удаление приложения".
Гпава 12. Создание программы Setup и оптимизация приложения 287 12.1.3. Использование пакета Visual Basic Setup Toolkit С помощью комплекта инструментальных средств Visual Basic Setup Toolkit можно созда¬ вать пользовательские программы Setup, добавляя возможности, которые не обеспечивает автоматически Setup Wizard. Например, Setup Toolkit можно использовать для создания программы Setup, которая выводит на экран пользовательские формы и окна диалога или позволяет пользователю установить необязательные параметры приложения. Пакет SetupToolkitcocTOHT из служебных программ, DLL и примерной программы установки, написанной на Visual Basic. Эта программа, Setup1.vbp, находится в папке \Vb\Setup- Kit\Setup1. Ее можно модифицировать подсвои потребности и затем создать исполняемый файл Setup1.exe. После этого с помощью Setup Wizard можно создать дистрибутивные диски или папку Setup. Setup Wizard копирует Setup1.exe из папки Visual Basic Setup- kit\Setup1 в папку Setup. Примечание: Рекомендуется сохранить оригинальную версию Setup1.vbp. Использование Setup Wizard с Setup Toolkit Setup Toolkit и Setup Wizard можно использовать совместно для добавления к программе установки окон диалога, в которых пользователю предлагается специфицировать установку в приложении необязательных функций. Например, в проекте может иметься файл оперативной справки, который некоторые пользователи могут не захотеть устанавливать. Можно добавлять столько опций установки, сколько требуется. Чтобы добавить к программе Setup опцию установки: 1. Отредактировать программный код Setup1 .frm, добавив в событии Form_Load, непосред¬ ственно после блока кода с вызовом функции Формы ShowBegin, примерно следующий программный код : Dim LoadHelp As Integer LoadHelp = MsgBox ("Хотите ли вы установить файлы Help?", vbYesNo) If LoadHelp = vbYes Then CalcDiskSpace "Help" EndIf ' Блок программного кода, содержащий cIcons = CountIcons(strINI_FILES) If LoadHelp = vbYes Then cIcons = CountIcons("Help") EndIf ' Блок программного кода, содержащий CopySection strINI FILES. If LoadHelp = vbYes Then CopySection "Help" EndIf ' Блок программного кода, содержащий CreateIcons strINI_FILES, strGroupName 2. Закрыть Setup1.frm, сохранить форму и проект и создать .exe файл. 3. Запустить Setup Wizard. В экране File Summary после подтверждения всех зависимостей файлов добавить имена всех файлов, которые требуется установить, если в этом окне диалога пользователь введет "Yes". 4. По завершении работы с Setup Wizard сформировать дистрибутивный носитель.
288 Оптимизация приложения 5. Вставить Disk1 в дисковод и открыть файл Setup.lst. Вырезать и вставить необязатель¬ ные файлы из раздела [Files] в новый раздел. Этот новый раздел будет расположен ниже раздела [Files], и ему будетдан новый заголовок раздела, который соответствует строко¬ вому параметру (например, [Help]), который использовался в операторе CopySection. Убедиться в том, что скопированные строки перенумерованы: [Help] Filel=5,SPLIT, Appl.HLl, Appl.HLP,$(AppPath),,,10/07/97,2946967 (AppPath),,,10/0 7/97,2 94 69 67 File2=6,SPLIT, Appl.HL2, Appl.HLP File3=7,, Appl.HL3, Appl.HLP Когда пользователь запускает программу установки, программа Setup копирует все файлы раздела [BootStrap] на машину пользователя и затем запрашивает у пользователя относи¬ тельно установки файлов Help. Если пользователь выбираетУеэ, в операторе CalcDiskSpa- ce определяется наличие достаточного дискового пространства на машине пользователя для файлов Help. Затем программа устанавливает все файлы, перечисленные в разделе [Files] файла Setup.lst. Далее программа снова тестирует флаг LoadHelp. Если пользователь выбрал установку файлов Help, Setup1 .exe выполняет для них оператор CopySection и устанавливает файлы, перечисленные в разделе [Help] файла Setup.lst. 12.1.4. Удалениеприложения Когда пользователь выполняет программу Setup, созданную Setup Wizard, программа уста¬ навливает в папку Windows системы пользователя служебную программу удаления прило¬ жений (St5Unst.exe). Для удаления приложения в Microsoft Windows NT или Windows 95 нужно щелкнуть пиктог- paMMyAdd/Remove Programs (Установка/удаление программ) в Control Panel. Служебная программа удаления приложений удаляет файлы приложения и пиктограммы или группы и уменьшает количество ссылок на разделяемые компоненты. Если количество ссылок — ноль, служебная программа запрашивает у пользователя подтверждение на удаление этого разделяемого компонента. Примечание: Служебная программа удаления приложения требует для работы наличия достовер¬ ного файла журнала и достоверного вхождения в системном реестре. Если приложение использует разделяемый компонент, о котором точно известно, что он имеется в системе пользователя, этот компонент все равно нужно включать с программой Setup. Этим гарантируется добавление ссылки на компонент, когда пользователь будет устанавливать приложение. 12.2. Оптимизация приложения Под оптимизацией приложения обычно понимается проведение мероприятий, повышаю¬ щих, насколько возможно, эффективность приложения. Visual Basic включает ряд инстру¬ ментальных средств, которые можно использовать для определения степени эффективности программного кода. Например, приложение можно оптимизировать так, чтобы пользователи могли сохранить текущие установки их рабочей среды. При этом в последующих сеансах пользователи не должны будут реконфигурировать компьютеры при запуске. Ниже описывается использование для оптимизации приложения надстройки Code Profiler. Также приводится ряд методов программирования, применение которых позволяет повы¬ сить производительность приложения.
Гпава 12. Создание программы Setup и оптимизация приложения 289 12.2.1. Visual Basic Code Profiler При оптимизации приложения необходимо определить, какой раздел кода выполняется наиболее часто, и затем постараться оптимизировать этот раздел кода. Visual Basic Code Profiler — надстройка, которая позволяет определить области приложения, оптимизация которых будет иметь наибольший эффект. Code РгоА1егсообщает, какой код выполняется в приложении, сколько раз и как долго он выполняется. Рис. 12.1. Окно диалога Code Profiler. Code Profiler поставляется с Visual Basic редакции Professional и находится в папке Tools (файл Vbcp.dll). Эта папка содержит различные инструментальные средства и вспомога¬ тельные программы. При установке Visual Basic эта папка не устанавливается. 12.2.2. Сохранение установок приложения Использование приложения упрощается, если имеется возможность сохранить информацию относительно операций пользователя или параметров, с которыми пользователь каждый раз запускает приложение. Эту информацию можно затем использовать в последующихсеансах. Например, можно сохранить имя последней базы данных, открытой пользователем, и ис¬ пользовать это имя в качестве умолчательной базы данных при следующем открытии. В Windows 3.1 и ранее программные установки обычно сохранялись в файлах .ini. В Windows NT и Windows 95 эти установки хранятся в системном реестре. Для сохранения установок приложения можно использовать операторы Visual Basic GetSetting и SaveSetting или подпрограммы Windows API. Использование GetSetting и SaveSetting Функция GetSetting используется для чтения установки из системного реестра. Синтаксис GetSetting следующий: GetSetting (имя_приложения, раздел, ключ, Q/молчание]) В следующем фрагменте кода из соответствующего ключа в системном реестре Windows 95 считывается информация номера заказчика: Dim strCustID as Integer Private Sub Form Load() strCustID = GetSetting _ ("OrderApp", "CustSection", "CustID", "0") End Sub
290 Оптимизация приложения Функция SaveSetting используется для записи вхождения в системный реестр. Синтаксис SaveSetting следующий: SaveSetting имя_приложения, раздел, ключ, установка В следующем фрагменте в соответствующем ключе системного реестра Windows 95 сохра¬ няется информация номера заказчика: Dim strCustID Private Sub Form Unload() strCustID = txtCustID.Text SaveSettings _ "OrderApp", "CustSection", "CustID", strCustID End Sub Использование Win32 API Windows обеспечивает несколько процедур, которые можно использовать для чтения и записи в файлы .ini. В Windows 95 и Windows NT сохранять специфическую для приложения информацию необходимо в системном реестре, используя операторы Visual Basic. Однако бывают слу¬ чаи, когда требуется использовать функции Windows (работа с файлами .ini). В следующей таблице перечислены процедуры Windows, которые можно использовать для сохранения установок приложения. Процедура Назначение GetPrivateProfileString Читает строковое вхождение из пользовательского файла .ini. GetPrivateProfilelnt Читает числовое вхождение из пользовательского файла .ini. WritePrivateProfileString Записывает вхождение в пользовательский файл .ini. GetProfileString Читает строковое вхождение из Win.ini. GetProfilelnt Читает числовое вхождение из Win.ini. Информацию относительно работы с DLL см. в главе 5. 12.2.3. Аспектыоптимизации Процесс оптимизации начинается с началом разработки приложения. Плохо спроектиро¬ ванное приложение работает медленно, независимо от того, сколько усилий впоследствии потратит разработчик, чтобы поднять производительность. Оптимизация — сумма компромиссов. Улучшение одного аспекта производительности мо¬ жет обусловить снижение эффективности в другом. Например, если хранить формы загру¬ женными, но скрытыми, они будут выводиться быстро, но в загруженном состоянии они потребляют много памяти. Если на компьютере пользователя память в дефиците, приложе¬ ние может работать медленно. Поэтому необходимо определить факторы, наиболее важ¬ ные для пользователя, и соответственно построить разработку. Оптимизация фактического быстродействия Ниже приводятся некоторые рекомендации по оптимизации реального быстродействия приложения: • некоторые типы данных при выполнении вычислений работают быстрее, чем другие. Рекомендуется использовать самый простой возможный тип данного;
Гпава 12. Создание программы Setup и оптимизация приложения 291 • доступ к переменной выполняется быстрее, чем доступ к свойству. При обращении к свойству в цикле вначале следует ассоциировать свойство с переменной и затем в цикле использовать переменную; • доступ к объектам ускоряется с использованием коллекций объектов; • в большинстве случаев производительность повышается при использовании DLL. Оптимизация воспринимаемого быстродействия Воспринимаемое быстродействие — субъективное восприятие быстродействия (как быстро приложение выполняется с точки зрения конечного пользователя). Эта характеристика часто связана с быстродействием отображения, но не всегда с реальным быстродействием. Для улучшения восприятия приложения можно использовать такие способы: • применять индикаторы прогресса, давая пользователю информацию относительно ста¬ туса задачи; • использование асинхронной обработки. Для фонового выполнения длительной процеду¬ ры можно использовать таймер. Пользователь в это время может продолжать работать. По завершении фонового процесса можно активировать команду индикации завершения; • хранение форм скрытыми, но загруженными. Очевидный отрицательный момент в этой методике — объем памяти, потребляемый загруженными формами. Однако, если на первом месте стоят требования к скорости вывода форм, стоимостью памяти приходится пренебрегать. Оптимизация быстродействия экранного вывода Учитывая графический характер Microsoft Windows, операции экранного отображения ока¬ зывают определяющее воздействие на общее восприятие эффективности приложения. Для ускорения графического вывода в приложении имеется несколько способов: • правильное использование свойства AutoRedraw формы. Если приложение генерирует сложную и часто изменяемую графику, улучшить производительность можно, установив AutoRedraw в False и перейдя на "ручное управление" процессом регенерации графики; • использование элемента управления lmage вместо PictureBox. Элемент управления lmage требует меньшего количества ресурсов, чем PictureBox. Если требуется только выводить на экран изображение и отвечать на событие Click, то эти операции вполне может обеспечить элемент управления lmage; • использование элемента управления PictureBox для имитации сложного набора элемен¬ тов управления вместо использования реальных элементов управления; • при частом использовании формы — скрывать ее, вместо выгрузки. Скрытые формы выводятся быстрее, чем выгруженные. Уменьшение расхода памяти Как правило, для приложений существует взаимосвязь: требования к доступной памяти — доступная память — быстродействие приложения. Для снижения уровня требований и фактического расхода памяти компьютера существует ряд способов, в частности: • если данные длинной строки более не требуются, установить в коде приложения для строки значение "", чтобы вернуть память, используемую строкой. Если более не требу¬ ются данные динамического массива, используя операторы Erase или ReDim Preserve, удалить ненужные данные и вернуть системе память, используемую массивом. Erase реинициализирует массив нулями; ReDim Preserve может использоваться для уменьше¬ ния размера массива; • если изображение, выводимое в объекте PictureBox, более не требуется, функцией LoadPicture с пустым строковым параметром можно очистить объект.
292 Оптимизация приложения 12.2.4. Протокол событий Возможность записывать ключевую информацию в журнал событий — новая функция, введенная в Microsoft Visual Basic версии 5.0. Методы и свойства, связанные с протоколи¬ рованием событий, — часть объекта App (приложение), который является глобальным объектом, доступным через ключевое слово App. Объект App определяет информацию относительно многих аспектов приложения, включая информацию версии. Для управления регистрацией событий используются методы StartLogging и LogEvent и свойство LogMode. Режим журнала и адресат регистрации операции устанавливаются методом StartLogging. Синтаксис метода следующий: App.StartLogging адресат, режим Адресат — путь и имя файла для сбора информации метода LogEvent. Режим — значение, определяющее порядок реализации протоколирования (методом LogEvent). Установки для параметра режим перечислены в следующей таблице: Режим Описание vbLogAuto Определяет, куда будут направляться сообщения. При работе в Windows 95 сообщения будут направляться в расположение, специфи¬ цированное свойством LogFile. При работе в Windows NT сообщения будут регистрироваться в журнале событий приложения NT. VbLogOff Выключает протоколирование. VbLogToFile Направляет протоколирование в файл. VbLogToNT Направляет протоколирование в журнал событий NT. VbLogOverwrite Определяет, что файл журнала должен перезаписываться при каждом запуске приложения. Это значение может управляться программным способом с помощью других констант режим. VbLogThreadlD Указывает, что в начало сообщения будетдобавлен текущий идентифи¬ катор процесса. Это значение может управляться программным спосо¬ бом с помощью других констант режим. Метод LogEvent используется для записи события в адресат журнала приложения. На платформах Windows NT метод записывает сообщения в журнал событий NT. На платфор¬ мах Windows 95 метод записывает в файл, специфицированный в методе StartLogging. Если файл не специфицирован, события записываются в файл VBEvents.log. Синтаксис метода LogEventcneflytOLun^ App.LogEvent (буфер_журнала, тип_события) Параметр буфер_журнала — текст, который должен быть записан в журнал. Параметр тип_события определяет тип или серьезность записываемых данных: ошибка, предупреж¬ дение или информационные данные. Свойство LogMode — только для чтения и возвращает значение, определяющее, как будет выполняться протоколирование (методом LogEvent). Синтаксис свойства LogMode следующий: режим = App.LogMode Свойство LogPath — только для чтения и возвращает путь к текущему файлу журнала. Синтаксис свойства LogPath следующий: файл = App.LogPath
Гпава 12. Создание программы Setup и оптимизация приложения 293 В следующем фрагменте кода показано, как регистрировать события в Visual Basic: Select Case Index Case 0 ' Начало регистрации Dim logMode As Long ' Вычислить значение logMode logMode = cboLogMode.ListIndex + &H10 * chkLogOverwrite.Value + &H10 * chkLogThreadID.Value ' Установить параметры протоколирования App.StartLogging txtLogTarget, logMode cmdAction(l).Enabled = True cmdAction(l).Default = True Case 1 ' Записать сообщение App.LogEvent txtLogText, cboEventType.ItemData(cboEventType.ListIndex) End Select 12.2.5. Повышение производительности разработки Microsoft Visual Basic предлагает два инструментальных средства, которые могут значи¬ тельно повысить производительность разработки: • Visual SourceSafe (в редакции Enterprise) позволяет управлять изменениями в файлах исходного текста; • если известно, что приложение будет локализоваться или изменяться для других целей, в качестве хранилищ данных (например, текстовых материалов) можно использовать файлы ресурсов. 12.2.6. Использование MicrosoftVisual SourceSafe Microsoft Visual SourceSafe — проектно-ориентированная система управления версиями для коллективной разработки программного обеспечения. Как библиотека, Visual SourceSa¬ fe позволяет пользователям осуществлять контроль над файлами больших проектов, заре¬ гистрированными в общем хранилище. Эта система прослеживает и хранит изменения в файлах таким образом, чтобы разработчики могли получить обзор хронологии развития файла и, в случае необходимости, вернуться к более ранним версиям файла. 12.2.7. YcTaHOBKaVisual SourceSafe Чтобы можно было использовать Visual SourceSafe с Visual Basic, необходимо сначала установить файлы поддержки и базу данных управления исходным текстом на сервере, доступном для всех пользователей. Программа Visual Basic Setup обеспечивает опцию установки сервера SourceSafe. После установки сервера Visual SourceSafe и Visual Basic на каждой системе, которая будет использовать Visual SourceSafe, необходимо установить программное обеспечение клиента SourceSafe. Для установки программного обеспечения клиента нужно выбрать SccAddin.SourceCode- ControlAddin в меню Add-Ins. Надстройка SourceSafe добавляет меню SourceSafe в меню Add-Ins и активирует команды Get, Check Out и Check ln в меню Tools в среде Visual Basic. 12.2.8. Добавление проекта KVisual SourceSafe Чтобы добавить проект к Visual SourceSafe, нужно выбрать команду Add Project to Source¬ Safe в меню SourceSafe. Файлы будут скопированы в проект SourceSafe.
294 Оптимизация приложения Изменение файла Для модификации файла, который был добавлен к проекту, его сначала необходимо скопи¬ ровать на локальную систему. Для этого нужно выбрать Check Out в менюТоо1з. SourceSafe копирует последнюю версию файла на компьютер разработчика. По окончании внесения изменений нужно выбрать команду Check ln, чтобы копировать файл обратно на сервер и удалить локальную версию. 12.2.9. Использование файлов ресурсов Если планируется распространять приложение на международном рынке, имеется возмож¬ ность уменьшить объем времени, требуемый для локализации приложения. Вместо исполь¬ зования литеральных данных в программном коде такую информацию, как строки и растровые рисунки, можно хранить в файле ресурсов. Для загрузки данных в период выпол¬ нения в приложении могут использоваться специальные функции. Таким образом, можно легко изменить данные в файле ресурсов без изменения фактического программного кода. Примечание: В папке Visual Basic \Samples\PguideWm\ имеется примерное приложение Atm.vbp, в котором используются файлы ресурсов. Создание файлов ресурсов Чтобы создать файл ресурсов: 1. Создать файл определения ресурса (* .rc), который содержит все строковые ресурсы приложения. Самый простой способ создания файла определения ресурса — использо¬ вать редактор ресурса, например поставляемый с MicrosoftVisual C++. 2. Используя компилятор ресурса, преобразовать файл определения ресурса в файл ре¬ сурса (* .res). Для этого можно использовать компилятор ресурса (Rc.exe), который поставляется с Visual Basic редакций Professional и Enterprise. Чтобы подключить файл ресурса к проекту: 1. В меню Project выбрать Add File. 2. В окне диалога Add File в окне Files oftype выбрать Resource Files (*.RES). 3. Выбрать файл ресурсов, который требуется добавить к проекту, и нажать Open. Использование функций для работы с ресурсами Visual Basic предоставляет несколько функций, которые позволяют загрузить информацию из файла ресурсов в период выполнения. Эти функции перечислены в следующей таблице: Функция Назначение LoadResString Загружает строку. LoadResPicture Загружает изображение. Второй параметр LoadResPicture определяет тип загружа- емыхданных (0=bitmap, 1=icon, 2=cursor). LoadResData Загружает общие данные (байтовый массив), такие, например, как файл .wav. Например, в следующем примере в событии Form_Load загружается строка ресурса 100 и присваивается свойству Caption элемента управления Label. Далее загружается ресурс-изобра- жение 100 (формат графики icon) и присваивается свойству Picture элемента управления lmage. Private Sub Form Load() Labell.Caption = LoadResString(10 0) Imagel.Picture = LoadResPicture(100, 1) End Sub
Содержание 295 Содержание Предисловие 3 ГЛАВА 1. ВВЕДЕНИЕ В VISUAL BASIC 4 1.1. Событийно-управляемое программирование 4 1.2. Редакции Visual Basic 5 5 1.3. Создание приложений в Visual Basic 5 1.3.1. Разработка интерфейса пользователя 5 1.3.2. Использование панели элементов 5 1.3.3. Работа со свойствами 9 1.3.4. Работа с меню 10 1.4. Написание программного кода 11 1.4.1. Создание процедур 12 1.4.2. Область определения программного кода 13 1.4.3. Переменные, константы и типы данных 15 1.4.4. Использование типов данных 15 1.4.5. Область определения переменных 20 1.4.6. Период существования переменных 20 1.5. Обработка вводимой информации и управление ошибками 21 1.5.1. Средства отладки приложения 21 1.5.2. Обработка данных поля 23 1.5.3. Управление интерфейсом и информацией формы 24 1.5.4. Отключение обработки ошибок 27 1.6. Компиляция приложения и построение ЕХЕ-файла 28 1.6.1. Компиляция во внутренний код 29 ГЛАВА 2. РАБОТА С ДАННЫМИ ЧЕРЕЗ ЭЛЕМЕНТ УПРАВЛЕНИЯ DATA 32 2.1. Способы доступа кданным BVisual Basic 32 2.1.1. Использование ядра базы данных MicrosoftJet 32 2.1.2. Другие методы доступа к данным 32 2.2. Основы организации данных 33 2.2.1. Элементы таблицы 33 2.3. Работа с элементом управления Data 34 2.3.1. Доступ к данным с помощью элемента управления Data 35 2.3.2. Некоторые свойства и методы элемента управления Data 36 2.3.3. Объект Recordset 37 2.3.4. Свойства и методы объекта Recordset 38 2.3.5. Мастер Data Form Wizard 39 2.3.6. Пример использования мастера Data Form Wizard 39 2.4. События элемента управления Data 41 2.4.1. Событие Validate 41 2.4.2. Событие Reposition 42 2.4.3. Событие Error 43 2.5. Использование связанных элементов управления ActiveX 43 2.5.1. Элемент управления DBGrid 43 2.5.2. Элемент управления MSFIexGrid 45 2.5.3. Элемент управления DBCombo 46
296 Содержание ГЛАВА 3. РАБОТА С ДАННЫМИ ЧЕРЕЗ ИНТЕРФЕЙС DAO 48 3.1. Обзор DAO 48 3.1.1. Объекты DBEngine и Workspace 49 3.1.2. Открытие и закрытие базы данных 50 3.2. Работа с наборами записей 51 3.2.1. Объявление объекта Recordset 51 3.2.2. Типы объектов Recordset 52 3.2.3. Вывод записей в форме 53 3.2.4. Навигационные свойства 54 3.2.5. Пример создания и перемещения по набору записей 55 3.3. Работа с данными 57 3.3.1. Изменение записей 57 3.3.2. Добавление записей 58 3.3.3. Удаление записей 58 3.4. Совместное использование DAO и элемента управления Data 59 3.5. Поиск записей 59 3.5.1. Поиск записей в наборах типа dynaset или snapshot 59 3.5.2. Поиск в наборах типа table 60 3.5.3. Пример поиска записей в наборе 61 3.6. Использование запросов и операторов SQL 61 3.6.1. Запрос на выборку 61 3.6.2. Запросы действия 62 3.6.3. Компоненты языка SQL 62 3.6.4. Использование операторов SQL в коде Visual Basic 64 3.6.5. Пример использования запросов SQL 65 3.6.6. Пример использования параметрических запросов 66 ГЛАВА 4. РАСШИРЕННЫЕ ВОЗМОЖНОСТИ ПРОГРАММИРОВАНИЯ ДОСТУПА К ДАННЫМ 68 4.1. Поддержание целостности данных 68 4.1.1. Определение правил для обрабатываемой информации 68 4.1.2. Ссылочная целостность 70 4.1.3. Транзакции 71 4.2. Вопросы многопользовательского доступа 72 4.2.1. Открытие таблицы в исключительном режиме 73 4.2.2. Блокировка ядра базы данных Microsoft Jet 73 4.2.3. Обработка ошибок блокировки 74 4.3. Работа с внешними данными 76 4.3.1. Способы доступа к данным 76 4.3.2. Работа с базами данных ISAM 78 4.3.3. Работа с файлами данных 79 4.4. Работа с базами данных ODBC 79 4.4.1. Определение рабочей области ODBCDirect 80 4.4.2. Соединение с удаленным источником данных 80 4.4.3. Отбор удаленных данных 81 4.5. Вопросы производительности 82 ГЛАВА 5. СОЗДАНИЕ ОТЧЕТОВ С ПОМОЩЬЮ CRYSTAL REPORTS 84 5.1. Конфигурирование Crystal Reports 84 5.1.1. Специфицирование умолчательного каталога данных 85 5.1.2. Специфицирование типов баз данных, представленных в окне диалога Choose Database File 86 5.1.3. Специфицирование умолчательного представления, используемого при предварительном просмотре отчета 86
Содержание 297 5.1.4. Специфицирование умолчательных шрифтов для разделов отчета 87 5.1.5. Специфицирование сервера SQL/ODBC как основного источника данных 87 5.1.6. Специфицирование шаблона отчета как основного источника данных 88 5.1.7. Специфицирование умолчательных установок форматирования полей 89 5.2. Построение отчетов 89 5.2.1. Выбор типа отчета 90 5.2.2. Выбор источника данных 91 5.2.3. Связывание таблиц базы данных 91 5.2.4. Режим Design 92 5.2.5. Выбор полей для отображения в отчете 93 5.2.6. Перемещение, изменение размера, форматирование и удаление полей 94 5.2.7. Сортировка данных отчета 94 5.2.8. Группирование данных отчета 96 5.2.9. Получение итогов и промежуточных сумм 97 5.2.10. Выбор записей 99 5.2.11. Добавление графика/диаграммы 101 5.2.12. Объекты OLE 103 5.2.13. Добавление заголовка отчета 103 5.2.14. Предварительный просмотр отчета 103 5.3. Работа с формулами 103 5.3.1. Приемы работы с формулами 105 5.3.2. Значение поля группы 105 5.3.3. Комментарии формул 105 5.3.4. Синтаксис формул 106 5.3.5. Порядок вычислений в формулах 107 5.3.6. Удаление формул из отчета 108 5.3.7. Копирование формул из оперативной справки 108 5.3.8. Функции 109 5.3.9. Операции 109 5.3.10. Переменные 109 5.4. Элемент управления Crystal 110 5.4.1. Подготовка к использованию элемента управления Crystal 110 5.4.2. Проектирование пользовательского интерфейса 110 5.4.3. Подключение элемента управления Crystal к проекту 111 5.4.4. Применение элемента управления Crystal 111 5.5. Свойства элемента управления Crystal 113 5.6. Методы элемента управления Crystal 140 ГЛАВА 6. РАБОТА С БИБЛИОТЕКАМИ ДИНАМИЧЕСКОЙ КОМПОНОВКИ 141 6.1. Обзор DLL 141 6.1.1. Преимущества использования DLL 141 6.1.2. Библиотеки Windows API 141 6.1.3. Использование API Viewer 142 6.1.4. Загрузка объявления из базы данных 142 6.1.5. Использование DLL cVisual Basic 143 6.2. Объявление процедуры DLL 143 6.2.1. Преобразование объявлений С в типы данных Visual Basic 144 6.2.2. Гибкие типы параметров 144 6.2.3. Библиотеки ANSI и Unicode 144 6.3. Вызов DLL 145 6.3.1. Передача нулевых значений 145 6.3.2. Передача параметров по значению и по ссылке 146 6.3.3. Передача строковых значений 146
298 Содержание 6.4. Дополнительная информация по DLL 147 6.4.1. Процедуры обратного вызова 147 6.4.2. Использование процедур-оболочек 149 6.4.3. Полезные DLL 150 6.4.4. Пример: Нахождение расположения папки Windows 151 6.4.5. Пример: Создание окна "Поверх остальных" 151 ГЛАВА 7. СОМ И СОЗДАНИЕ КЛИЕНТОВ ACTIVEX 153 7.1. Компонентная Объектная Модель 153 7.1.1. Краткая история СОМ 154 7.1.2. Компонентные приложения 154 7.1.3. Облегчение настройки приложения 155 7.1.4. Библиотеки компонентов 156 7.1.5. Распределенные компоненты 156 7.1.6. Требования к компонентам 157 7.1.7. Динамическая компоновка 157 7.1.8. Инкапсуляция 157 7.1.9. Спецификация СОМ 159 7.1.10. Использование интерфейсов 159 7.1.11. Взаимодействие клиента с сервером 161 7.2. Реализация Автоматики 162 7.2.1. Объекты Автоматики 162 7.2.2. Библиотеки типов 162 7.2.3. Объектные модели 163 7.2.4. Интерфейс IDispatch 164 7.2.5. Двойные интерфейсы 165 7.2.6. Введение в связывание 166 7.3. Характеристики компонентов сервера 167 7.3.1. Установка свойства Instancing 167 7.3.2. Определение расположения компонентов сервера 168 7.3.3. Уведомление клиентов 169 7.4. Создание клиента в Visual Basic 170 7.4.1. Первый шаг: установление ссылок 170 7.4.2. Второй шаг: объявление объектных переменных 171 7.4.3. Третий шаг: создание объектов 172 7.4.4. Четвертый шаг: использование объектов Автоматики 174 7.5. Прием сообщений от серверов 175 7.5.1. Сообщения сервера с использованием событий 175 7.5.2. Сообщения сервера, использующие обратные вызовы 176 7.5.3. События или обратные вызовы? 177 7.6. Создание приложения-клиента, использующего Microsoft Excel 179 7.6.1. Объектная модель Microsoft Excel 179 7.6.2. Создание экземпляра Microsoft Excel 180 7.6.3. Использование методов Microsoft Excel 181 7.6.4. Получение и установка значений 181 7.6.5. Использование семейства Charts 182 7.6.6. Запуск процедур Microsoft Excel 184 7.6.7. Пример: Управление Microsoft Excel 185 ГЛАВА 8. СОЗДАНИЕ ПРОГРАММНЫХ КОМПОНЕНТОВ ACTIVEX 188 8.1. Обзор компонентов ActiveX 188 8.1.1. Элементы управленияАсйуеХ 188 8.1.2. Документы ActiveX 188 8.1.3. Программные компоненты ActiveX 188
Содержание 299 8.1.4. Преимущества использования компонентов ActiveX 189 8.2. Создание объектов в Visual Basic 189 8.2.1. Модули классов 189 8.2.2. Создание экземпляра класса 190 8.2.3. События модуля класса 190 8.2.4. Создание методов 191 8.2.5. Создание свойств 192 8.2.6. Использование процедур РгореИудпя создания свойств 193 8.2.7. Использование Class Builder 195 8.3. Работа с программными компонентами ActiveX 195 8.3.1. Выбор типа программного компонента 195 8.3.2. Установка свойств проекта 196 8.3.3. Установка свойств модуля класса 198 8.3.4. Компиляция компонента 199 8.3.5. Регистрация компонента 200 8.4. Тестирование программных компонентов ActiveX 200 8.4.1. Установка испытательного проекта 200 8.4.2. Установка ссылки на библиотеку типов 201 8.4.3. Отладка компонента 201 8.4.4. Способы обработки ошибок 202 8.4.5. Инициирование ошибок выполнения 202 8.5. Использование событий 204 8.5.1. Создание событий класса 204 8.5.2. Обработка событий в приложении-клиенте 205 8.5.3. Выполнение с помощью событий асинхронных вызовов 206 8.6. Реализация интерфейса 208 8.6.1. Использование интерфейсов 209 8.7. Прочие аспекты программных компонентов 211 8.7.1. Использование именованных констант 211 8.7.2. Информация о компоненте и Help 211 8.7.3. Глобальность данных 212 8.7.4. Объявление методов Friend 212 8.7.5. Создание объектной модели 214 8.7.6. Хранение объектов в семействах 214 8.7.7. Совместимость версий 214 8.7.8. Управление занятым компонентом 216 8.8. Пример: Создание программного компонента 216 8.8.1. Создание программного компонента 216 8.8.2. Создание свойств и методов 217 8.8.3. Создание приложения-клиента 218 8.9. Пример: Определение и использование событий 218 8.9.1. Определение и использование события Status 219 ГЛАВА 9. СОЗДАНИЕ ЭЛЕМЕНТОВ УПРАВЛЕНИЯ ACTIVEX 221 9.1. Введение в элементы управления ActiveX 221 9.1.1. Классы элементов управления 221 9.1.2. Элементы управления — компоненты 221 9.1.3. Элементы управления ActiveX и программные компоненты 221 9.1.4. Объект UserControl 222 9.1.5. Тиражирование элементов управления ActiveX 223 9.1.6. Шаги создания элемента управления ActiveX 224 9.2. Создание пользовательского интерфейса элемента управления 224 9.2.1. Добавление составляющих элементов управления 224
300 Содержание 9.2.2. Настройка размера элемента управления 225 9.2.3. Настройка пользовательского интерфейса 225 9.2.4. Создание элемента управления — контейнера 225 9.2.5. Добавление окна About 226 9.2.6. Специфицирование пиктограммы для панели элементов 226 9.3. Тестирование элемента управления 228 9.3.1. Создание испытательного проекта 228 9.3.2. Отладка элемента управления и обработка ошибок 228 9.3.3. Экземпляры и события элементов управления 229 9.4. Предоставление свойств, методов и событий 229 9.4.1. Построение свойств 230 9.4.2. Добавление методов 231 9.4.3. Использование общих свойств контейнера 232 9.4.4. Хранение и получение значений свойств 233 9.4.5. Использование именованных констант 234 9.4.6. Инициирование событий элемента управления 234 9.4.7. Использование мастера ActiveX Control Interface Wizard 235 9.5. Создание страниц свойств 238 9.5.1. Создание интерфейса страниц свойств 238 9.5.2. Программирование поведения страниц свойств 238 9.5.3. Установление отношений страниц свойств 240 9.5.4. Использование стандартных страниц свойств 241 9.6. Тиражирование элемента управления 241 9.6.1. Лицензирование элементов управления 241 9.6.2. Создание программы установки элемента управления 242 ГЛАВА 10. СОЗДАНИЕ И ИСПОЛЬЗОВАНИЕ ДОКУМЕНТОВ ACTIVEX 244 10.1. Документы ActiveX 244 10.1.1. Контейнеры документов ActiveX 244 10.1.2. Документы ActiveX и внедренные объекты 245 10.1.3. Преимущества документов ActiveX 245 10.1.4. Internet Explorer и Office Binder 246 10.1.5. Документы ActiveX в Visual Basic 248 10.2. Работа с проектами документов ActiveX 249 10.2.1. Элементы проекта документа ActiveX 249 10.2.2. Создание проекта документа ActiveX 250 10.2.3. Компиляция проекта документа ActiveX 251 10.2.4. Размещение документа ActiveX в контейнере 251 10.2.5. События пользовательскогодокумента 251 10.2.6. Различия между контейнерами документов 252 10.2.7. Определение типа контейнера документа 252 10.3. Тестирование и отладка документов ActiveX 253 10.3.1. Запускпроекта BVisual Basic 253 10.3.2. Тестирование документа ActiveX в контейнере 253 10.3.3. Определение среды периода выполнения 254 10.4. Многодокументные проекты 254 10.4.1. Определение навигационных требований кдокументу 254 10.4.2. Использование глобальныхссылок 255 10.4.3. Создание свойств 256 10.5. Пользовательский интерфейс и пользовательский документ 259 10.5.1. Установка свойств пользовательского документа 259 10.5.2. Добавление меню к пользовательскому документу 259
Содержание 301 ГЛАВА 11. СОЗДАНИЕ ПРИЛОЖЕНИЙ ДЛЯ INTERNET 262 11.1. Использование гнезд 262 11.1.1. Функции гнезд 262 11.1.2. Применения гнезд 262 11.1.3. Элемент управления Winsock 263 11.1.4. Базовые операции с элементом управления Winsock 264 11.1.5. Программирование сервера Winsock 265 11.1.6. Программирование клиента Winsock 266 11.1.7. Прием и передача данных 266 11.2. Установление соединений FTP и HTTP в Internet 267 11.2.1. Элемент управления Internet Transfer 267 11.2.2. Базовые операции с элементом управления Internet Transfer 267 11.2.3. Программирование асинхронных операций 269 11.2.4. Программирование синхронных операций 272 11.2.5. Использование элемента управления WebBrowser 272 11.2.6. Применение элемента управления WebBrowser 273 11.2.7. Основные операции с WebBrowser 273 11.2.8. Программирование навигации в WebBrowser 273 11.3. Использование Автоматики с Internet Explorer 275 11.3.1. Объект lnternetExplorer 275 11.4. Работа с Personal Web-Server 276 11.4.1. Конфигурирование Personal Web-Server 277 11.4.2. Запуск Personal Web-Server 280 11.5. Пример: Создание приложения для работы в Internet 280 11.5.1. Формирование с использованием WebBrowser приложения — средства просмотра 280 11.5.2. Программирование приложения 282 ГЛАВА 12. СОЗДАНИЕ ПРОГРАММЫ SETUP И ОПТИМИЗАЦИЯ ПРИЛОЖЕНИЯ 285 12.1. Создание программы установки 285 12.1.1. Использование мастера Setup Wizard 285 12.1.2. Файлы установки 286 12.1.3. Использование пакета Visual Basic Setup Toolkit 287 12.1.4. Удаление приложения 288 12.2. Оптимизация приложения 288 12.2.1. Visual Basic Code Profiler 289 12.2.2. Сохранение установок приложения 289 12.2.3. Аспекты оптимизации 290 12.2.4. Протокол событий 292 12.2.5. Повышение производительности разработки 293 12.2.6. Использование MicrosoftVisual SourceSafe 293 12.2.7. Установка Visual SourceSafe 293 12.2.8. Добавление проекта к Visual SourceSafe 293 12.2.9. Использование файлов ресурсов 294