Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОСНОВЫ ОФИСНОГО ПРОГРАММИРОВАНИЯ И ЯЗЫК VBA - 2....doc
Скачиваний:
79
Добавлен:
17.12.2018
Размер:
1.62 Mб
Скачать

Классы как обертка вызовов функций Win32 api

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

Каждый из наших примеров работы с функциями Win32 API достоин лучшей упаковки и представления его в виде класса. Мы ограничимся одним последним примером и представим в виде класса работу с таймером. Пожалуй, этот пример наиболее интересен, поскольку он представляет особый случай из-за наличия Callback функции, которая, конечно же, не может быть стандартизована и должна быть задана конечным пользователем, в интересах которого и строится класс.

Построение класса "ВашТаймер"

Поскольку мы уже хорошо знакомы с тем, как строятся классы и как работать с функциями Win32 API, то нам осталось рассказать, как объединить эти две вещи в единое целое. Никаких особых деталей здесь нет. Общая стратегия такова:

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

  • Встроить в класс стандартные средства, сделав их скрытыми, недоступными для внешнего использования.

  • Реализовать интерфейс класса, используя встроенные средства, возможно расширив их возможности.

Применим эту общую схему для создания класса ВашТаймер. Начнем с проектирования его интерфейса. Естественно, целью класса является предоставление пользователю возможности создавать таймер, посылающий сообщения с заданным интервалом, и удалять его, когда необходимость в нем исчезнет. Пользователь не должен ничего знать о функциях Win32 API, об операторах Declare, преобразовании типов. Кажется естественным с этих позиций в интерфейс класса включить два метода: "СоздатьТаймер" и "УдалитьТаймер" и свойство "ИнтервалТаймера", доступное для чтения и записи. Методы не имеют параметров, что облегчает работу с ними. Чтобы созданный таймер посылал сообщения с заданным интервалом, необходимо предварительно установить подходящее значение свойства, но можно этого и не делать, - в этом случае будет использоваться значение по умолчанию.

Рассматриваемый нами случай упаковки функций Win32 API особый, поскольку одна из этих функций требует вызова Callback функции. Заметьте, функции обратного вызова не должны принадлежать упаковке, - нашему классу. Они не являются стандартными средствами, это функции, создаваемые пользователем. Поэтому они должны находиться вне модуля класса, - в стандартном классе, созданном пользователем, там, где он будет создавать и объекты класса ВашТаймер. Чтобы не возникала соблазна поместить в класс функцию обратного вызова, такая возможность исключается синтаксически. Обратите, однако, внимание, что созданный класс предъявляет определенные требования к заголовку функции обратного вызова и даже диктует ее имя. Но обо всем по порядку и давайте вначале рассмотрим описание класса ВашТаймер:

Option Explicit

'Класс ВашТаймер служит упаковкой функций WIN32 API работы с таймером

'Интерфейс класса будут составлять две функции:

'СоздатьТаймер, УдалитьТаймер и свойство ИнтервалТаймера

'При работе с классом необходимо описать Callback функцию по следующему образцу:

'Public Sub TimerProc(ByVal HandleW As Long, ByVal msg As Long, _

' ByVal idEvent As Long, ByVal TimeSys As Long)

' 'Функция обратного вызова. Вызывается при обработке сообщения WM_Timer,

' 'посылаемого таймером, созданным процедурой SetTimer

'

' 'Поместите здесь свой код!

'

'End Sub

'Функции Win32 API для работы с таймером

Private Declare Function SetTimer Lib "user32" (ByVal hwnd As Long, _

ByVal nIDEvent As Long, ByVal uElapse As Long, ByVal lpTimerFunc As Long) As Long

Private Declare Function KillTimer Lib "user32" (ByVal hwnd As Long, ByVal nIDEvent As Long) As Long

'Свойства: Интервал - хранит значение интервала посылки сообщений

Private Интервал As Long

'Идентификатор таймера

Private IdEv As Long

Public Sub СоздатьТаймер()

'Создает таймер, вызывая Win32 Api функцию SetTimer

IdEv = SetTimer(0&, 0&, Интервал, AddressOf TimerProc)

If IdEv = 0 Then

MsgBox ("Не удалось создать таймер!")

Else

Debug.Print "Создан Таймер: Идентификатор = ", IdEv

End If

End Sub

Public Sub УдалитьТаймер()

'Удаляет таймер

If IdEv > 0 Then

Call KillTimer(0&, IdEv)

Debug.Print "Удален Таймер: Идентификатор = ", IdEv

IdEv = 0

End If

End Sub

Public Property Get ИнтервалТаймера() As Long

ИнтервалТаймера = Интервал

End Property

Public Property Let ИнтервалТаймера(ByVal NewValue As Long)

Интервал = NewValue

End Property

Private Sub Class_Initialize()

Интервал = 1000

End Sub

Private Sub Class_Terminate()

УдалитьТаймер

End Sub

Пример 6.12. (html, txt)

Некоторые комментарии к этому тексту:

  1. О проектировании интерфейса класса мы уже говорили. Его составляют два метода, не имеющие параметров, - СоздатьТаймер и УдалитьТаймер, а также процедуры - свойства Property Get и Property Let ИнтервалТаймера, позволяющие взаимодействовать с закрытым свойством Интервал.

  2. Закрытых свойств и методов больше. Закрытыми являются операторы Declare, описывающие функции Win32 API SetTimer и KillTimer, уже упомянутое свойство Интервал и свойство IdEv, хранящее идентификатор таймера, о котором конечный пользователь может и не знать.

  3. Закрытыми являются конструктор класса по умолчанию и деструктор: Class_Initialize и Class_Terminate. В конструкторе инициализируется свойство Таймер, значение которого устанавливается по умолчанию, равным одной секунде. В деструкторе класса таймер уничтожается, если он не был удален до этого.

  4. При создании таймера устанавливается ссылка на функцию обратного вызова с именем TimerProc. Процедура с таким именем и уже упоминавшимися требованиями к ее заголовку должна быть описана в стандартном модуле класса, созданным конечным пользователем.

  5. В описание класса в качестве комментария вставлена заготовка функции обратного вызова, чтобы облегчить создание этой функции конечному пользователю.