Книги в продаже (аннотация + содержание + отрывок)

П. Литвин, К. Гетц, М. Гунделой
РАЗРАБОТКА НАСТОЛЬНЫХ ПРИЛОЖЕНИЙ В ACCESS 2002. ДЛЯ ПРОФЕССИОНАЛОВ (+CD).
Цена: 448 р.

Источник: Издательский дом 'ПИТЕР'
Разделы: Разное (общие вопросы использования ПК, компьютерная архитектура, пользовательский интерфейс, компьютерные системы и информационные ситемы)
Подробнее: Информация от издателя (открывается в новом окне)
Заказ: Оформление покупки (открывается в новом окне)
      В книге представлено большое количество полезной информации, необходимой каждому разработчику приложений в среде Microsoft Access, Visual Basic и Microsoft SQL Server. В ней рассматриваются: объектная модель Microsoft Access, особенности создания модулей класса, проектирование форм и отчетов. Большое внимание уделено принципам и приемам проектирования приложений для баз данных и интегрированных решений на базе Microsoft Office XP, а также средствам отладки и оптимизации приложений. К книге прилагается компакт-диск с исходными текстами всех примеров и демонстрационные базы данных, а также множество процедур и модулей классов, которые можно использовать в собственных приложениях. Книга будет полезна как начинающим, так и профессиональным разработчикам настольных бизнес-приложений для индивидуальных пользователей и небольших рабочих групп.
     
     
     
      Содержание
      Благодарности
      Об авторах
      Предисловие
      Введение
      Глава 1. Новые возможности Access 2002
      Краткая история Access
      Access 2002
      Средства программирования
      Формы и отчеты
      Доступ к данным
      Работа в сетях Интернет и корпоротивных сетях
      Другие усовершенствования
      Особенности Microsoft Office Developer
      Резюме
      Глава 2. Модель событий в Access
      Событий так много, а времени так мало...
      Использование событий
      События формы
      Отменяемые события
      Последовательность событий
      Регистрация событий
      Работа программы регистрации событий
      Операции с формой
      События клавиатуры
      Назначение свойства KeyPreview
      Отмена нажатия клавиш
      Использование параметров KeyCode и Shift
      Сравнение событий KeyDown и KeyUp
      Повторяющиеся события клавиатуры
      События мыши
      Двойной щелчок мышью
      События, связанные с данными
      События обработки ошибок
      Обязательное событие по таймеру
      Неблокируемые события
      Резюме
      Глава 3. Использование модулей класса VBA
      Зачем нужны модули класса
      Создание собственных объектов
      Описание сложных процессов с помощью классов
      Классы упрощают разработку
      Как работают модули класса
      Модули класса - это форма для приготовления печенья
      Экземпляры объектов - это само печенье
      Простой пример: класс "текстовый файл"
      Создание класса
      Использование класса объектов
      Применение процедур Property
      Получение значений свойств с помощью процедуры Property Get
      Установка значений свойств с помощью процедуры Property Let
      Присваивание свойствам значений с помощью процедуры Property Set
      Пример простой базы данных
      Дополнительные сведения о работе с модулями класса
      Перечисляемые типы
      Иерархия объектов
      Создание свойства Parent
      Коллекции объектов
      Создание собственных коллекций
      Определение и применение пользовательских событий
      Резюме
      Глава 4. SQL Access
      Где можно использовать SQL
      SQL Access: основные сведения
      Инструкция SELECT
      Предложение SELECT
      Предложение FROM
      Предложение WHERE
      Предложение ORDER BY
      Объединение таблиц
      Предикаты ALL, DISTINCTROW и DISTINCT
      Предикат TOP
      Объявление WITH OWNERACCESS OPTION
      Агрегатирование данных
      Итоговые запросы, не использующие предложение GROUP BY
      Использование предложения GROUP BY
      Использование предложения HAVING
      Создание перекрестных запросов при помощи инструкции TRANSFORM
      Запросы на объединение
      Использование опции TABLE
      Опция ALL
      Сортировка результатов
      Совместимость запросов
      Подчиненные запросы
      Проверка значений с помощью таблицы просмотра
      Сравнение значений
      Проверка наличия строк
      Использование подчиненных запросов в предложении SELECT
      Пример: использование подчиненного запроса для нахождения повторяющихся строк
      Передача параметров в SQL
      Использование внешних источников данных
      Применение связанных таблиц
      Применение предложения IN
      Применение прямых ссылок на таблицы
      Обновление данных при помощи SQL
      Инструкция UPDATE
      Инструкция DELETE
      Инструкция INSERT INTO
      Инструкция SELECT INTO
      Определение данных при помощи SQL
      Инструкция CREATE TABLE
      Предложение CONSTRAINT
      Инструкция CREATE INDEX
      Инструкция ALTER TABLE
      Инструкция DROP
      Создание SQL-запросов к серверу
      Расширения Jet 4 ANSI SQL-92
      Установка режима запросов ANSI SQL-92
      Дополнительные операции над таблицами в Jet 4.0
      Поддержка Jet 4 представлений и хранимых процедур
      Обработка транзакций в Jet 4
      Защита данных в Jet 4
      Различия между SQL Access, SQL-92, Jet SQL-92 и T-SQL
      Резюме
      Глава 5. Объекты данных ADO
      ADO? А как же DAO?
      Создание ссылок
      Выбор библиотеки
      Исследование иерархий объектов
      ADO, UDA и OLE DB
      Правила синтаксиса
      Свойства и методы
      Использование объектных переменных
      Объект Connection
      Ссылки на объекты
      Что использовать: восклицательный знак, точку или кавычки?
      Положение объекта в коллекции
      Коллекции, используемые по умолчанию
      Перебор объектов в коллекции
      Свойства объектов
      Типы свойств
      Перебор свойств
      Определение данных с помощью объектов ADOX
      Создание объектов
      Наборы записей
      Знакомство с курсорами
      Создание наборов записей
      Непосредственный доступ к таблицам
      Согласованное и несогласованное обновление данных
      Место расположения курсора
      Взаимное влияние свойств объекта Recordset
      Метод Supports
      Способы создания объектов Recordset
      Перемещение по набору записей
      Определение числа строк в наборе записей
      Определение границ набора записей
      Проверка наличия записей в наборе
      Просмотр всех записей
      Использование массивов для хранения данных набора записей
      Создание объекта Recordset с помощью объекта Command
      Поиск конкретных записей
      Использование закладок
      Метод Clone
      Сортировка наборов записей
      Фильтрация записей
      Обновление наборов записей
      Редактирование данных в наборах записей
      Постоянные наборы записей
      Использование наборов записей вместо массивов
      Использование объекта Command для выполнения групповых операций
      Наборы записей схем
      Использование коллекций, входящих в объекты CurrentProject и CurrentData
      Пример использования коллекций
      Проектирование формы frmDBC
      Выбор операции и типа объекта
      Отображение списка объектов
      Заполнение списка объектов
      Получение информации об опциях, выбранных пользователем в окне Options
      Формирование списка объектов
      Включать ли объект в список
      Добавление объекта в список
      И наконец...
      Использование формы frmDBC в приложении
      Резюме
      Глава 6. Элементы управления
      Элементы управления и их использование
      Код, связанный с формами: модули классов
      Группировка элементов управления
      Свойства стандартных элементов управления
      Применение свойства Tag для создания пользовательских свойств
      Свойство ControlType
      Свойства ControlTipText и ShortCutMenuBar
      Свойства TabStop и TabIndex
      Свойство DisplayWhen
      События Dirty и Undo
      Управление выводом текста
      Применение надписей
      Свойство Parent
      Текстовые поля
      Перенос значений полей в новые записи
      Свойство ControlSource и вычисляемые элементы управления
      Элементы управления с двумя состояниями
      Кнопка-выключатель
      Переключатели
      Флажки
      Группы переключателей
      Добавление элементов управления в группу переключателей
      Присвоение и извлечение значений
      Группы переключателей и возвращаемая ими информация
      Коллекция Controls элемента управления
      Списки и поля со списками
      Различия между списком и полем со списком
      Основные свойства списков и полей со списками
      Выбор нескольких элементов списка
      Особенности использования свойства LimitToList
      Событие NotInList
      Самораскрывающиеся поля со списком
      События BeforeUpdate и AfterUpdate
      Программное заполнение списка или поля со списком
      Множественный выбор в списке
      Как и когда используются подчиненные формы
      Создание подчиненной формы
      Связь родительской формы с дочерней
      Извлечение вычисляемых значений из подчиненных форм
      Вложенные подчиненные формы
      Элемент управления Command Button
      Свойства командной кнопки
      События командной кнопки
      Элемент управления Tab Control
      Что позволяют и чего не позволяют наборы вкладок
      Как работает элемент управления Tab Control
      Где я?
      Использование набора вкладок
      Модификация вкладок во время выполнения приложения
      Использование набора вкладок в качестве контейнера
      Замена многостраничных форм
      Замена прямоугольников и групп переключателей
      Настройка стандартных значений свойств элементов управления
      Использование метода DefaultControl для установки стандартных значений свойств
      Программное создание элементов управления
      Функции для создания форм и элементов управления
      Элементы управления и Windows
      Использование функции SendMessage для ограничения числа вводимых символов
      Резюме
      Глава 7. Разработка и применение форм
      Новые режимы представления формы в Access 2002
      Введение в модули класса
      Управление закрытием окон
      Существует ли данная форма
      Загружена ли данная форма
      Создание всплывающих форм
      Применение всплывающих форм
      Как работают наши формы-примеры
      Использование форм-примеров
      Создание пользовательских свойств
      Использование общедоступных переменных
      Использование процедур Property Let/Get/Set
      Использование процедур форм в качестве методов
      Фильтрация данных
      Свойство Filter
      Свойство FilterOn
      Событие Filter
      Событие ApplyFilter
      Настройка фильтра по форме
      Сортировка записей
      Работа с данными форм
      На новой записи?
      Какая запись является текущей и сколько строк в наборе записей
      Изменены ли данные формы
      Какие записи выделены
      Использование свойств Recordset и RecordsetClone
      Свойство RecordsetClone
      Проблема, связанная со свойством RecordsetClone
      Использование свойства Recordset
      Recordset или RecordsetClone?
      Условное форматирование
      Задание условий
      Задание условий форматирования в режиме конструктора
      Условное форматирование во время выполнения приложения
      Обработка ошибок на уровне формы
      Защита от нестандартных действий пользователя
      Использование свойства Cycle
      Свойство KeyPreview
      Вывод нескольких экземпляров формы
      Что происходит при создании нового экземпляра формы
      Как создать новый экземпляр формы
      Лучшее решение
      Закрытие экземпляра формы
      Закрытие всех экземпляров формы
      Использование экземпляра формы в роли диалогового окна
      Использование подчиненных форм
      Вложить одну форму в другую или просто их синхронизировать?
      Использование синхронизированных подчиненных форм
      Загружена ли форма как подчиненная
      Как связать формы самостоятельно
      Создание самоотключающихся навигационных кнопок
      Подчиненные формы и транзакции
      Дескрипторы окон, классы окон и многодокументный интерфейс
      Дескриптор окна
      Классы окон
      Многодокументный интерфейс
      Управление формами
      Демонстрация возможностей класса FormInfo
      Члены класса FormInfo
      Как это работает
      Удаление строки заголовка формы
      Сохранение и восстановление координат формы
      Что дальше?
      Автоматическое изменение размеров форм
      Понятие разрешения экрана
      Масштабирование форм при их загрузке
      Использование класса FormResize
      Управление масштабированием отдельных элементов
      Как это работает
      Программирование новых режимов представления формы
      Новые представления занимают всю форму
      Свойства и события формы, поддерживающие представления PivotChart и PivotTable
      Обработка событий представления PivotChart
      Резюме
      Глава 8. Разработка отчетов
      Сравнение отчетов и форм
      Фильтрация отчетов
      Управление сортировкой и группировкой
      Свойство Section
      Ссылки на разделы по их именам
      Работа со свойством Section
      Доступ к уровням группировки
      Свойства уровня группировки
      Свойства раздела, задаваемые в режиме конструктора
      Свойства CanGrow и CanShrink
      Свойство NewRowOrCol
      Свойство ForceNewPage
      Свойство KeepTogether
      Свойство RepeatSection
      События отчета и его разделов
      События отчета
      События раздела
      Свойства раздела, доступные только во время выполнения
      Свойства MoveLayout, NextRecord и PrintSection
      Свойство FormatCount
      Свойство PrintCount
      Свойства WillContinue и HasContinued
      Примеры использования событий и свойств отчетов и их разделов
      Печать произвольного числа наклеек
      Печать почтовых наклеек, начиная с заданной позиции
      Вставка пустых строк
      Четные и нечетные страницы
      Установка номера начальной страницы
      Нумерация различных элементов в отчете
      Несколько примеров простых отчетов
      Отчет о продажах
      Телефонная книга
      Компании, контакты и аппаратное обеспечение
      Программное изменение отчета
      Создание отчета на основе перекрестного запроса
      Получение настоящих имен полей
      Вычисление количества выводимых полей
      Настройка надписей и текстовых полей
      Наведение порядка
      Несколько заключительных рекомендаций
      Распространение отчетов Access
      Резюме
      Глава 9. Управление печатью
      Выбор выводного устройства
      Формирование списка установленных принтеров
      Изменение принтера, используемого по умолчанию
      Изменение выводного устройства
      Настройка параметров печати
      Изменение параметров страницы
      Получение информации о возможностях принтера
      Использование класса PrinterCapabilities
      Демонстрация класса PrinterCapabilities
      Как мне...
      Как просмотреть список установленных принтеров программными средствами
      Как определить, используется ли принтер по умолчанию
      Как заполнить список или поле со списком перечнем установленных принтеров
      Как заменить принтер, устанавливаемый по умолчанию
      Как заменить выводное устройство отчета
      Как изменить параметры печати формы или отчета
      Как настроить параметры страницы при печати формы или отчета
      Как определить возможности принтера
      Резюме
      Глава 10. Использование Access в качестве клиента автоматизации
      Основы технологии автоматизации
      Терминология
      Значение технологии автоматизации
      Классы объектов
      Библиотеки типов: ключ к классам
      Просмотр объектов в Object Browser
      Создание экземпляров классов
      Раннее и позднее связывание
      Простой пример раннего связывания
      Когда создавать объекты
      Функции CreateObject и GetObject
      Классы серверов автоматизации
      Управление другими приложениями
      Изучение объектной модели приложений
      Различия в поведении приложений
      Память и ресурсы
      Создание интегрированных решений на базе Microsoft Office
      Объектные модели Office
      Пример: запись отчета в Word
      Создание шаблона Word
      Формирование заказа
      Пример: фиксация времени в Outlook
      Outlook и Exchange
      Взаимодействие с Outlook
      Внесение в дневник новых записей
      Загрузка информации из дневника
      Пример: создание презентации PowerPoint
      Понятие слайда PowerPoint
      Работа с элементами слайдов PowerPoint
      Создание простейшей презентации
      Применение эффектов
      Пример: заполнение таблицы Excel
      Использование существующего файла
      Наш сценарий
      Создание объекта на основе существующего документа
      Обновление электронных таблиц и диаграмм
      Использование элементов ActiveX
      Регистрация элемента ActiveX
      Включение элемента ActiveX в приложение
      Настройка свойств элемента ActiveX
      Использование событий элементов ActiveX
      Использование связанных элементов ActiveX
      Пример использования календаря
      Использование элементов ActiveX из других продуктов
      Перехват событий с помощью переменных, объявленных с WithEvents
      Что значит WithEvents
      Использование ключевого слова WithEvents
      Перехват событий в формах
      Резюме
      Глава 11. Access как сервер автоматизации
      Использование Access в качестве сервера автоматизации
      Использование библиотеки типов Access
      Обычное программирование в Access: в чем разница?
      Как ведет себя Access в качестве сервера автоматизации
      Специальный класс для автоматизированного управления Access
      Начало сеанса автоматизации
      Загрузка базы данных или проекта
      Защищенное подключение
      Управление видимостью окна
      Определяем, загружен ли проект
      Выгрузка Access
      Создание отчета с помощью Access
      Приложение-пример
      Начало сеанса автоматизированного управления Access
      Открытие базы данных
      Получение списка отчетов
      Предварительный просмотр отчетов
      Вызов пользовательских функций из приложения-клиента автоматизации
      Глобальные функции
      Функции уровня формы
      Разработка приложений Access, поддерживающих автоматизацию
      Свойство UserControl
      Главное окно Access
      Как помешать пользователю закрыть базу данных
      Учитывайте действия программы, требующие пользовательского ввода
      Создание собственного стека ошибок
      Переключение в приложение-клиент
      Резюме
      Глава 12. Обработка ошибок и отладка кода
      Синтаксические ошибки
      Ошибки времени выполнения
      Активизация обработчика ошибок с помощью оператора On Error
      Создание интеллектуальных обработчиков ошибок
      Генерация ошибок
      Упрощенная обработка ошибок
      Иерархия обработчиков ошибок
      Свойство On Error и событие Error
      Обработка ошибок доступа к данным
      Создание процедуры, сообщающей об ошибках
      Реализация стека вызовов
      Борьба с логическими ошибками
      Методы уменьшения количества ошибок в программном коде
      Устраняйте ошибки сразу
      Использование комментариев
      Удалять или не удалять комментарии
      Организация программного кода
      Модуляризация программы
      Требование явного описания переменных
      Старайтесь избегать переменных типа Variant
      Аккуратно используйте передачу параметров по значению
      Будьте осторожны с операторами Dim
      Объединяйте операторы Dim в группы
      Используйте как можно более узкие области определения переменных
      Применение согласованных правил присвоения имен
      Ваш друг - функция MsgBox
      Средства отладки программ в Access
      Использование окна отладки
      Использование точек останова
      Методы отладки
      Систематизированная отладка
      Трудности отладки
      Восстановление состояния среды программирования после останова программы
      Использование утверждений
      Резюме
      Глава 13. Оптимизация приложений
      Оптимизация приложений Access
      Как Jet выполняет запросы
      Определение запроса
      Компиляция запроса
      Оптимизация запроса
      Выполнение запроса
      Как заставить Jet повторно откомпилировать и оптимизировать запрос
      Преимущества технологии Rushmore
      Точность статистических данных
      Настройка Jet
      Использование метода DAO SetOption
      Свойства объекта ADO Connection, предназначенные для настройки Jet
      Средства оптимизации Jet, официально не поддерживаемые Microsoft
      Опция ShowPlan
      Метод ISAMStats
      Ускорение процессов выполнения запросов и обработки наборов записей
      Повышение быстродействия форм
      Ограничение набора записей формы
      Повышение быстродействия полей со списками, содержащими большое количество строк
      Другие способы повышения быстродействия форм
      Повышение быстродействия отчетов
      Оптимизация и компиляция модулей VBA
      Как VBA загружает программный код
      Зачем нужно компилировать код
      Что сохраняется при компиляции кода
      Когда следует выполнять компиляцию
      Зачем нужна опция Compile On Demand
      Из-за чего декомпилируется код
      Как компиляция влияет на использование памяти и дискового пространства
      Удаляются ли модули из памяти
      Как оптимизировать использование модулей
      Циклические ссылки в библиотеках
      Что еще вы можете сделать
      Повышение быстродействия кода: тестирование усовершенствований
      Создание таймера
      Получение точных результатов
      Как это работает
      Советы по оптимизации кода VBA
      Резюме
      Глава 14. Доступ к DLL и Windows API
      Библиотеки динамической компоновки
      Вызов DLL-процедур из VBA
      Использование оператора Declare
      Передача аргументов функциям DLL
      Возврат строк из DLL
      Использование константы vbNullString
      Передача DLL данных пользовательского типа
      Передача массива
      Использование библиотек типов с функциями DLL
      Распространение приложений, использующих библиотеки типов
      Разработка классов-оболочек для DLL-функций
      Использование буфера обмена
      Использование класса CClipboard
      Структура оператора Declare
      Public против Private
      Задание имени процедуры
      Предложение Lib
      Предложение Alias
      Описание аргументов
      Преобразование объявлений C в объявления VBA
      Более подробные сведения о вызовах DLL-функций
      Передача параметров по ссылке и по значению
      Передача строк в DLL: как это происходит
      Что собой представляет константа vbNullString
      Unicode - ANSI - Unicode
      Использование типа данных Any
      Использование Err.LastDLLError
      Использование функций с обратным вызовом
      Выравнивание структур по границе двойных слов
      Конвертирование вызовов Windows API, написанных для 16-разрядной Windows
      Резюме
      Глава 15. Секреты мастеров
      Использование процедур
      Функции для работы с файлами
      Проверка существования файла
      Разделение полного имени файла на элементы
      Получение полного имени файла
      Использование диалоговых окон Windows
      Использование класса CommonDlg
      Использование стандартных диалоговых окон открытия и сохранения файла
      Изменение внешнего вида окна открытия или сохранения файла
      Выбор цвета
      Выбор шрифта
      Использование класса ShellBrowse
      Чтение и запись данных системного реестра
      Получение информации о разделе реестра
      Получение имени параметра
      Чтение значения из реестра
      Запись значения в реестр
      Получение имени подраздела реестра
      Создание нового подраздела
      Эмуляция функций VBA, предназначенных для работы с реестром
      Функции для управления шрифтами
      Получение списка шрифтов
      Получение списка размеров шрифта
      Получение информации о шрифтах в ваших проектах
      Использование класса ScreenInfo
      Что еще может класс ScreenInfo?
      Сколько места займет на экране текст, выведенный данным шрифтом
      Функции для работы с объектами Access
      Получение списка имен объектов
      Сортировка массива строк
      Получение списка объектов и их типов
      Сортировка массива структур adhDBObj
      Разные функции
      Определение национального языка
      Получение полной информации о файле
      Рисунки для кнопок
      Использование функции adh_accGetTBDib
      Несколько интересных замечаний
      Резюме
      Глава 16. Создание надстроек
      Библиотеки, мастера, построители
      Точки входа надстроек
      Доступ к данным и надстройки
      Надстройки и системный реестр
      Создание библиотечных баз данных
      Структурирование модулей библиотечных баз данных
      Использование библиотечной базы данных
      Ссылки на библиотечные базы данных Access
      Запрет использования циклических ссылок
      Редактирование кода загруженной библиотеки
      Запуск процедур с помощью метода Application.Run
      Использование раздела реестра LoadOnStartup для управления загрузкой библиотек
      Всегда компилируйте создаваемые библиотеки
      Надстройки меню: простейшие из надстроек
      Создание собственных построителей
      Пример построителя
      Написание функции построителя
      Записи в реестре, связанные с построителями
      Внесение в реестр записей для новых построителей
      System Color Builder
      Разработка мастеров
      Функции мастеров Access
      Общая структура мастера
      Пример мастера форм
      Способы использования таблицы состояний мастера
      Главная форма мастера
      Программный код главной формы
      Пример главной формы мастера
      Глобальные функции мастера
      Создание страниц мастера
      Завершение процесса
      Создание форм и элементов управления
      Использование таблицы Access для хранения программного кода
      Загрузка мастера
      Записи реестра о мастерах
      Шаблон мастеров - заключение
      Мастер элементов управления
      Функция мастера элементов управления
      Элементы системного реестра для мастера элементов управления
      Мастер элементов управления ActiveX
      Распространение и установка надстроек
      Использование диспетчера надстроек
      Создание таблицы USysRegInfo
      Дополнительная информация о надстройках
      Восстановление ссылок с помощью VBA
      Создание MDE-файлов
      Надстройки COM
      Надстройки COM: за и против
      Диалоговое окно надстроек COM
      Интерфейс IDTExtensibility2
      Коллекция COMAddIns
      Создание простейшей надстройки COM
      Резюме
      Предметный указатель
     
     
     
     
      ОТРЫВОК
     
     
      Глава 15
      Секреты мастеров
      Функции для работы с файлами
      Управление стандартными диалоговыми окнами Windows
      Функции для работы со шрифтами
      Чтение и запись данных реестра
      Получение списков объектов базы данных
      Классы для получения экранных установок Windows и сведений о файлах
      В предыдущих изданиях этой книги мы рассказывали о недокументированных функциях Access, которые используются в ее мастерах (wizards). В Access 2 и Access 95 эти функции хранились в отдельных библиотеках, MSAU200.DLL и MSAU7032.DLL. В Access 97 они были перенесены прямо в исполняемый файл Access, MSACCESS.EXE, и для них были определены общедоступные точки входа, подобные вызовам Windows API. В предыдущих изданиях этой книги мы их подробно описали и рассказали, как ими пользоваться.
      Однако начиная с Access 2000 ситуация изменилась. Многие из доступных ранее недокументированных функций теперь программистам не доступны, а оставшиеся, похоже, оставлены ненадолго. Поэтому данная глава уже не посвящена исключительно недокументированным функциям Access, у нее теперь несколько иные задачи.
      Мы предлагаем вам ряд написанных нами функций, заменяющих те недокументированные функции Access, которые были описаны в предыдущих изданиях этой книги (не все, но большую их часть). У наших функций те же имена, параметры и возвращаемые значения, так что с их помощью вы сможете перенести в Access 2002 программный код, написанный для Access 97 и использующий ее недокументированные вызовы. Это позволит вам не зависеть от решений команды разработчиков Access.
      Нами разработан ряд стандартных модулей и классов, позволяющих получать информацию о версиях файлов, пользоваться стандартными диалоговыми окнами Windows открытия и сохранения файлов, выбора цвета и шрифта, обзора папок, а также выполнять многие другие важные действия. (Иными словами, изменив исходный замысел этой главы, мы фактически превратили ее в рассказ о дополнительных функциональных возможностях, необходимых разработчику современного приложения.)
      Кроме того, в этой главе описываются некоторые недокументированные процедуры, которые имелись в Access 97 и по-прежнему доступны в Access 2002; при этом их нелегко написать на VBA. Нет никакой гарантии, что эти процедуры будут поддерживаться будущими версиями Access, но если сейчас их возможности вам необходимы - пока они к вашим услугам.
      Программные модули, которые мы вам предлагаем, можно разделить на семь основных категорий.
      Функции для работы с файлами: проверка существования файла; выделение компонентов имени файла; определение полного пути к файлу при наличии информации о его относительном местоположении.
      Интерфейсы для стандартных диалоговых окон: открытия и сохранения файла; выбора шрифта; выбора цвета; просмотра папок, принтеров и компьютеров.
      Процедуры для чтения и записи данных системного реестра Windows: определение количества подразделов и параметров в указанном разделе, чтение и запись параметров и создание разделов. В дополнение мы предлагаем вам замены для встроенных процедур VBA GetSetting, SaveSetting, GetAllSettings и DeleteSetting, выполняющие чтение и запись в любой части реестра.
      Функции для работы со шрифтами: получение списка доступных шрифтов и их размеров; определение высоты и ширины указанной строки, выведенной заданным шрифтом.
      Функции для извлечения сведений об объектах базы данных: получение списка имен объектов или массива объектов и их типов; сортировка массива строк; сортировка массива объектов по именам или типам.
      Процедуры для считывания информации о версии файла: язык, кодовая страница, номер версии, тип файла, операционная система, для которой предназначен файл, имя продукта и т. п.
      Процедуры для считывания информации о параметрах экрана: размеры экрана в пикселях, количество цветов, количество твипов на пиксель, доступные экранные шрифты и их размеры; а также изменение видеоустановок программным путем.
      ВНИМАНИЕ. Microsoft утверждает, что документированные функции Access не будут меняться от одной ее версии к другой. Однако к недокументированным функциям это не относится. Судьба описанных в предыдущих изданиях этой книги функций является убедительным подтверждением тому, что при использовании недокументированных технологий вы ставите крест на возможности безболезненного переноса приложения в будущие версии Access. В лучшем случае проблемы будут небольшими, но едва ли вам настолько повезет, что их не будет совсем. То, что Microsoft включила в Access 95 файл MSAU7032.DLL и определила точки входа для его функций, перенесенных в Access 97 в файл MSACCESS.EXE, не означало, что Microsoft собиралась поддерживать эти функции и дальше. Как видите, она и не стала их поддерживать. Вот поэтому почти все, что мы предлагаем вам в этой главе, основано на документированных и проверенных технологиях - мы взяли идеи старой версии этой главы в качестве отправной точки и реализовали большинство старых функций посредством Window
      s API и DAO.
      СОВЕТ. Предлагаемый в настоящей главе программный код вначале предназначался просто для замены старых недокументированных функций Access, о которых рассказывалось в предыдущих изданиях этой книги. Однако в ходе разработки возникали новые идеи, круг задач расширялся и глава росла. В результате мы можем предложить вам не только замены для старых функций, но и во многих случаях более удобные способы решения тех же задач с использованием модулей классов. Если у вас есть программный код, в котором задействованы только процедуры adh_acc*, описанные в издании этой книги, посвященном Access 97, их можно продолжать использовать и дальше. Однако желательно все же просмотреть эту главу на предмет более удобных способов решения тех же задач.
      Использование процедур
      В отличие от большинства других глав книги в последующих разделах больше рассказывается не о том, как работает предлагаемый нами программный код, а о том, как его можно использовать. Просмотрев наш демонстрационный проект, вы увидите огромное количество объявлений Windows API, констант, пользовательских типов и много очень сложного VBA-кода. Разбираться в том, как весь этот код работает, вам совершенно ни к чему. Конечно, в отдельных случаях вы можете это сделать (если вас интересуют какие-то конкретные технологии или вы хотите модифицировать предложенный код), но в целом это совершенно не обязательно. Главное, чтобы наш код был вам полезен.
      В базе данных CH15.MDB содержится множество стандартных модулей и модулей класса, а также демонстрационных форм. Ни одна из форм в ваших проектах не понадобится. Это значит, что если какие-то из предложенных нами технологий потребуются в вашем приложении, в него нужно будет импортировать только соответствующие модули, но не формы. В каждом разделе мы указываем, какие модули вам потребуются для реализации описанных в нем возможностей (обычно это несколько модулей).
      СОВЕТ. В программном коде этой главы очень активно используются вызовы Windows API и пользовательские классы VBA. Если вы не знакомы с этими концепциями, желательно сначала ознакомиться с соответствующими главами книги (3 и 14), особенно если у вас возникнет необходимость модифицировать предложенный нами код.
      Функции для работы с файлами
      В большинстве приложений Access требуется выполнять те или иные операции над файлами. В наш демонстрационный проект включено несколько полезных функций, позволяющих:
      проверить, существует ли файл;
      разбить полное имя файла на компоненты;
      получить полный путь к файлу;
      Каждая из этих функций рассматривается в отдельном разделе.
      СОВЕТ. Для использования описанных в этом разделе процедур в своем проекте импортируйте в него модуль basFileHandling.
      Проверка существования файла
      Для проверки существования файла можно вызвать функцию adh_accFileExists. Делается это так:
      fRetval = adh_accFileExists(strFileName)
      Эта функция возвращает значение True, если заданный файл существует, и False в противном случае.
      Например, для проверки существования файла C:\AUTOEXEC.BAT можно использовать следующий код.
     
      If adh_accFileExists("C:\AUTOEXEC.BAT") Then
      ' Вы знаете, что C:\AUTOEXEC.BAT существует
      End If
     
      ПРИМЕЧАНИЕ. В версии для Access 97 эта функция возвращала 0, если файл отсутствовал, и 1, если он был найден. Мы модифицировали нашу функцию для большего соответствия стандартам VBA, чтобы она возвращала ответ в виде логического значения: True (файл существует) или False (файла нет). Это может отразиться на работе вашего старого кода при его переносе в Access 2002.
      Однако если вы пишете новый код, мы советуем использовать новую функцию, adhFileExists. Функцию adh_accFileExists мы оставили только для совместимости, и она не делает ничего, кроме вызова adhFileExists.
      Как это работает
      Функция adhFileExists использует встроенную функцию VBA Dir, которая в случае существования указанного вами файла возвращает его имя без пути. Мы передаем этой функции все возможные атрибуты файла, чтобы она нашла файл и в том случае, если он скрытый, системный или доступен только для чтения. Если функция Dir возвращает пустую строку или в ходе ее выполнения происходит ошибка, это абсолютно точно означает, что файла не существует. Вот полный код функции adhFileExists:
     
      Public Function adhFileExists(strName As String) As Boolean
      ' Из модуля basFileHandling
      On Error Resume Next
      Dim strTemp As String
      ' Ищет файл с любым набором атрибутов.
      strTemp = Dir(strName, _
      vbHidden Or vbSystem Or _
      vbArchive Or vbReadOnly)
      adhFileExists = ((Len(strTemp) > 0) And _
      (Err.Number = 0))
      Err.Clear
      End Function
     
      Разделение полного имени файла на элементы
      Очень часто программисту нужно из полного имени файла в формате
      Диск:\Путь\ИмяФайла.Расширение выделить одну или несколько его частей (диск, путь, имя файла или расширение). Эту работу делает процедура adhSplitPath. Ей передается полное имя файла и четыре строковые переменные, в которых она возвращает выделенные элементы.
      ПРИМЕЧАНИЕ. Процедура adhSplitPath не проверяет, существует ли заданный вами файл. Она просто разбирает строку на составные части, разделенные символами "\" и ".". Не рассчитывайте, что она будет проверять правильность имен или существование указанных вами файлов.
      В листинге 15.1 приведен пример процедуры, использующей adhSplitPath, а на рис. 15.1 показан результат работы этой процедуры.
      Рис. 15.1. Процедура adhSplitPath разделяет полное имя файла на составные части
      Листинг 15.1
     
      Public Sub TestSplitPath()
      ' Из модуля basTestFileHandling
      Dim strDrive As String
      Dim strPath As String
      Dim strFileName As String
      Dim strExt As String
     
      adhSplitPath "C:\Windows\System\FOO.INI", strDrive, _
      strPath, strFileName, strExt
      Debug.Print "========================================="
      Debug.Print "Full : " & "C:\Windows\System\FOO.INI"
      Debug.Print "========================================="
      Debug.Print "Drive: " & strDrive
      Debug.Print "Path : " & strPath
      Debug.Print "File : " & strFileName
      Debug.Print "Ext : " & strExt
     
      adhSplitPath "C:\", strDrive, strPath, strFileName, strExt
      Debug.Print "========================================="
      Debug.Print "Full : " & "C:\"
      Debug.Print "========================================="
      Debug.Print "Drive: " & strDrive
      Debug.Print "Path : " & strPath
      Debug.Print "File : " & strFileName
      Debug.Print "Ext : " & strExt
      End Sub
     
      Как это работает
      Процедура adhSplitPath принимает пять параметров. Один из них, обязательный первый параметр, передается по значению (с использованием ключевого слова ByVal), а остальные необязательны и передаются по ссылке (с применением ключевого слова ByRef). Процедура не возвращает никакого значения. Точнее, она возвращает выделенные компоненты имени файла через переданные вами по ссылке четыре последних строковых параметра. Например, если вас интересует папка, в которой хранится некоторый файл, вызовите процедуру adhSplitPath следующим образом:
      В этом фрагменте кода предполагается, что strFullPath
      содержит полное имя файла, а strPath - это строковая
      переменная, в которую должно быть помещено имя папки.
      adhSplitPath strFullPath, Folder:=strPath
      Debug.Print strPath
      В этом случае процедура adhSplitPath, как обычно, выполнит всю работу по разбиению имени файла на части, но вернет вам только значение параметра Folder.
      Если вас интересуют подробности работы нашей процедуры, обратитесь к модулю basFileHandling. (Впрочем, ничего особенного, кроме манипуляций со строками, эта процедура не делает.)
      СОВЕТ. Если вы еще не пользовались функцией Split, появившейся только в Access 2000, возможно, вам захочется просмотреть код adhSplitPath, чтобы понять, как с нею работать. Эта полезная функция получает строку и символ-разделитель и возвращает массив подстрок этой строки, разделенных заданным символом. Мы использовали эту функцию для выделения элементов полного имени файла.
      Получение полного имени файла
      Если вы знаете относительный путь к файлу, но не знаете полного пути, для получения файла можно воспользоваться нашей функцией adhFullPath. Например, если вашим текущим каталогом является C:\WINDOWS, следующий вызов
      adhFullPath("..\SAMPLES\TESTAPP.EXE")
      вернет строку "C:\SAMPLES\TESTAPP.EXE" - полное имя указанного вами файла. Эта функция может быть вам полезна, скажем, в случае, когда нужно знать, в каком каталоге находится файл, для которого известен только относительный путь. Тогда вы передаете этот путь функции adhFullPath, а из возвращенного ею результата выделяете имя каталога с помощью процедуры adhSplitPath, описанной в предыдущем разделе.
      ПРИМЕЧАНИЕ. Назначение нашей функции может быть не совсем очевидным. Она берет имя текущего каталога и переданное вами относительное имя файла и объединяет эту информацию, составляя полное имя файла. Ничего больше она не делает: не проверяет, существует ли ваш файл и похожа ли вообще переданная вами строка на имя файла; не проверяет, существует ли каталог, входящий в состав его относительного имени. Она просто преобразует относительный путь в абсолютный.
      Как это работает
      Функция adhFullPath вызывает функцию Windows API GetFullPathName. Эта функция принимает относительный путь к файлу и возвращает абсолютный. Как и большинству других функций Windows API, возвращающих строки, этой функции нужно передать строковый буфер для заполнения и длину этого буфера. Но она достаточно дружественна и в случае, если в буфере не хватает места, сообщает, какой длины оказалось полное имя файла, чтобы вы могли вызвать ее еще раз и передать ей строковый буфер нужного размера. В листинге 15.2 приведен полный код функции adhFullPath.
      Листинг 15.2
     
      Public Function adhFullPath(strName As String) _
      As String
      ' MAX_PATH определена в Windows API.
      Const MAX_PATH = 260
      Dim lngLen As Long
      Dim lngFilled As Long
      Dim strBuffer As String
     
      lngLen = MAX_PATH
      Do
      strBuffer = Space(lngLen)
      lngFilled = GetFullPathName( _
      strName, lngLen, strBuffer, vbNullString)
      ' Если буфер оказался слишком мал (а
      ' этого не должно случиться, поскольку
      ' мы задали его размер с учетом максимально
      ' допустимой в Windows длины пути), lngFilled
      ' содержит значение необходимого размера буфера.
      ' Тогда попробуем еще раз.
      If lngFilled > lngLen Then
      lngLen = lngFilled
      End If
      Loop Until lngFilled < lngLen
      adhFullPath = Left$(strBuffer, lngFilled)
      End Function
     
      Использование диалоговых окон Windows
      Для стандартизации интерфейса приложений Windows предоставляет в их распоряжение несколько своих наиболее часто используемых диалоговых окон. В частности, если вы хотите предложить пользователю открыть или сохранить файл, выбрать цвет или шрифт, то можете воспользоваться стандартными окнами Windows. В Access нет механизма для вывода этих окон, за исключением окна печати, но это всегда можно сделать с помощью Windows API.
      Но у функций Windows API, предназначенных для работы с диалоговыми окнами, есть один недостаток: ими слишком сложно пользоваться. Поэтому мы разработали для них удобный класс-оболочку под названием CommonDlg и включили его в базу данных CH15.MDB вместе с несколькими примерами. Об этом классе, который вы легко можете включить в свои приложения, рассказывается в следующих разделах.
      В Access есть недокументированная возможность использовать диалоговое окно открытия и сохранения файла Microsoft Office. Вы видите это окно каждый раз, когда открываете или сохраняете файл в любом из приложений Microsoft Office. С помощью процедуры из предлагаемого нами модуля basFileOpen вы сможете выводить его и сами.
      ВНИМАНИЕ. Не забывайте, что недокументированные средства, какими являются функции работы с окном открытия и сохранения файла Microsoft Office, могут не поддерживаться в следующих версиях Access (как это случилось со многими процедурами, описанными в предыдущих изданиях этой книги). Мы даже предполагаем, что в следующей версии Access не останется ни одной из доступных сейчас недокументированных функций. Но пока наш код работает, и мы надеемся, что Microsoft, наконец, предоставит пользователям официальный интерфейс для доступа к своему диалоговому окну.
      Кроме кода для доступа к стандартным диалоговым окнам мы включили в базу данных CH15.MDB код для вывода еще одного диалогового окна, которое, хотя и не является стандартным, требуется очень часто, - окна для выбора папки. С помощью нашего класса ShellBrowse вы сможете предоставить пользователям возможность выбрать каталог, компьютер, принтер или любую виртуальную папку.
      ПРИМЕЧАНИЕ. Мы не включили в наш класс CommonDlg еще одно часто использующееся диалоговое окно - Print. Пользы от его включения в этот класс было бы немного, а наш проект и так оказался внушительных размеров. Вызвав метод RunCommand с опцией acCmdPrint, вы можете легко вывести это окно самостоятельно.
      Использование класса CommonDlg
      Класс CommonDlg содержит код, позволяющий легко выводить диалоговые окна сохранения и открытия файла, выбора шрифта и цвета. Этот класс предоставляет целый ряд удобных свойств и методов и берет на себя всю работу по взаимодействию с Windows API. При этом в классе широко применяются пользовательские и перечислимые типы данных. Вот четыре основных метода этого класса, служащие для вывода четырех диалоговых окон:
     
      Метод Действие
      ShowColor Выводит стандартное диалоговое окно для выбора цвета
      ShowFont Выводит стандартное диалоговое окно для выбора шрифта
      ShowOpen Выводит стандартное диалоговое окно для открытия файла
      ShowSave Выводит стандартное диалоговое окно для сохранения файла
      В простейшем случае для использования этих диалоговых окон достаточно просто создать новый объект CommonDlg и вызвать один из его методов. Вот пример открытия диалогового окна вывода шрифта:
      Dim cdl As CommonDlg
      Set cdl = New CommonDlg
      cdl.ShowFont
      Debug.Print cdl.FontName
      А как насчет элемента ActiveX CommonDialog?
      Если у вас есть элемент ActiveX CommonDialog, его можно использовать вместо нашего класса CommonDlg. Однако с его применением связано несколько ограничений.
      Этот элемент управления должен быть помещен в форму. Если вы хотите обращаться к нему из разных мест приложения, придется либо поместить его во все формы, где он может понадобиться, либо держать форму, в которой он содержится, открытой. Класс же доступен всегда и отовсюду.
      Элемент управления не позволяет задать функцию с обратным вызовом (то есть функцию, которая может вызываться, пока диалоговое окно отображается на экране). Такая функция может обеспечить расположение диалогового окна там, где вы хотите, изменить надписи его элементов управления (в случае диалогового окна открытия или сохранения файла) или отреагировать на действия пользователя в этом окне. С нашим классом все это возможно, и мы включили в базу данных пример функции с обратным вызовом, которая центрирует окно на экране.
      Элемент управления не позволяет задать владельца диалогового окна. Без этой возможности трудно управлять тем, что происходит, когда пользователь нажимает на клавиши Alt+Tab, пока окно находится на экране. У нашего класса CommonDlg имеется свойство hWndOwner, позволяющее вам указать, какому окну "принадлежит" открываемое вами диалоговое окно.
      Элемент управления не содержит исходного кода. Ни модифицировать его, ни дополнить новыми функциями вы не сможете. Что касается нашего класса, то он весь в вашем полном распоряжении.
      Общие действия
      Какое бы из диалоговых окон вам ни потребовалось, процедура его открытия одна и та же.
      1.Убедитесь, что ваш проект содержит класс CommonDlg. (Если вы хотите использовать описанную ниже функцию с обратным вызовом, импортируйте в свой проект также модули basCommonDlg и basCommon.)
      2.Объявите в своем приложении переменную типа CommonDlg:
      Dim cdl As CommonDlg
      3.Создайте объект CommonDlg и присвойте ссылку на него своей переменной:
      Set cdl = New CommonDlg
      4.Настройте свойства объекта CommonDlg. Хотя это и не обязательно, обычно перед открытием окна с помощью свойств OpenFlags, ColorFlags или FontFlags устанавливается несколько опций. Различные опции комбинируются с помощью оператора Or. Вот пример:
      cdl.InitDir = "C:\"
      cdl.OpenFlags = cdlOFNAllowMultiselect Or _
      cdlOFNNoChangeDir
      5.Вызовите нужный вам метод объекта CommonDlg для вывода одного из его диалоговых окон (ShowColor, ShowFont, ShowOpen или ShowSave). Выполнение вашего кода будет приостановлено до закрытия диалогового окна.
      cdl.ShowOpen
      6.Когда пользователь закроет окно, прочитайте информацию о результатах его действий из свойств объекта CommonDlg. Например, чтобы получить выбранное пользователем имя файла, можно написать такую строчку:
      Me.txtFileName = cdl.FileName
      7.Закончив работу с объектом CommonDlg, освободите занимаемую им память:
      Set cdl = Nothing
      СОВЕТ. Как правило, после закрытия диалогового окна вы хотите узнать, не щелкнул ли пользователь на кнопке Cancel. Для этого перед открытием диалогового окна нужно присвоить свойству CalcelError объекта CommonDlg значение True и организовать перехват сообщений об ошибках. После этого, если пользователь закроет окно щелчком на кнопке Cancel, управление будет передано вашему обработчику ошибок. Более подробно об использовании этой технологии рассказывается чуть ниже в разделе "Нажал ли пользователь кнопку Cancel?".
      Теперь вам известна общая схема работы с диалоговыми окнами, и нам осталось обсудить лишь некоторые детали, о которых пойдет речь в следующих разделах. Не пожалейте времени на то, чтобы просмотреть все доступные вам опции и понять их назначение, а если хотите увидеть наш класс в действии - воспользуйтесь тестовыми формами frmTestCommonDlg и frmTestFileOpenSave.
      Совместимость с существующим кодом
      Для того чтобы была возможность применять уже имеющийся код, в котором использовался элемент управления ActiveX Common Dialog, мы сделали класс CommonDlg совместимым с элементами ActiveX. Теперь, если у вас есть код, использующий элемент управления ActiveX, вы можете просто удалить этот элемент из вашего проекта и применить вместо него класс CopmmonDlg. Если в вашем коде был использован метод ShowOpen, ShowSave, ShowColor или ShowFont, то при работе с классом CopmmonDlg его функциональность не изменится.
      Установка опций
      Кроме базовых свойств, о которых рассказывается в следующих разделах, у класса CommonDlg есть еще по одному специальному свойству для каждого типа окна. Это свойство позволяет задать набор опций, управляющих содержимым и поведением окна. Класс CommonDlg передает Windows API структуру данных, один из элементов которой называется Flags. Это длинное целое, представляющее собой набор из 32 однобитовых флагов. Изменяя состояние отдельных битов, вы указываете Windows, как должно вести себя диалоговое окно.
      Мы решили включить в класс CommonDlg аналогичное свойство для каждого из диалоговых окон (Open, Save, Color и Font), по своему интерпретирующего биты свойства Flags. Для каждого из окон мы определили также свою группу констант, служащих для установки его специфических опций. В модуле класса CommonDlg вы найдете перечислимые типы adhFileOpenConstants (для окон открытия и сохранения файла), adhColorConstants (для окна выбора цвета) и adhFontsConstants (для окна выбора шрифта). Соответствующие свойства называются OpenFlags, ColorFlags или FontFlags. Задавать значения опций в этих свойствах вам будет очень удобно - их можно просто выбирать в списке, предлагаемом функцией редактора VBA IntelliSense, как показано на рис. 15.2. Внутренний код класса CommonDlg объединит все три свойства (OpenFlags, ColorFlags и FontFlags) в единое свойство Flags, которое будет передано функции Windows API.
      Такая организация данных значительно облегчает настройку опций диалоговых окон, так что, с одной стороны, сохраняется гибкость такого инструмента, как набор флагов, а с другой стороны, благодаря тому что флаги разделены на группы по назначению, их можно просто выбирать в списке. Вот что, к примеру, представляет собой набор флагов для настройки диалоговых окон открытия и сохранения файла (здесь важны имена констант, а не их значения):
     
      Public Enum adhFileOpenConstants
      cdlOFNAllowMultiselect = 512
      cdlOFNCreatePrompt = 8192
      cdlOFNEnableHook = 32
      cdlOFNEnableSizing = 8388608
      cdlOFNExplorer = 524288
      cdlOFNExtensionDifferent = 1024
      cdlOFNFileMustExist = 4096
      cdlOFNHelpButton = 16
      cdlOFNHideReadOnly = 4
      cdlOFNLongNames = 2097152*
      cdlOFNNoChangeDir = 8
      cdlOFNNoDereferenceLinks = 1048576
      cdlOFNNoLongNames = 262144
      cdlOFNNoNetworkButton = 131072
      cdlOFNNoReadOnlyReturn = 32768
      cdlOFNNoValidate = 256
      cdlOFNOverwritePrompt = 2
      cdlOFNPathMustExist = 2048
      cdlOFNReadOnly = 1
      cdlOFNShareAware = 16384
      End Enum
     
      Для объединения нескольких из этих флагов в одном свойстве можно пользоваться либо оператором "+", либо оператором Or. С математической точки зрения, они делают одно и то же. На наш взгляд, выражение с операторами Or выглядит понятнее, но вообще-то это дело вкуса. Для конечного результата все равно, каким из двух операторов вы воспользуетесь. На рис. 15.2 показано, как формируется значение свойства OpenFlags.
      СОВЕТ. В разделах, посвященных отдельным диалоговым окнам, приведены таблицы с описанием всех возможных значений свойства Flags.
      Использование функции с обратным вызовом
      Класс CommonDlg предоставляет вам одну очень важную возможность: пока открытое вами диалоговое окно остается на экране, Windows может вызвать для выполнения ваш собственный программный код. Наш пример использования этой возможности очень прост: функция с обратным вызовом центрирует диалоговое окно на экране. Однако на самом деле это очень мощное и потенциально опасное средство работы, требующее тщательного изучения документации Windows API.
      ПРИМЕЧАНИЕ. Более подробно об использовании функций с обратным вызовом рассказывалось в главе 14.
      Для использования функции с обратным вызовом по отношению к стандартному диалоговому окну Windows вам нужно знать ответы на следующие вопросы.
      Как указать объекту CommonDlg, что Windows должна вызывать вашу функцию?
      Как объявить функцию, чтобы Windows могла правильно передать ей информацию?
      Как присвоить адрес функции с обратным вызовом соответствующему свойству объекта CommonDlg?
      Что вы намерены делать внутри функции с обратным вызовом?
      Первый вопрос самый простой: установите соответствующий флаг (имя нужной вам константы содержит фрагмент "EnableHook"). Если не установить флаг...EnableHook в свойстве...Flags, Windows никогда не вызовет вашу функцию.
      Ну а как должны быть определены параметры функции с обратным вызовом? Прежде всего, помните, что типы параметров и возвращаемого вашей функцией значения и само это значение должны строго соответствовать требованиям Windows. Поскольку Windows будет вызывать вашу функцию непосредственно, без какого-либо вмешательства VBA, любые ошибки в ее объявлении приведут к разрушению приложения. Вот как должна быть объявлена функция с обратным вызовом для стандартных диалоговых окон Windows:
     
      Public Function SampleCallback( _
      ByVal hWnd As Long, ByVal uiMsg As Long, _
      ByVal wParam As Long, ByVal lParam As Long) As Long
     
      Имя этой функции значения не имеет, так же как и имена ее параметров, но их типы, способ передачи (ByVal) и тип возвращаемого значения должны быть в точности такими, как показано выше. Поэтому мы предлагаем вам всегда использовать в качестве шаблона наш пример функции с обратным вызовом - тогда вы уж точно не ошибетесь.
      Как же сообщить Windows, какую функцию она должна вызывать? Для этого у объекта CommonDlg есть свойство CallBack. Вы должны присвоить ему адрес своей функции, для чего используется модификатор AddressOf. (Раньше этот модификатор был доступен только в Visual Basic, теперь же им можно пользоваться во всех приложениях Office, поддерживающих VBA.) Модификатор AddressOf заменяет имя процедуры ее адресом в памяти. Чтобы этот механизм сработал, процедура должна быть объявлена как Public в стандартном модуле - она не может быть Private и не может находиться в модуле класса. (Более подробная информация о применении модификатора AddressOf приводилась в главе 14.) Однако остается одна маленькая проблема: модификатор AddressOf может использоваться только в вызове процедуры. Нельзя просто взять и написать вот так:
      cdl.CallBack = AddressOf SampleCallback
      VBA просто откажется компилировать такой код. И все же вам нужно как-то поместить в свойство CallBack адрес своей функции. Для этого можно воспользоваться небольшим обходным маневром. В модуле basCommon вы найдете функцию adhFnPtrToLong, которая получает один параметр типа Long и тут же возвращает его обратно:
     
      Public Function adhFnPtrToLong(lngAddress As Long) As Long
      adhFnPtrToLong = lngAddress
      End Function
     
      Чем это нам поможет? Хотя кажется, что функция adhFnPtrToLong просто ничего не делает, ей можно передать имя другой функции с модификатором AddressOf, и она вернет адрес этой функции. С помощью adhFnPtrToLong вы можете легко присвоить свойству CallBack адрес своей функции с обратным вызовом:
      cdl.CallBack = adhFnPtrToLong(AddressOf SampleCallback)
      Именно так мы организовывали обратные вызовы во всех примерах использования класса CommonDlg.
      Теперь посмотрим, что можно делать в самой функции с обратным вызовом. Прежде всего, можно обрабатывать сообщения, переданные ей Windows. Эти сообщения указывают текущее состояние диалогового окна и позволяют принимать решения о дальнейших действиях программы. (Сообщения Windows можно рассматривать просто как константы - собственно, это и есть константы типа Long, которые Windows использует для взаимодействия между приложениями.) Windows передает вашей процедуре сообщение и дескриптор диалогового окна. Дескриптор окна - вещь полезная. С его помощью опытный программист, хорошо знающий Windows API, может проделывать с окном самые разнообразные манипуляции. Наша же простенькая функция-пример дожидается сообщения WM_INITDIALOG (указывающего, что процесс инициализации диалогового окна завершен) и центрирует окно на экране. В листинге 15.3 приведен код функции с обратным вызовом для окон выбора шрифта и цвета. (Вы найдете ее вместе с процедурой CenterWindow в модуле basCommonDlg.)
      СОВЕТ. За дополнительной информацией об использовании функций с обратным вызовом по отношению к стандартным диалоговым окнам Windows вам нужно обратиться к какой-нибудь хорошей документации по Windows API. Если у вас есть подписка на Microsoft Developer Network (MSDN), начните с нее.
      Листинг 15.3
     
      Public Function CDCallback( _
      ByVal hWnd As Long, ByVal uiMsg As Long, _
      ByVal wParam As Long, ByVal lParam As Long) As Long
     
      Select Case uiMsg
      Case WM_INITDIALOG
      ' После инициализации центрируем диалоговое окно.
      Call CenterWindow(hWnd)
      ' Вы можете получить и множество других сообщений.
      ' Все обычные оконные сообщения пройдут через вашу
      ' функцию, и вы сможете отреагировать на любые из них.
      End Select
      ' Пусть и Windows обработает это сообщение
      ' стандартным образом, иначе могут возникнуть проблемы.
      ' Чтобы попросить ее об этом, верните 0.
      CDCallback = 0
      End Function
     
      Использование стандартных диалоговых окон открытия и сохранения файла
      Диалоговые окна Windows, предназначенные для открытия и сохранения файла, дают вам возможность предоставить пользователю стандартный интерфейс для выполнения этих повседневных операций. Для этого вам нужно передать Windows некоторую информацию, после чего она сама выполнит все необходимое и вернет результат.
      Какие бы опции ни выбрал пользователь, какой бы файл он ни указал, само по себе диалоговое окно не будет выполнять никаких действий по открытию или сохранению файла - оно просто передаст вашему приложению информацию о действиях пользователя. А уж что делать с этой информацией, полностью зависит от вас.
      Прежде чем выводить на экран диалоговое окно для открытия или сохранения файла, вы можете захотеть настроить ряд свойств объекта CommonDlg, управляющих внешним видом и поведением этого окна. Все эти свойства перечислены в табл. 15.1.
      ПРИМЕЧАНИЕ. В Windows 98 и Windows 2000 можно изменить размер и координаты диалогового окна открытия или сохранения файла, и Windows их запомнит для последующего использования с этим же окном. В табл. 15.2 описаны специальные флаги, управляющие этими действиями. Мы заметили, что после ошибки VBA (например, если пользователь щелкнул на кнопке Cancel, а вы присвоили свойству CancelError значение True) Windows, похоже, "забывает" размер и координаты окна.
      Таблица 15.1. Свойства класса CommonDlg, относящиеся к диалоговым окнам открытия
      и сохранения файла
     
      Свойство Тип данных Описание
      CallBack Long Адрес функции с обратным вызовом, которую Windows будет вызывать в ходе работы с диалоговым окном. Эта функция может позиционировать окно или выполнять любые другие действия в зависимости от конкретной ситуации
      CancelError Boolean Если присвоить этому свойству значение True, щелчок на кнопке Cancel в диалоговом окне вызовет ошибку выполнения кода класса. В обработчике ошибок проверьте, имеет ли ошибка код cdlCancel - он и означает щелчок на кнопке Cancel
      DefaultExt String Если вы укажете в этом свойстве расширение, оно будет добавлено к имени выбранного пользователем файла. См. описание константы cdlOFNExtensionDifferent в табл. 15.2
      DialogTitle String Текст заголовка диалогового окна
      FileExtOffset Long После возвращения из ShowOpen или ShowSave содержит смещение расширения имени файла (в символах). Это облегчает разделение имени файла на составные части
      FileList String() Если вы установили флаг cdlOFNAllowMultiselect, пользователь может выбрать несколько файлов. После закрытия диалогового окна этот массив строк будет содержать по одному элементу для каждого выбранного файла. FileList(0) всегда содержит имя папки, в которой находятся все выбранные файлы, а элементы от FileList(1) до FileList(n) (где n - общее количество выбранных файлов) содержат их имена. Если пользователь выбрал только один файл, FileList(0) всегда будет содержать имя его папки, а FileList(1) - имя самого файла
      FileName String Полное имя выбранного файла, включая путь. Если задать это свойство до обращения к ShowOpen или ShowSave, диалоговое окно выведет указанное вами имя файла как выбранное по умолчанию
      FileNameBufferSize Long Перед тем как попросить Windows вывести окно открытия или сохранения файла, класс CommonDlg должен выделить память для возвращаемых имен файлов. По умолчанию выделяется 20 000 байт. Если вам кажется, что этого мало, можете задать в данном свойстве другой размер буфера. Однако если вы точно знаете, что пользователи не станут выбирать много файлов за один раз, значения по умолчанию будет вполне достаточно
      FileOffset Long После возвращения из ShowOpen или ShowSave это свойство содержит смещение в символах имени файла относительно начала его полного пути
      FileTtile String После возвращения из ShowOpen или ShowSave это свойство содержит имя выбранного файла и расширение без пути. Если выбрано несколько файлов, это свойство останется пустым
      Filter String Список предлагаемых пользователю фильтров в виде пар имя фильтра/шаблоны, разделенных символами "
      FilterIndex Integer Индекс фильтра (начиная с 1), который нужно выбрать при открытии окна. По умолчанию выбирается первый фильтр. После закрытия окна содержит индекс выбранного пользователем фильтра
      Flags Long Ноль или более значений из табл. 15.2 (скомбинированных с помощью оператора Or), указывающих, как должно быть инициализировано диалоговое окно и как оно должно себя вести. Вы можете задать либо это значение, либо значение свойства OpenFlags. Последнее дает вам возможность выбирать отдельные значения в списке констант adhFileOpenConstants, поэтому мы предлагаем всегда пользоваться свойством OpenFlags, а не свойством Flags, которое включено в класс для совместимости с элементом ActiveX CommonDialog
      hWndOwner Long Дескриптор окна, родительского по отношению к открываемому диалоговому окну открытия или сохранения файла. Если вы открываете названное окно из формы, присвойте этому свойству значение свойства hWnd формы, в противном случае - значение Application.hWndAccessApp
      InitDir String Папка, файлы которой диалоговое окно должно показать после открытия. Если не задать это свойство, в диалоговом окне будут выведены файлы текущей папки. После того как пользователь сделает выбор, Windows назначит выбранную им папку текущей, если только вы не установите флаг cdlOFNNoChangeDir
      OpenFlags AdhFileOpen-Constants Ноль или более значений из табл. 15.2 (скомбинированных с помощью оператора Or), указывающих, как должно быть инициализировано диалоговое окно и как оно должно себя вести. Вы можете задать либо это значение, либо значение свойства Flags. Первое дает вам возможность выбирать отдельные флаги из списка констант adhFileOpenConstants, поэтому мы предлагаем всегда пользоваться свойством OpenFlags, а не свойством Flags, которое включено в класс для совместимости с элементом ActiveX CommonDialog
      Таблица 15.2. Допустимые значения свойств Flags и OpenFlags
     
      Константа Описание
      cdlOFNAllowMultiselect Указывает, что пользователь может выбрать в списке более одного файла. Если вы установили этот флаг, используйте для работы с массивом полученных имен свойство FileList (см. табл. 15.1)
      cdlOFNCreatePrompt Если этот флаг установлен и пользователь указал несуществующий файл, Windows запросит у него подтверждение необходимости его создания. Однако Windows на самом деле не будет создавать файл, а просто закроет окно, и свойство FileName будет содержать указанное пользователем имя файла. Если же флаг не установлен и пользователь указал несуществующий файл, Windows просто закроет окно. Если этот флаг используется в сочетании с флагом cdlOFNAllowMultiselect, допускается задание только одного несуществующего файла
      cdlOFNEnableHook Если этот флаг установлен, в ходе работы с окном Windows будет вызывать вашу функцию, заданную в свойстве CallBack. В Windows 98, Windows 2000 и Windows XP, если установить этот флаг и не установить флаг cdlOFNEnableSizing, пользователь не сможет менять размер диалогового окна
      cdlOFNEnableSizing (Только в Windows 98, Windows 2000 и Windows XP.) По умолчанию пользователь может менять размер диалогового окна, и Windows запоминает установленную им позицию и размер, используя их при следующем открытии окна. Как правило, этот флаг вам не нужен, но если вы установили флаг cdlOFNEnableHook, Windows считает, что вы хотите сами управлять размером и координатами окна, и запрещает делать это пользователю. Однако с помощью нашего класса вы не можете позиционировать окно, и поэтому, если вы устанавливаете флаг cdlOFNEnableHook, установите и cdlOFNEnableSizing. В Windows 95 и Windows NT данный флаг игнорируется, поэтому вы не сможете изменять размер диалогового окна
      cdlOFNExplorer Указывает Windows, что диалоговое окно должно иметь интерфейс Windows Explorer. Класс CommonDlg всегда устанавливает этот флаг. Если вас это не устраивает, придется модифицировать код нашего класса
      cdlOFNExtensionDifferent По возвращении из диалогового окна указывает, что пользователь выбрал файл с расширением, отличающимся от заданного в свойстве DefaultExt. Если вы не задали значение свойства DefaultExt, этот флаг никогда не будет установлен. Для выяснения значения этого флага используйте следующий код:If cldOpenFlags And _ cdlOFNExtensionDifferent <> 0 Then ' Вы знаете, что выбран файл с ' расширением, отличающимся от ' заданного вами в свойстве DefaultExtEnd If
      cdlOFNFileMustExist Указывает, что пользователь может вводить имена только существующих файлов. Если пользователь введет имя несуществующего файла, Windows выведет сообщение об ошибке. Когда данный флаг установлен, диалоговое окно ведет себя так, как будто установлен также и флаг cdlOFNPathMustExist
      cdlOFNHelpButton Управляет выводом в диалоговом окне кнопки Help. Хотя вы вполне можете реагировать на щелчок пользователя на этой кнопке, для этого нужно создать подкласс окна и обрабатывать зарегистрированные сообщения Windows. Рассказ об этом выходит за рамки нашей книги, и мы включили в наш класс данную константу только для совместимости с элементом ActiveX CommonDialog1
      cdlOFNHideReadOnly Если этот флаг установлен, в диалоговом окне отсутствует опция Read Only
      cdlOFNLongNames Для диалоговых окон старого стиля (см. описание флага cdlOFNExplorer) разрешает использование длинных имен файлов. Этот флаг не используется классом CommonDlg и включен в него только для совместимости
      cdlOFNNoChangeDir Если этот флаг установлен, то после того, как пользователь закроет диалоговое окно, Windows восстановит исходный текущий каталог, даже если пользователь выбрал файлы из другого каталога
      cdlOFNNoDereferenceLinks Если пользователь выберет ярлык (LNK-файл), Windows вернет вам имя и путь этого LNK-файла. Если же этот флаг не установлен, Windows вернет имя и путь того файла, на который ссылается выбранный ярлык
      cdlOFNNoLongNames Для диалоговых окон старого стиля (см. флаг cdlOFNExplorer) установка флага вызывает вывод всех файлов в формате 8.3. Этот флаг не используется классом CommonDlg и включен в него только для совместимости
      cdlOFNNoNetworkButton Для диалоговых окон старого стиля (см. опсание флага cdlOFNExplorer) при установке этого флага из диалогового окна удаляется кнопка Network. Данный флаг не используется классом CommonDlg и включен в него только для совместимости
      cdlOFNNoReadOnlyReturn Если после закрытия диалогового окна этот флаг оказывается установленным, значит, пользователь не установил флаг Read Only и сам файл не находится в папке, защищенной от записи. Чтобы проверить, установлен ли этот флаг, воспользуйтесь оператором And (см. пример для флага cdlOFNExtensionDifferent)
      cdlOFNNoValidate Указывает, что в имени файла можно применять недопустимые символы. Как правило, этот флаг устанавливать нежелательно1
      cdlOFNOverwritePrompt Если этот флаг установлен и файл, выбранный пользователем в диалоговом окне сохранения файла, уже существует, Windows выведет диалоговое окно для подтверждения необходимости проведения операции. Разработчик может решить, предупреждать ли пользователя о вводе имени уже существующего файла
      cdlOFNPathMustExist Определяет, что пользователь может указывать только допустимые имена файлов и папок. Если этот флаг установлен, Windows выводит диалоговое окно, предупреждающее пользователя о вводе неверного пути и имени
      cdlOFNReadOnly Если этот флаг установлен, по умолчанию в диалоговом окне устанавливается флаг Read Only. После закрытия диалогового окна этот же флаг указывает, оставил ли пользователь этот флаг или снял его. Чтобы проверить, установлен ли данный флаг, воспользуйтесь оператором And (см. пример для флага cdlOFNExtensionDifferent)
      cdlOFNShareAware Если этот флаг установлен и пользователь выбрал файл, который уже открыт, ошибка игнорируется и Windows возвращает имя выбранного файла1
      1Для полной поддержки опции требуется написание дополнительного программного кода с использованием Windows API. Поэтому мы рекомендуем использовать данный флаг, только если вы точно знаете, что делаете.
      Если стандартное поведение диалогового окна открытия или сохранения файла вас устраивает, вам не нужно устанавливать никакие из описанных флагов. Вызовите метод ShowOpen или ShowSave, и стандартное диалоговое окно будет выведено на экран. Если, к примеру, выполнить следующий код, то сначала появится диалоговое окно открытия файла, а после его закрытия - окно с сообщением о том, какой файл вы в нем выбрали.
     
      Dim cdl As CommonDlg
      Set cdl = New CommonDlg
      cdl.ShowOpen
      MsgBox cdl.FileName
     
      Если же вы хотите указать Windows, какие файлы следует предлагать пользователю, какую папку открыть первой, выводить ли в окне флажок Read Only и т. п., тогда вам нужно изучить свойства и флаги, описанные в табл. 15.1 и 15.2. В этом вам помогут демонстрационные формы frmTestCommonDlg и frmTestFileOpenSave. В листинге 15.4 приведена процедура из модуля формы frmTestCommonDlg, в которой используются многие свойства класса CommonDlg.
      СОВЕТ. Для выполнения этой процедуры откройте форму frmTestCommonDlg, щелкните в ней на кнопке Test File Open и выберите файл. Если вы выберете файл с расширением, отличным от BAT, то получите предупреждающее сообщение о том, что выбрали файл не с тем расширением.
      Процедура cmdFileOpen_Click выполняет следующие действия.
      Объявляет и создает объект CommonDlg:
      Dim cdl As CommonDlg
      Set cdl = New CommonDlg
      Делает текущую форму владельцем диалогового окна:
      cdl.hWndOwner = Me.hWnd
      Задает набор фильтров для отбора файлов и указывает, какой из них нужно применить по умолчанию:
      ' Устанавливаем три пары значений для фильтрации файлов.
     
      cdl.Filter = _
      "Text files (*.txt)|" & _
      "*.txt|" & _
      "Database files (*.mdb, *.mde, *.mda)|" & _
      "*.mdb;*.mde;*.mda|" & _
      "All files (*.*)|" & _
      "*.*"
     
      ' Выбираем второй фильтр (Database files) для
      ' отбора файлов при открытии диалогового окна.
      cdl.FilterIndex = 2
      Устанавливает свойство OpenFlags, указывая, как должно вести себя диалоговое окно:
      cdl.OpenFlags = cdlOFNEnableHook Or _
      cdlOFNNoChangeDir Or cdlOFNFileMustExist
      Назначает функцию с обратным вызовом, для чего присваивает свойству CallBack адрес нашей функции-примера из модуля basCommonDlg. Функция с обратным вызовом должна находиться в стандартном модуле, быть объявлена как Public и соответствовать требованиям, перечисленным в разделе "Использование функции с обратным вызовом". Для записи адреса процедуры в переменную необходимо вызвать функцию adhFnPtrToLong:
      cdl.CallBack = adhFnPtrToLong(AddressOf GFNCallback)
      Устанавливает еще несколько свойств:
      cdl.InitDir = "C:\"
      cdl.FileName = "autoexec.bat"
      cdl.DefaultExt = "bat"
      Вызывает метод ShowOpen, после чего выполнение кода приостанавливается до тех пор, пока диалоговое окно не будет закрыто:
      cdl.ShowOpen
      После закрытия диалогового окна считывает выбранное пользователем имя файла:
      txtFileOpen = cdl.FileName
      Проверяет, имеет ли имя файла то расширение, которое вы задали в свойстве DefaultExt:
     
      If (cdl.OpenFlags And _
      cdlOFNExtensionDifferent) <> 0 Then
      MsgBox "You chose a different extension!"
      End If
     
      В листинге 15.4 эта процедура приведена целиком.
      СОВЕТ. Чтобы эта процедура выполнялась в вашем приложении, нужно импортировать в него модуль нашего класса CommonDlg. Если вы хотите использовать функцию с обратным вызовом, импортируйте также модули basCommon и basCommonDlg (содержащие ее образец и функцию, необходимую для организации ее вызова).
      СОВЕТ. Об использовании свойства CancelError для перехвата ошибки, генерируемой, когда пользователь закрывает окно кнопкой Cancel, рассказывается в следующем разделе.
      Листинг 15.4
     
      Private Sub cmdFileOpen_Click()
      ' Тестирует диалоговое окно открытия файла и класс CommonDlg.
     
      Dim cdl As CommonDlg
      Set cdl = New CommonDlg
     
      cdl.hWndOwner = Me.hWnd
      cdl.CancelError = True
     
      On Error GoTo HandleErrors
     
      ' Задаем три пары значений для фильтрации файлов.
      cdl.Filter = _
      "Text files (*.txt)|" & _
      "*.txt|" & _
      "Database files (*.mdb, *.mde, *.mda)|" & _
      "*.mdb;*.mde;*.mda|" & _
      "All files (*.*)|" & _
      "*.*"
     
      ' Выбираем второй фильтр (Database files) для
      ' отбора файлов при открытии диалогового окна.
      cdl.FilterIndex = 2
     
      ' Устанавливаем флаги, указывающие, что мы
      ' хотим использовать функцию с обратным вызовом,
      ' после закрытия окна вернуться в исходную папку,
      ' а также хотим, чтобы пользователь мог выбрать
      ' только cуществующий файл.
      cdl.OpenFlags = cdlOFNEnableHook Or _
      cdlOFNNoChangeDir Or cdlOFNFileMustExist
     
      ' Задаем адрес функции с обратным вызовом.
      cdl.CallBack = adhFnPtrToLong(AddressOf GFNCallback)
     
      ' Устанавливаем еще несколько свойств.
      cdl.InitDir = "C:\"
      cdl.FileName = "autoexec.bat"
      cdl.DefaultExt = "bat"
     
      ' Открываем диалоговое окно открытия файла
      ' и ждем, пока пользователь его закроет.
      cdl.ShowOpen
     
      ' Считываем имя выбранного пользователем файла.
      txtFileOpen = cdl.FileName
     
      ' Проверяем свойство OpenFlags (или Flags), чтобы
      ' выяснить, отличается ли расширение файла от
      ' заданного нами расширения по умолчанию.
      If (cdl.OpenFlags And _
      cdlOFNExtensionDifferent) <> 0 Then
      MsgBox "You chose a different extension!"
      End If
      ExitHere:
      Set cdl = Nothing
      Exit Sub
     
      HandleErrors:
      Select Case Err.Number
      Case cdlCancel
      ' Пользователь нажал кнопку Cancel!
      Resume ExitHere
      Case Else
      MsgBox "Error: " & Err.Description & _
      "(" & Err.Number & ")"
      End Select
      Resume ExitHere
      End Sub
     
      ПРИМЕЧАНИЕ. Единственным отличием окон открытия и сохранения файла является интерпретация ими некоторых из перечисленных в табл. 15.2 флагов. Эти окна выглядят и ведут себя практически одинаково. Какой бы метод вы ни собирались вызвать, ShowOpen или ShowSave, для установки нужных флагов пользуйтесь свойством OpenFlags.
      СОВЕТ. Если вы предпочитаете открывать окно с помощью одного вызова процедуры, которая скрыла бы от вас подробности процесса создания объекта и установки его свойств, то можете воспользоваться функцией adhCommonFileOpenSave из модуля basFileOpen. Ей передаются параметры, определяющие поведение окна, а возвращает она имя выбранного пользователем файла.
      Нажал ли пользователь кнопку Cancel?
      Если вас интересует, нажал ли пользователь кнопку Cancel (а не просто щелкнул на кнопке OK, не выбрав ни одного файла), добавьте в свою процедуру дополнительный код.
      1.Присвойте свойству CancelError объекта CommonDlg значение True.
      2.Включите в процедуру обработчик ошибок и проверьте в нем наличие ошибки cdlCancel (32755). Эту ошибку генерирует класс CommonDlg после того, как пользователь щелкнет на кнопке Cancel (или нажмет клавишу Esc).
      В обработчике события можно отреагировать на нажатие пользователем этой кнопки. Однако чаще приложение просто продолжает работу, не делая в ответ ничего особенного. Например, обработчик события cmdChooseColor_Click из модуля формы frmTestCommonDlg в случае нажатия кнопки Cancel просто ничего не делает (об использовании диалогового окна выбора цвета подробно рассказывается в специально посвященном ему разделе этой главы):
     
      Private Sub cmdChooseColor_Click()
      Dim cdl As CommonDlg
     
      On Error GoTo HandleErrors
      Set cdl = New CommonDlg
     
      ' Если пользователь нажмет кнопку Cancel,
      ' сгенерировать ошибку времени выполнения.
      cdl.CancelError = True
     
      ' Здесь часть кода опущена.
      cdl.ShowColor
      ' Здесь часть кода опущена.
     
      ExitHere:
      Set cdl = Nothing
      Exit Sub
     
      HandleErrors:
      Select Case Err.Number
      Case cdlCancel
      ' Ничего не делаем.
      Case Else
      MsgBox "Error: " & Err.Description & _
      " (" & Err.Number & ")"
      End Select
      Resume ExitHere
      End Sub
     
      ВНИМАНИЕ. Обязательно проверьте, какая из опций перехвата ошибок выбрана для параметра VBA Error Trapping (Tools ? Options ? General). Если выбрана опция Break in Class Module, ни один из модулей класса, в которых вы перехватываете ошибку cdlCancel, не будет работать правильно. Дело в том, что эта опция заставляет VBA перейти в режим останова, как только произойдет ошибка в модуле класса. В Visual Basic, создающем независимые приложения, эта опция полезна, но в Access она может пригодиться лишь в некоторых случаях и только на время отладки. Оставлять ее в готовом приложении нельзя. Так что выберите лучше опцию Break on Unhandled Errors, иначе вы не сможете пользоваться свойством класса CancelError. Хотите убедиться? Установите опцию Break in Class Module, откройте форму frmTestCommonDlg, щелкните в ней на первой кнопке, а в диалоговом окне открытия файла - на кнопке Cancel. Вы тут же окажетесь в редакторе Visual Basic в режиме останова - выполнение кода будет остановлено в обработчике ошибки. Если вы не хотите, чтобы в такой же ситуации оказался пользователь, тогда проверяйте установку этой опции в каждом готовом проекте.
     

Разработка настольных приложений в Access 2002. Для профессионалов (+CD). / П. Литвин, К. Гетц, М. Гунделой - СПб: Питер, 2002. - 1008 с.

Экономика и управление | Право/a> | Бухгалтерский учет и налоги |