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

Функция EnumWindows

Окна являются одним из основных объектов операционной системы. Обычно, программист и не подозревает, сколь много таких объектов существует в процессе работы его программы. Функция EnumWindows позволяет перечислить все такие объекты. В нашем примере мы в результате работы с окнами сформируем три коллекции, - описателей окон, имен классов окон, заголовков окон. Задачей функции обратного вызова будет формирование этих коллекций путем добавления очередного элемента коллекции при каждом вызове Callback функции.

Начнем с описания функции EnumWindows в том виде, в каком оно представлено в документации Platform SDK:

BOOL EnumWindows(

WNDENUMPROC lpEnumFunc, // pointer to callback function

LPARAM lParam // application-defined value

);

Функция EnumWindows перечисляет все окна верхнего уровня, передавая текущий описатель окна Callback функции, определенной в приложении. Функция не перечисляет дочерние окна - Child Windows . Функция выполняется, пока перечисление не будет закончено или Callback функция не вернет значение False. Ее параметры:

  1. lpEnumFunc - указатель на определенную в приложении Callback функцию.

  2. lParam - определенное приложением значение, передаваемое в Callback функцию.

Функция возвращает значение 0 в случае неуспеха и ненулевое значение при благоприятном исходе.

Описание Callback функции EnumWindowsProc, полученное из той же документации, имеет вид:

BOOL CALLBACK EnumWindowsProc(

HWND hwnd, // handle to parent window

LPARAM lParam // application-defined value

);

Функция EnumWindowsProc является Callback функцией, определенной в приложении, используемой при вызове функций Win32 API EnumWindows или EnumDesktopWindows. Она получает при вызове описатель окна верхнего уровня. Тип WNDENUMPROC определяет указатель на эту Callback функцию. Имя EnumWindowsProc является держателем места (placeholder) и должно быть замещено именем функции, определенной в приложении.

Ее параметры:

  1. hwnd - описатель окна верхнего уровня.

  2. lParam - определенное приложением значение, данное в EnumWindows или EnumDesktopWindows.

Для продолжения перечисления функция возвращает значение True, для окончания - False.

Как видите, представленные описания функций ориентированы на язык C/C++ и нуждаются в преобразовании для их использования в программах на VB/VBA. Используя обозреватель API Viewer, можно получить оператор Declare для функции EnumWindows. Вот как выглядит заголовок этой функции после соответствующей трансляции:

Public Declare Function EnumWindows Lib "user32" _

(ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

Заметьте, появились описатели ByVal, а все типы заменились в данном случае на тип Long. Поскольку API Viewer не помощник в деле преобразования описания Callback функций, то эту работу необходимо проделать самостоятельно. В результате, описание имеет вид:

Public Function EnumWindowsProc(ByVal HandleW As Long, _

ByVal lParam As Long) As Long

Заметим, формальная трансляция не вызывает затруднений, - описатель Callback следует опустить, имя можно дать произвольное, а трансляция типов в данном случае достаточно проста. Вместе с тем, с описанием типа параметра lParam не все так просто. Ведь он должен служить для передачи произвольной информации, поэтому теоретически допускается задание любого произвольного типа для этого параметра, например, этот параметр может быть объектом. В этом случае следует быть особо внимательным, так первая наша попытка передать функции параметр, отличный от типа Long, привела к критической ошибке и прекращении работы приложения. Как я уже говорил ранее, можно применить альтернативный способ и передавать информацию, пользуясь глобальными переменными.

Перейдем теперь к описанию реализации нашего примера. В проекте тестового документа был создан модуль с именем "ОбратныйВызов". Вот текст раздела объявлений этого модуля:

Option Explicit

'Операторы Declare вызываемых функций Win32 API

Public Declare Function EnumWindows Lib "user32" _

(ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" _

(ByVal hwnd As Long, ByVal lpString As String, ByVal cch As Long) As Long

Public Declare Function GetClassName Lib "user32" Alias "GetClassNameA" _

(ByVal hwnd As Long, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long

'Описание глобальных переменных, обеспечивающих связь

'с функцией обратного вызова EnumWindowsProc

Public HandleCol As New Collection

Public CaptCol As New Collection

Public ClassNameCol As New Collection

Помимо функции EnumWindows, основной для нашего примера, но о которой уже много говорилось, в разделе приведено объявление новой, ранее не упоминавшейся Win32 API функции GetClassName. Она похожа на функцию GetWindowText и возвращает по описателю окна имя класса этого окна. Функцию GetWindowText мы объявляем повторно, соответствующий оператор Declare есть в разделе объявлений другого модуля проекта, но, заметьте, в этом есть необходимость, поскольку в других модулях эта функция использовалась с различными псевдонимами. Раздел объявлений модуля содержит объявление трех глобальных переменных - трех коллекций, с которыми будет работать Callback функция EnumWindowsProc, формируя на каждом шаге своего вызова очередной элемент каждой из коллекций. Коллекции будут содержать соответственно описатели окон, заголовки окон и имена классов. Заметьте, что все окна имеют имя класса, но не все окна имеют заголовок, так что число элементов в коллекциях будет различным в процессе работы. Приведем теперь текст Callback процедуры EnumWindowsProc:

Public Function EnumWindowsProc(ByVal HandleW As Long, _

ByVal lParam As Long) As Long

Dim TextW As String

Dim LenTextW As Long

Dim Res As Long

'Добавить описатель в коллекцию

HandleCol.Add HandleW

'Получить заголовок окна.

TextW = VBA.String$(255, vbNullChar)

LenTextW = VBA.Len(TextW)

Res = GetWindowText(HandleW, TextW, LenTextW)

If Res > 0 Then

'Добавить заголовок в коллекцию

TextW = VBA.Left(TextW, Res)

CaptCol.Add TextW

End If

'Получить класс окна.

TextW = VBA.String$(255, vbNullChar)

LenTextW = VBA.Len(TextW)

Res = GetClassName(HandleW, TextW, LenTextW)

If Res > 0 Then

'Добавить имя класса в коллекцию

TextW = VBA.Left(TextW, Res)

ClassNameCol.Add TextW

End If

EnumWindowsProc = 1

End Function

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

Напомним, эта процедура вызывается автоматически в процессе работы процедуры EnumWindows. Поскольку процедура всегда возвращает значение 1, означающее успешность ее работы, то число ее вызовов определяется размером перечисляемого множества окон. Обратите внимание и на то, что в процедуре используется только первый параметр - описатель текущего окна, который передается вызываемым Win32 API функциям GetWindowText и GetClassName. Второй параметр вообще не используется, вместо этого напрямую происходит заполнение коллекций, заданных глобальными переменными. Так обеспечивается связь с внешним миром.

Чтобы закончить пример, нам осталось привести описание процедуры GetCaptions, вызывающей EnumWindows:

Public Sub GetCaptions()

'Вызов Win32 API функции EnumWindows,

'вызывающей в свою очередь Callback функцию EnumWindowsProc

Dim item As Variant

Dim Res As Long

Res = EnumWindows(AddressOf EnumWindowsProc, 0&)

'Обработка глобальных переменных, определенных в

'результате совместной работы EnumWindows и EnumWindowsProc

Debug.Print "Число окон = ", HandleCol.Count

Debug.Print "Описатели окон"

Res = 0

For Each item In HandleCol

Debug.Print item

Res = Res + 1

If Res > 10 Then Exit For

Next item

Debug.Print "Число окон с заголовками= ", CaptCol.Count

Debug.Print "Заголовки окон"

Res = 0

For Each item In CaptCol

Debug.Print item

Res = Res + 1

If Res > 10 Then Exit For

Next item

Debug.Print "Число окон, возвращающих класс = ", ClassNameCol.Count

Debug.Print "Имена классов окон"

Res = 0

For Each item In ClassNameCol

Debug.Print item

Res = Res + 1

If Res > 10 Then Exit For

Next item

End Sub

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

Несколько комментариев к этой процедуре:

  1. Главное, на что следует обратить внимание, это на операцию "AddressOf" в момент вызова Win32 API функции EnumWindows. В результате ее выполнения создается ссылка на Callback функцию (адрес расположения функции в памяти). Заметьте, на имя передаваемой функции не накладывается ограничений, поэтому в разных вызовах могут быть разные имена, что и позволяет иметь при необходимости несколько Сallback функций.

  2. Мы передаем 0 в качестве значения второго параметра. Это своего рода заглушка, поскольку, как говорилось ранее, передача информации производится через глобальные переменные. В следующем примере мы продемонстрируем возможность передачи информации и через этот параметр.

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

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

Число окон = 254

Описатели окон

3735790

131912

131888

131916

65684

40370412

917748

262866

852650

852668

131844

Число окон с заголовками =76

Заголовки окон

Continue

Microsoft Agent

Microsoft Office Shortcut Bar

Menu Parent Window

NetDDE Agent

Edit

Microsoft Visual Basic - DocOne6 [running] - [ОбратныйВызов (Code)]

Ch6 - Microsoft Word

Edit

Properties

Microsoft Office Shortcut Bar

Число окон, возвращающих класс =254

Имена классов окон

OfficeTooltip

tooltips_class32

ComboLBox

tooltips_class32

tooltips_class32

AgentAnimBalloon

AgentAnim

tooltips_class32

tooltips_class32

tooltips_class32

tooltips_class32

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