Что нового

Реализация подобия SEH в AutoIt - Обработка ошибок

firex

AutoIT Гуру
Сообщения
943
Репутация
207
AutoIt: 3.3.12.0, 3.3.9.4, 3.3.8.X, 3.3.6.X
Версия: 0.2.2

Категория: Вспомогательные функции

Описание: Добавляет возможность регистрирования Callback-функции вызываемой в момент обнаружения ошибки при выполнении скомпилированного скрипта. Позволяет проигнорировать ошибку и продолжить выполнение.

Список функций:
Код:
; #CURRENT#
; OnAutoItErrorRegister( [ $sFunc ] )
; OnAutoItErrorUnRegister()

Пример:
Код:
#Include <SEH.au3>
OnAutoItErrorRegister( '__Example_OnError' ) ; >>> __TRY {
	For $Idx = 1 To 5 Step 1
		$PlsError[1] = $PlsError[2]
	Next
OnAutoItErrorUnRegister() ; >>> }

Func __Example_OnError( $pErrMsg ) ; >>> __EXCEPT {
	Local $tError, $aRes
	; *
	$aRes = DllCall("kernel32.dll", "int", "lstrlenW", "ptr", $pErrMsg)
	If @Error Or Not $aRes[0] Then _
		Return 0 ;Terminate script

	$tError = DllStructCreate( "wchar Msg[" & $aRes[0] & "]", $pErrMsg )
	If @Error Then _
		Return 0 ;Terminate script
	; ---

	If MsgBox( 5, 'Custom Au3Error callback', DllStructGetData( $tError, 'Msg' ) ) = 2 Then _
		Return 0 ;Terminate script

	; ---
	Return 1 ;Continue execute
EndFunc ; >>> }

Файлы: SEH.au3, SEH_beta.au3
(с форума можно будет качать только release-версии)

Лог обновлений:
Код:
[0.3.3](beta) - 14.02.15
{+} Попытка заставить работать переход к указанной строке для всех типов исключений

[0.3.2](beta) - 14.02.15
{*} Переименованы функции ( __TRY / __ENDTRY )
{*} Изменен формат возвращаемого значения ( < 0; = 0; > 0 ) 
{+} Экспериментальная* возможность перехода к указанной строке для блока __TRY( и за его пределы )
* - (Временно поддерживаются не все типы исключений)

[0.3.0](beta) - 11.02.15
{-} Поддержка только 3.3.12.0 (x86) - временно
{+} Поддержка интерпретируемой версии(Run script).
{+} Захват ошибок с флагом /ErrorStdOut
{+} Все данные распределены по аргументам обработчика (pwError, pwScriptLine, iLine)
{+} Получение реального номера строки (см. SEH_INCLUDES_LENGTH)*
{+} Получение** строки скрипта (в которой произошло исключение)
* - (библиотека SEH.au3 должна быть подключена после других)
** - (только для не скомпилированной версии)

[0.2.2] - 08.02.15
{+} Поддержка 3.3.9.4, 3.3.8.X, 3.3.6.X
{+} Обработка ошибок
{+} Продолжение/остановка выполнения скрипта

[0.0.1] - 07.02.15
{+} Игнорирование ошибок

Источник: autoit-script.ru
Автор(ы): Firex
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Для нескомпенсированного скрипта еще бы такую функцию.
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
inververs
Посмотрю, что можно сделать.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,321
firex,
Скомпилировал Ваш пример, запустил, получил сообщение:
Код:
Line 42  (File "C:\Users\...\Desktop\AutoIt v3 Script (9).exe"):


Error: Expected a "=" operator in assignment statement.
Но можно как-то узнать, что ошибка именно в строке $PlsError[1] = $PlsError[2]?
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
madmasles
Проблематично будет. Единственное, что я могу предусмотреть в будущем - относительный переход ( ибо это просчитываемо ), а вот на счет идентификации реального номера строки придется подумать. Проблема в том, что AutoIt при компиляции "склеивает" библиотеки ( Include ) и основной скрипт.

Если вы собираетесь использовать только SEH, то высчитать строку можно путем вычитания кол-ва строк из библиотеки SEH. Иначе - придется вычитать кол-во строк из всех библиотек.

Upd/
Если вы имеете ввиду текст самой строки, то посмотрю, что можно сделать. Полагаю это возможно, хоть и отключено в скомпилированной версии.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,670
Репутация
2,473
firex [?]
Если вы собираетесь использовать только SEH, то высчитать строку можно путем вычитания кол-ва строк из библиотеки SEH. Иначе - придется вычитать кол-во строк из всех библиотек.
А если сделать условием указания этой библиотеки в самом конце списка библиотек, то наверняка можно вычислить позицию её начала и считать уже от неё?
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
CreatoR [?]
А если сделать условием указания этой библиотеки в самом конце списка библиотек, то наверняка можно вычислить позицию её начала и считать уже от неё?
Единственное, что приходит в голову ( при условии, что SEH указана последней ):
-Добавляем в библиотеку строку, к примеру #SEH
-Пишем скрипт под AutoIt3Wrapper, который между этапами обработки и компиляции вычислит номер строки #SEH и создаст в шапке скрипта константу.

Еще вариант:
-Создать преднамеренное исключение и перехватить его в библиотечном обработчике.

Подумаю еще, полагаю найдется более оптимальный способ.
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
firex [?]
Подумаю еще, полагаю найдется более оптимальный способ.
Да не особо нужно правильно высчитывать номер строки, гораздо важнее это показывать вот это:

$PlsError[1] = $PlsError[2]
$PlsError^ ERROR

