Не так уж и давно столкнулся с пренеприятнейшей ошибкой AV при работе с Indy. Если бы дело касалось сугубо меня я бы, не сильно переживая, переписал бы за часик код под Synapse и жил бы счастливо, но было оговорено заранее — вся работа с HTTP через Indy. Бился над ошибкой два дня с переменным успехом. В итоге ошибка вообще стала проявляться как-то хаотично — повторяю тика-в-тику все действия в программе и один раз есть AV второй раз — нету. В общем жуть да и только. Вообще я стараюсь со своими проблемами часто друзей и знакомых не доставать обычно попадал SeregaAltmer и то потому, что давненько знакомы — можно и подоставать =), а тут всё-таки решил попросить помощи потому как мозг закипал конкретно. Первый кто пришел на ум по части поиска и обработки исключений в Delphi — GunSmoker. Вот он-то и посоветовал мне воспользоваться madExcept‘ом, за что ему (Александру) — большое спасибо, т.к. с того момента для меня практически отпала проблема поиска ошибок в коде, приводящих к самым различным последствием. Ну, а что бы и у Вас не было проблем с отловом AV в Ваших проектах я решил сегодня немного поделиться своим скромным опытом работы с madExcept.
Что из себя madExcept?
madExcept — это трейсер исключений в ваших Delphi-проектах. Смысл работы инструмента сводится к следующему: каждый раз как в Вашей программе происходит исключение MadExcept его перехватывает, обрабатывает, собирает максимум полезной информации и выдает Вам в виде удобного багрепорта.
Но сказать так и закончить пост — это значит практически ничего не сказать про madExcept. Давайте посмотрим, что этот инструмент может на деле — проведем, так сказать, маленький тест-драйв =) Все же практический пример использования будет нагляднее, чем сухое перечисление всех опций инструмента.
Проект с madExcept.
Итак, качаем бесплатную версию инструмента тут. Устанавливаем и запускаем Delphi. Создаем новый проект и в меню Project жмем опцию «madExcept settings…«:
Жмем на опцию и в открывшемся окне настроек инструмента ставим галочку «enable madExcept»:
Теперь, если вы посмотрите в исходник проекта, то увидите, что в списке uses на первом месте появились сразу несколько новых модулей, имя которых начинается с «mad..». Собственно, пока простого включения использования madExcept нам будет достаточно, чтоб взглянуть на его работу.
Теперь напишем, что-нибудь в проекте такое из-за чего 100% вылетит птичка исключение, например, такое:
procedure TForm3.FormCreate(Sender: TObject); var S1, S2: TStringStream; begin S1.LoadFromStream(S2) end;
Тут к гадалке не ходить — будет AV, а нам сейчас только этого и надо. Запускам проект. Если бы мы не включили madExcept мы бы получили что-то наподобие вот такого сообщения:
Что бы мы могли сказать про ошибку? Что это AV, произошедший где-то в программе, а вот где произошла ошибка — это уже надо копаться в коде. С MadExcept все становится намного проще. В результате возникновения ошибки мы получаем вот такое удобное сообщение:
Здесь мы уже можем:
- продолжить выполнение приложения
- перезапустить приложение
- остановить работу приложения
- отправить багрепорт на почту
- сохранить багрепорт в файл
- просмотреть багрепорт
- general — общая информация о компьютере на котором запускалась программа: кто пользователь, его привилегии, время возникновения ошибки, информация о ЦП, класс исключения (в нашем случае это EAccessViolation) и сообщение об исключении (то самое, которое показана в первом скрине с ошибкой без использования madExcept’а).
- call stack — эта вкладка сегодня для нас будет наиболее полезна. Здесь содержится информация по адресам и, что самое важно по модулям и методам в результате вызова которых произошло исключение. О содержимом этой вкладки мы ещё поговорим ниже.
- modules — список модулей, которые были загружены ОС в момент возникновения ошибки.
- processes — процессы, запущенные в ОС в момент возникновения ошибки.
- hardware — основное железо компьютера на котором была запущена программа
- cpu regs — регистры ЦП
- stack dump — дамп памяти
- disasm — дизасемблированый код программы в месте возникновения исключения.
try // тут ваш код except HandleException end;
После этого, если в потоке возникнет исключение, то madExcept вам его обработает и выдаст отчёт.
Пара слов о настройках madExcept
На скринах работы инструмента я постарался вывести Вам аксимум возможностей инструмента. Однако Вы можете настроить вид отчёта и способы его отправки как вам будет угодно. Так, например, на странице «exception box settings» Вы можете настроить внешний вид окна с исключением — включить/отключить кнопки:
А на странице «bug repotr settings» настроить содержимое отчёта об ошибке — убрать ненужные вкладки, указать форму отчёта по вызовам, размер дизасемблированного участка и т.д.:
Также Вы можете настроить фильтры исключений, задать Email на который будут слаться багрепорты, разрешить отправку скринов с программой и т.д. В общем, если расписывать каждую опцию, думаю потребуется ещё один пост в блоге.
Что можно в целом сказать по поводу madExcept? Поработав с ним некоторое время, пусть и достаточно поверхностно, могу сказать, что инструмент этот мне очень понравился. Не могу сказать, что он «самый-самый» и вообще, т.к. по большому счёту с другими трейсерами исключений дел особых не имел, но то, что madExcept очень помогает избавиться от багов в проектах в минимальный срок и с минимальными усилиями — для меня это стало фактом.
Ну и раз уж я решил закончить пост таким образом, то не могу пройти мимо ещё одного похожего инструмента — EurekaLog. Что касается использования EurekaLog, то информацию по нему Вы можете найти в блоге e GunSmoker‘а — там информации предостаточно.
Думаю, что для первого раза информации по инструменту хватит. Если Вы ещё не использовали madExcept — скачайте и испробуйте его в работе, если уже работали, но отказались от использования — тоже нормально =) Расскажите почему отказались и в пользу какого инструмента? Думаю, что как положительные так и отрицательные отзывы об инструменте будут полезны для читателей.
Отличный пост! Как раз был необходим такой компонент.
Спасибо! Интересная и самое главное очень полезная вещь. Интересует вот что, целесообразность использования этого дополнения в готовом приложении, в том смысле что на этапе разработки всегда бывают ошибки, но ошибки могут возникнуть когда приложение отошло конечному пользователю, так вот вопрос какие последствия могут возникнуть если оставить это дополнение в релизе программы (скорость работы, размер приложения, потребляемое ОЗУ)?
Не раскрыто как madExcept помог найти причину «неуловимого» AV при работе с Indy
Может я криво что поставил, но включение модуля не добавляет юниты к файлу. И даже если я это делаю вручную, ошибка стандартная =(
Эх, на сайте убрали бесплатную версию….
Может кто то выложит?
m1sclick, да ничего не убрали. Вот он http://madshi.net/madCollection.exe бесплатно для некоммерческого использования
Keeper, модули добавляются в dpr-файлик, а именно добавляются вот эти модули madExcept’а: madExcept, madLinkDisAsm, madListHardware, madListProcesses, madListModules,
Ага, добавились. Забавно, что madExpert работает при исключениях самой bds, а вот мои не ловит )
Keeper, в основной программе madExcept отлавливает все исключения (например, в статье рассмотрен пример с AV), если же madExcept’у надо отловить исключения в потоках, dll-ках и т.д. — тогда надо использовать try..except
Vlad, никаких dll, обычный проект. Галочку в enabled поставил. Delphi XE. try..except ведь мешать не должен?
Keeper, если простой проект, то try…except..end не нужен. Либо, если уж хочется с try, то код должен быть таким (по примеру из поста, но с try):
uses
…. madExcept ;
type
TForm4 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form4: TForm4;
implementation
{$R *.dfm}
procedure TForm4.FormCreate(Sender: TObject);
var S, S2: TStringStream;
begin
try
S.LoadFromStream(S2);
except
HandleException; {!!!!!!!!!!!!!!!!!!!!!!!}
end;
end;
ААА, HandleException. Спасибо! Шикарная вещь, буду смотреть )
Keeper, не за что =) Разработка-то не моя — я только поделился информацией
Vlad, у меня вопрос: чтобы madExpert показывал место возникновения исключения в коде, нужно ли собирать исполняемый файл с включением отладочной информации и созданием map-файлов?
Я пользуюсь JvExceptionDialog из библиотеки JVCL, но нигде еще не видел сравнительной таблицы по возможностям EurekaLog, madExpert и JvExceptionDialog. Чем не тема для очередного поста?
> Чем не тема для очередного поста?
Такое должен писать человек, хорошо знакомый с тремя инструментами. А где такого возьмёшь, кроме самих разработчиков этих инструментов (которые, само собой, хорошо в этом разбираются и знают конкурентов)? Но обзор тогда будет явно перекошен в сторону кого-то одного.
Кстати, есть ещё крайне малоизвестный и редко обновляемый Exception Magic от нашего разработчика.
Странный какой-то компонент. Это для тех, кто не умеет пользоваться отладчиком? Ни разу не встречал проблемы при отладке AV.
А если за него ещё и деньги платить — в помойку его!
Трассировщики исключений в первую очередь предназначены для внедрения в программу, которая будет работать на конечной машине клиента, где отладчика нет (имеется в виду коробочный софт, а не корпоративное ПО).