- •Создание динамических структур данных
- •Встроенный динамический класс Collection
- •Создание собственных динамических классов
- •Обертывание коллекции vba
- •Несколько слов об api, Win32, dll
- •Вызов функций и оператор Declare
- •Две кодировки ansi и Unicode
- •Два языка: c и vb. Различия при вызове функций
- •Соответствие между простыми типами данных
- •Структуры языка c и тип, определенный пользователем, в языке vba
- •Об описателях языка c и объектах Windows
- •Void функции языка c
- •Вызов аргументов по ссылке ByRef и по значению ByVal
- •Строковые аргументы при вызове функций Win32 api
- •Примеры работы с Win32 api функциями
- •Работа с окнами
- •Характеристики окружения
- •Вызов функций Win32 api, работающих в Unicode кодировке
- •Обработка ошибок, возникающих при вызове функций Win32 api
- •Функции api и вызов Callback функций
- •Функции высших порядков и конструкция AddressOf
- •Функции перечисления Win32 api
- •Функция EnumWindows
- •Еще один пример работы с функцией EnumWindows
- •Функции Win32 api для работы с таймером
- •Функция SetTimer
- •Функция обратного вызова TimerProc
- •Функция KillTimer
- •Пример создания, работы и удаления таймера
- •Классы как обертка вызовов функций Win32 api
- •Построение класса "ВашТаймер"
- •Использование класса ВашТаймер
- •Операторы
- •Операторы и строки
- •Оператор комментария
- •Присваивание
- •Оператор Let
- •Оператор lSet
- •Оператор rSet
- •Оператор Set
- •Управляющие операторы
- •Условный оператор If Then Else End If
- •Оператор выбора Select Case
- •Цикл For Next
- •Цикл Do...Loop
- •Цикл While...Wend
- •Цикл For Each...Next
- •Работа с каталогами, папками и файлами
- •Изменение текущего диска: оператор ChDrive
- •Изменение текущего каталога (папки): оператор ChDir
- •Создание каталога (папки): оператор MkDir
- •Переименование каталогов (папок) и файлов: оператор Name
- •Удаление каталога (папки): оператор RmDir
- •Установка атрибутов файла: оператор SetAttr
- •Копирование файлов: оператор FileCopy
- •Удаление файлов: оператор Kill
- •Прочие операторы
- •Операции с одним объектом. Оператор With
- •Операции
- •Работа с числовыми данными
- •Математические функции
- •Работа со строками
- •Сравнение строк
- •Сравнение с образцом
- •Основные операции над строками
- •Новые функции для работы со строками
- •Функция InStrRev - поиск последнего вхождения подстроки
- •Функция Replace - замена всех вхождений подстроки
- •Удаление подстроки
- •Разбор строки. Функции Split, Join и Filter
- •Преобразование строки в массив. Функция Split
- •Сборка элементов массива в строку. Функция Join
- •Фильтрация элементов массива. Функция Filter
- •Несколько модификаций встроенных функций
- •Замена, основанная на шаблоне. Функция WildReplace
- •Замена разных символов строки. Функция CharSetReplace
- •Фильтрация, основанная на шаблоне. Функция WildFilter
- •Разбор строки, допускающей разные разделители ее элементов. Функция WildSplit
- •Работа с датами и временем
- •Присваивание значений
- •Встроенные функции для работы с датами
- •Определение текущей даты или времени.
- •Вычисления над датами
- •Функция Timer и хронометраж вычислений
- •Некоторые встроенные функции
- •Функции проверки типов данных
- •Преобразование типов данных
- •Форматирование данных. Функции группы Format
- •Функция Format.
- •Другие функции форматирования
- •Описание и создание процедур
- •Классификация процедур
- •Синтаксис процедур и функций
- •Функции с побочным эффектом
- •Создание процедуры
- •Создание процедур обработки событий
- •Вызовы процедур и функций Вызовы процедур Sub
- •Вызовы функций
- •Использование именованных аргументов
- •Аргументы, являющиеся массивами
- •Конструкция ParamArray
- •Задача о медиане
- •Пользовательские функции, принимающие сложный объект Range
- •Рекурсивные процедуры
- •Деревья поиска
- •Класс TreeNode
- •Класс BinTree
- •Работа со словарем
- •Отладка
- •Написание надежных программ
- •Искусство отладки
- •Средства отладки
- •Панель отладки и команды меню
- •Окна наблюдения
- •Окно локальных переменных - Locals
- •Окно проверки - Immediate
- •Окно контрольных выражений - Watch
Обработка ошибок, возникающих при вызове функций Win32 api
Как мы уже говорили ранее, не бывает программ без ошибок. Если ошибка возникает при выполнении кода процедур и функций VBA, - ошибка периода выполнения (run time error), - то появляется окно сообщения об ошибке. Если ошибка периода выполнения появляется при работе функции Win32 API, то прерывания работы программы не происходит, окно сообщения об ошибке не появляется. Вместо этого функция возвращает значение 0 в качестве результата, свидетельствующее об ошибке периода выполнения. Тем не менее, большинство функций Win32 API сохраняют информацию о возникшей ошибке. Эту информацию можно получить стандартным способом, используя VBA объект Err. Свойство LastDLLErr этого объекта возвращает номер последней ошибки, возникшей в DLL. К сожалению, сам по себе номер мало что говорит. Необходимо знать описание ошибки, соответствующее этому номеру. Частично причину ошибки можно понять по имени константы, которую можно найти в уже неоднократно упоминавшемся файле Win32API.txt, используемом в API Viewer. Опять-таки, к сожалению, возможные значения констант приводятся независимо от функций, в которых они возникают. И, несмотря на то, что все такие константы начинаются со слова ERROR найти константу по ее значению не так то просто. Можно, конечно, воспользоваться возможностью создания базы данных по текстовому файлу и организовать специальный запрос, позволяющий найти имя константы по ее значению. Естественно, что лучше всего иметь полную информацию об используемых функциях Win32 API, включающую, в том числе, и сведения о возможных ошибках периода выполнения данных функций. Эту информацию можно найти, если под рукой есть подходящая литература, например, справочник программиста Win32, или поискать на упоминавшемся сервере Microsoft для разработчиков.
Естественно, что пример ошибки времени выполнения в процессе работы DLL у нас уже под рукой. Нам и изобретать его не было необходимости. Как Вы помните, в последнем примере мы сетовали на возникновение подобной ошибки в процессе поиска описателя окна по его заголовку при вызове функции FindWindowW, работающей в Unicode кодировке. Давайте вернемся к этому примеру и попробуем обработать эту ошибку. В раздел объявлений ранее созданного модуля Unicode мы добавили объявление констант и функций и теперь он выглядит так:
Option Explicit
Public Const ERROR_INVALID_NAME = 123&
'Объявление вызываемых функций
Public Declare Function FindWindowA Lib "user32" _
(ByVal lpClassName As String, ByVal lpWindowName As String) As Long
'Функции в Unicode кодировке
'Тип string заменен на Any. Передача аргумента по ссылке
Public Declare Function FindWindowW Lib "user32" _
(lpClassName As Any, lpWindowName As Any) As Long
Public Declare Function GetWindowText Lib "user32" Alias "GetWindowTextW" _
(ByVal hwnd As Long, lpString As Any, ByVal cch As Long) As Long
Public Declare Function SetWindowText Lib "user32" Alias "SetWindowTextW" _
(ByVal hwnd As Long, lpString As Any) As Long
Public Declare Function GetActiveWindow Lib "user32" () As Long
Public ArCapt() As Byte 'Объявление динамического массива
Приведем теперь процедуру, в которой вызывается функция FindWindowW, приводящая к ошибке периода выполнения:
Public Sub WorkWithApiErr()
Dim Res As Long
Dim capt As String 'Заголовок
Dim HandleW As Long 'Описатель окна
'Поиск окна по заголовку
capt = "DocOne6 - Microsoft Word"
ArCapt = capt & vbNullChar
Debug.Print ArCapt
HandleW = FindWindowW(0&, ArCapt(0))
If HandleW > 0 Then 'OK
Debug.Print HandleW
Else: MsgBox ("Не могу корректно вызвать UniCode FindWindowW")
If Err.LastDllError = ERROR_INVALID_NAME Then
Debug.Print "Не корректно задано имя при вызове Unicode
FindWindowW функции!"
End If
End If
'Еще один эксперимент: вначале получим заголовок активного окна,
'затем найдем окно по заголовку, работая в Unicode кодировке.
HandleW = GetActiveWindow()
'Получить заголовок окна
ArCapt = VBA.String$(128, vbNullChar)
Res = GetWindowText(HandleW, ArCapt(0), 128)
If Res > 0 Then 'OK
Debug.Print ArCapt
Else: MsgBox ("не получен заголовок окна")
End If
ArCapt = VBA.Left(ArCapt, Res)
HandleW = FindWindowW(0&, ArCapt(0))
If HandleW > 0 Then 'OK
Debug.Print HandleW
Else: MsgBox ("Не могу корректно вызвать UniCode FindWindowW")
If Err.LastDllError = ERROR_INVALID_NAME Then
Debug.Print "Не корректно задано имя при вызове Unicode
FindWindowW функции!"
End If
End If
End Sub
Пример 6.6. (html, txt)
Приведем результаты печати , появившиеся в окне отладки при выполнении этой процедуры:
DocOne6 - Microsoft Word
Не корректно задано имя при вызове Unicode FindWindowW функции!
Microsoft Visual Basic - DocOne6 [running] - [Unicode (Code)]
Не корректно задано имя при вызове Unicode FindWindowW функции!
Прокомментируем теперь работу программы и полученные результаты:
-
Вначале мы попытались найти окно с заведомо существующим заголовком, - окно документа, содержащего тестовые примеры. В процессе работы функции Win32 API FindWindowW возникла ошибка периода выполнения, функция вернула нулевой результат. Ошибка была обработана, и как показывает константа ERROR_INVALID_NAME, причиной является ошибка в задании имени (передаваемый формат в виде массива байтов не годится для цели поиска и сравнения строк), о чем свидетельствует отладочная информация.
-
Далее проводится еще один эксперимент на ту же тему. Для активного окна находится заголовок, используя функцию GetWindowTextW, возвращающую строку в виде массива байтов. Тут же этот массив используется для поиска окна по заголовку. Однако ничего не помогает и снова при поиске окна возникает ошибка. Она обрабатывается, о чем выдается соответствующее сообщение.