Error: Expected a "=" operator in assignment statement.
По этому выражению легко найти место в скриптах. А номер строки даже если и знать, то не ясно в каком include ее смотреть.
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
Небольшое обновление, список изменений добавил в лог.

На счет получения строки скрипта в скомпилированной версии: пока не в приоритете, слишком много кода придется перелопатить.
 

joiner

Модератор
Локальный модератор
Сообщения
3,470
Репутация
609
запускал пример с бета-версией библиотеки. никаких сообщений об ошибке в коде
код использовал из первого сообщения



Добавлено:
Сообщение автоматически объединено:

помимо этого в бетке есть ошибка
Код:
Func __SEH_GetIncludesLength()
        If OnAutoItErrorRegister( '__SEH_InternalCb' ) Then
                SEH_GetError  ; тут

                OnAutoItErrorUnRegister()
        EndIf
EndFunc
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
joiner
Убедитесь, что запускаете на x86 версии. Проверил еще раз - все работает.

Для запуска из под редактора можете использовать:
Код:
#Region ;**** Directives created by AutoIt3Wrapper_GUI ****
#AutoIt3Wrapper_Run_AU3Check=n
#AutoIt3Wrapper_Tidy_Stop_OnError=n
#EndRegion ;**** Directives created by AutoIt3Wrapper_GUI ****


На счет ошибки - так и должно быть.
 

joiner

Модератор
Локальный модератор
Сообщения
3,470
Репутация
609
насчет ошибки можешь пояснить почему так? интересно
запускаю на семерке х86, версия autoit - последняя стабильная
не бетка работает нормально


Добавлено:
Сообщение автоматически объединено:

что пишет редактор в логе
Код:
>Running:(3.3.12.0):C:\Program Files\AutoIt3\autoit3.exe "C:\Users\master\Desktop\Rate.au3"    
--> Press Ctrl+Alt+Break to Restart or Ctrl+Break to Stop
!>10:56:56 AutoIt3.exe ended.rc:-1073741819
+>10:56:56 AutoIt3Wrapper Finished.
>Exit code: 3221225477    Time: 8.228
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
joiner [?]
насчет ошибки можешь пояснить почему так? интересно
Таким образом происходит получение размера всех подключенных библиотек в скрипт => позволяет получить верную строку ошибки в основном скрипте ( если он скомпилирован ).

запускаю на семерке х86, версия autoit - последняя стабильнаяне бетка работает нормально
Вы брали пример из новой беты? Поменялись аргументы callback функции. Пример к бете включен в шапку UDF.
 

joiner

Модератор
Локальный модератор
Сообщения
3,470
Репутация
609
да точно. не тот пример :smile:
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,670
Репутация
2,473
Номер строки неправильный если использовать директивы AutoItWrapper.
 
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
Обновление до 0.3.2(beta). Изменения/добавления занесены в лог.

Пример к новой (beta) как обычно в шапке UDF(beta).
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,670
Репутация
2,473
firex
Как можно найти нужные адреса для добавления поддержки других версии AutoIt?
Какой алгоритм поиска?

И ещё, можно как то добавить определение ошибки "Recursion level has been exceeded"?
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,670
Репутация
2,473
И ещё, я считаю что в конечном варианте (законченный продукт), пользователю незачем отображать строку кода с ошибкой. Вместо этого, сам разработчик (получив скрин или данные ошибки) может вычислить строку ошибки используя мой стрипер (также прикрепил).
 

Вложения

  • GetErrLineCode.au3
    6.7 КБ · Просмотры: 9
Автор
firex

firex

AutoIT Гуру
Сообщения
943
Репутация
207
CreatoR [?]
Как можно найти нужные адреса для добавления поддержки других версии AutoIt?Какой алгоритм поиска?
Можно достаточно быстро выйти на обработчик путем поиска обращений к уникальной строке: "Line %d (File "%s"):" Их(обработчика) должно быть два, один выводит инфу в консоль, а второй в MessageBox. Предупрежу: они практически идентичны, без понятия зачем разработчики проделали такой копипаст.

Его начало - это в основном сбор информации об ошибке / некоторые проверки, затем вызов MessageBoxW и сразу же CleanUp-процедуры. Я перезаписывал этот регион памяти своим кодом, который вызывает установленный CallBack с некоторой информацией.

И ещё, можно как то добавить определение ошибки "Recursion level has been exceeded"?
Перепроверил - действительно, скрипт падает. На максимальном значении вложенности скрипт вызывает ошибку, однако библиотека перехватывает ее и кидает управление на CallBack, именно это вызывает переполнение стека и падение скрипта - еще один вызов функции как никак.

Можно поправить уменьшив лимит, но это не защитит глупого пользователя от рекурсии в обработчике ошибки связанной с рекурсией :smile:

И ещё, я считаю что в конечном варианте (законченный продукт), пользователю незачем отображать строку кода с ошибкой. Вместо этого, сам разработчик (получив скрин или данные ошибки) может вычислить строку ошибки используя мой стрипер (также прикрепил).
В BETA я разделил по разным аргументам текст и номер строки, но она сыра и не портирована под другие версии.

Быть может позже руки дойдут...
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,670
Репутация
2,473
firex [?]
Можно достаточно быстро выйти на обработчик путем поиска обращений к уникальной строке: "Line %d (File "%s"):"
Можно небольшую инструкцию как это корректно сделать? Очень хотелось бы покопаться в этом чтобы прикрутить и другие версии, а также чтобы оно работало и не в скомпилированном скрипте.
 
Верх