Приёмы отладки VBA-кода (на примере MS Excel)
Многие из тех, кто часто работает в MS Excel, используют книги или надстройки с VBA-макросами. Зачастую требуется доработать существующее решение, добавив новую функциональность или исправив найденный баг. В поисках места, где скрывается баг или производится нужное вычисление, можно провести немало времени, особенно если проект содержит десятки тысяч строк кода (увы, такие макросы иногда встречаются). Можно прибегнуть к текстовому поиску (например по тексту сообщения, вшитому в код), но иногда удобнее запустить макрос и прибегнуть к пошаговой отладке.
В этом посте описаны несколько приёмов, которые могут быть полезны при отладке макросов на VBA в приложениях MS Office на примере MS Excel.
1. Стандартные точки останова (breakpoint). Step-into, step-over
2. Окна Immediate ("REPL-терминал"), Locals (локальные переменные), Watches (наблюдатели)
3. Условные точки останова на базе watch expression
4. Обработка ошибок
1. Самый очевидный способ отладки - поставить точку останова в начале макроса, а затем пошагово исполнять строку за строкой, наблюдая за значениями переменных и состоянием ячеек в книге. Чтобы установить точку останова, нажмите F9 - и на строке, где находится курсор,
появится такая отметка (можно установить и кликом мышью по области слева, где красный кружок):
Теперь как только поток исполнения доберётся до этой строки, он будет приостановлен, а Вы увидите желтый указатель, указывающий на следующую инструкцию:
Многие не знают, что этот указатель можно перемещать на любой statement в пределах функции, просто перетащив мышью желтую стрелку!
Когда Вы приостановили исполнение кода, можете продолжить его исполнение пошагово, с помощью команд step-into, step-over и step-out:
* step-into (F8) - шаг вперёд. Будет выполнен код на строке под указателем, а сам указатель перемещён на следующую строку. Однако если в текущей строке есть вызов другой функции, указатель переместится внутрь этой функции
* step-over (Shift-F8) - полностью аналогичен step-into, за исключением того, что эта команда позволяет не "проваливаться" в вызов вложенных функций
* step-out (Ctrl-Shift-F8) - текущая функция будет исполнена до конца, а исполнение приостановлено в вызывающей функции. Полезна, если Вы случайно провалились в длинную функцию командой step-into
Теперь немного о том, как узнать значения переменных и иную полезную информацию.
2. В нижней части экрана VBE (Visual basic editor) Вы можете увидеть три окна:
* Immediate (терминал для выполнения кода и вывода текстовой информации)
* Locals (локальные переменные)
* Wathes (наблюдатели)
Если Вы не видите эти окна, включите их отображение в меню View
Разберём подробнее, какие возможности открывают нам эти инструменты.
Окно Immediate представляет собой REPL-терминал, в котором можно ввести выражение и запустить его нажатием Enter. Чтобы вывести результат в этот же терминал, передайте результат выражения в функцию Debug.Print (кстати, эту функцию можно вызвать и в основном коде макроса - результат так же будет выведен в консоль Immediate). В самой консоли можно воспользоваться и сокращённой версией этой команды - знаком вопроса:
Обратите внимание, что с помощью сочетаний Ctrl+Space и Ctrl+J можно вызывать окно IntelliSense , также как и в основном редакторе кода.
Окно Locals позволяет увидеть значения переменных, доступных в текущем контексте:
Например, текущее значение счётчика цикла или состав коллекции. Обратите внимание, что для объектов Collection при раскрытии отображаются значения элементов коллекции, а для словарей (Dictionary) - их ключи. Поэтому чтобы узнать значение самого элемента в словаре, нужно вычислить выражение, например такое:
dict.Items("key1")
Это можно сделать при помощи "наблюдателя" - watch expression
Выделите выражение и выполните команду Add watch... в контекстном меню (доступном с помощью правой кнопки мыши), или введите нужно выражение вручную в окне добавления наблюдателя:
Осторожно: выражение d.Item("key1") при вычислении может добавить элемент к словарю, если такой ключ в словаре отсутствует. Поэтому не забудьте удалить наблюдатель, когда он станет ненужным, иначе в дальнейшем можно провести немало времени, выясняя откуда взялся лишний элемент в словаре.
3. Условные точки останова, которые можно реализовать с помощью наблюдателей.
Вероятно, Вы обратили внимание, что в меню добавления наблюдателя помимо стандартной опции "Watch Expression" есть ещё две: "Break When Value Is True" и "Break When Value Changes". Они позволяют добиться приостановки исполнения макроса при наступлении соответствующего условия (выражение истинно, либо значение выражения изменилось). Эта возможность может оказаться особенно полезной, например, при отладке циклов. Если Вы знаете, что макрос, который в цикле обрабатывает строки на листе Excel, сталкивается с ошибкой, скажем, на строке 42, то можно избежать ручного "пролистывания" 41 предшествующей итерации, добавив выражения вида i=42 с опцией Break When Value Is True, где i - это переменная счётчика цикла.
4. Напоследок хотел бы немного рассказать об обработке ошибок в VBA.
В настройках VBE Вы можете найти выбор из трёх опций (меню Tools -> Options, вкладка General):
Break on All Errors
Break in Class Module
Break on Unhandled Errors
По умолчанию, как правило, установлена последняя опция, которая позволяет программисту обрабатывать ошибки с помощью директив On Error Goto (показать сообщение об ошибке, "прибраться за собой" - закрыть книгу или соединение) и On Error Resume Next (игнорировать ошибку и продолжать исполнение). Однако, когда Вы столкнётесь с ошибкой вида "Извините, что-то пошло не так =(", которая отображается из обработчика в On Error Goto, будет трудно определить место, где произошла ошибка. В этом случае пригодится опция Break on All Errors, которая позволит проигнорировать директивы On Error и перейти к тому месту в коде, где и произошла ошибка. В этот момент может пригодиться и окно Locals, где Вы сможете увидеть, например, текущее значение счётчика цикла, и понять, при обработке какой строки на листе Excel возникла ошибка.
Указанные опции обработки ошибок устанавливаются на уровне настроек пользователя, и не сохраняются в VBA-проекте.
Надеюсь, что эта статья окажется полезной как начинающим пользователям VBA, так и бывалым разработчикам, которые смогут узнать что-то новое.
Минутка рекламы.
В свободное время я пилю надстройку общего назначения для MS Excel на платформе VSTO. Проект доступен на гитхабе под лицензией MIT (можете свободно использовать в своих проектах, форкать и изменять под свои нужды):
Призываю неравнодушных пользователей оставить пожелания по добавлению новых функций (заводите issue на гитхабе, или пишите прямо тут в комментариях), а разработчиков, знакомых с технологией VSTO (или желающих познакомиться) - присоединяться к разработке!
Это мой первый пост на Пикабу, буду рад конструктивной критике в комментариях и ЛС.
MS, Libreoffice & Google docs
711 постов15K подписчиков
Правила сообщества
1. Не нарушать правила Пикабу
2. Публиковать посты соответствующие тематике сообщества
3. Проявлять уважение к пользователям
4. Не допускается публикация постов с вопросами, ответы на которые легко найти с помощью любого поискового сайта.
По интересующим вопросам можно обратиться к автору поста схожей тематики, либо к пользователям в комментариях
Важно - сообщество призвано помочь, а не постебаться над постами авторов! Помните, не все обладают 100 процентными знаниями и навыками работы с Office. Хотя вы и можете написать, что вы знали об описываемом приёме раньше, пост неинтересный и т.п. и т.д., просьба воздержаться от подобных комментариев, вместо этого предложите способ лучше, либо дополните его своей полезной информацией и вам будут благодарны пользователи.
Утверждения вроде "пост - отстой", это оскорбление автора и будет наказываться баном.