![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Обработка исключительных ситуаций без SysUtils [D6]
Bopros © (2006-01-14 22:48:00)Необходимо обработать исключительную ситуацию без использования модуля SysUtils, вот элементарный пример, который выдаёт Runtime error 200:
program Project1;
uses
Windows;
var b:integer;
begin
try
b:=trunc(b/0);
except
MessageBox(0,'123','321',mb_ok);
end;
end.
NightAngel (2006-01-21 02:09:00) [1]> Игорь Шевченко © (19.01.06 11:08) [50]
Статей не встречал, но вот как это можно сделать в простейшем случае:
program TestSEH;
uses
Windows;
type
ValueReg=record
SafeEip:DWORD; // Метка, куда нужно будет попасть после исключения
PrevEsp:DWORD; // Предыдущее значение ESP
PrevEbp:DWORD; // Предыдущее значение EBP
end;
const
ExceptionContinueExecution = 0;
ExceptionContinueSearch = 1;
ExceptionNestedException = 2;
ExceptionCollidedUnwind = 3;
Caption : PChar = 'SEH Тест' + #0;
NotOccured : PChar = 'Всё в порядке!' + #0;
Occured : PChar = 'Исключение!' + #0;
var
SEHReg : ValueReg;
Text : PAnsiChar;
label
SafePlace;
{$O+}
function Exception_Handler(
ExceptionRecord:PExceptionRecord;
EstablisherFrame:Pointer;
ContextRecord:PContext;
DispatcherContext:Pointer):DWord;cdecl;
begin
ContextRecord.Eip := SEHReg.SafeEip;
ContextRecord.Esp := SEHReg.PrevEsp;
ContextRecord.Ebp := SEHReg.PrevEbp;
// Рестарт после инструкции вызвавшей исключение
Result := ExceptionContinueExecution;
end;
{$O-}
begin
Text := Occured;
asm
push offset Exception_Handler // Смещение на наш обработчик
push dword ptr fs:[0] // Адрес следующей структуры ERR
mov fs:[0], esp
mov SEHReg.SafeEip, offset SafePlace
mov SEHReg.PrevEsp, esp
mov SEHReg.PrevEbp, ebp
end;
asm
xor eax, eax // Вызываем исключение (код защищенный обработчиком)
mov [eax], 1
end;
Text := NotOccured;
SafePlace:
asm
pop dword ptr fs:[0] // Восстановить структуру ERR в FS:[0]
add esp, 4 // Очищаем стек
end;
MessageBox(0,Text,Caption,MB_OK or MB_ICONINFORMATION);
end.
EIP,ESP,EBP можно не сохранять в глобальной переменной, а помещать их значения в стек. И еще, обязательными полями являются только запись EXCEPTION_REGISTRATION (указатель на предыдущую запись и указатель на наш обработчик), но никто не запрещает перед указателем на обработчик поместить в стек и другие параметры, в частности, safeplace и EBP. Стандартов здесь нет. В Delphi, кстати, метка, куда нужно будет попасть после исключения, специально не сохраняется, а используется комбинация из 2-3-х jmp-ов. Примерно вот так:
_try // Устанавливаем SEH
push _jmp_to_SEH // В стек помещается не сам обработчик, а jmp на него
push fs:[0]
mov fs:[0],esp
...
_except: // :=safeplace
...
_end:
pop fs:[0]
add esp,4
jmp _continue // Обходим прыжки для продолжения
_jmp_to_SEH:
jmp @_except_handler // Переход на универсальный обработчик
jmp _except // Сюда обработчик возвращает управление
_continue:
...
function @_except_handler(...):integer; // Универсальный обработчик
asm
...
mov edx,[esp+8] // Адрес EstablisherFrame := Exception_Registration
mov edx,[edx+4] // Адрес обработчика := _jmp_to_SEH
add edx,5 // Прибавляем длину инструкции jmp и получаем адрес инструкции jmp _except для возврата
...
end;
Удачи!
Игорь Шевченко (2006-01-19 11:08:00) [2]Встречный вопрос - никто не встречал статьи по организации обработки SEH в Delphi ? Интересна именно обработка SEH, а не Delphi'йских исключений - это все-таки разница, с доступом к EXCEPTION_POINTERS, CONTEXT, возможностью задавать EXCEPTION_CONTINUE_SEARCH, EXCEPTION_CONTINUE_EXECUTION.
NightAngel (2006-01-19 03:45:00) [3]> Bopros (18.01.06 09:40) [16]
Если Вы хотите использовать только WinApi можете установить конечный обработчик исключений применяя функцию SetUnhandledExceptionFilter().
Как правило, обработчик устанавливается в основном потоке как можно ближе после точки входа программы. Поэтому он охватывает целую программу от точки входа до завершения. Нет никакой потребности удалять обработчик после завершения - это будет сделано автоматически Windows. Если же Вы хотите обрабатывать исключительные ситуации в каком-либо потоке, то Вам придется использовать SEH (каждый поток в вашей программе имеет различное значение сегментного регистра FS:[0], поэтому обработчик особых ситуаций будет определенным потоком). И ничего вырезать и прикручивать не нужно.
Defunct (2006-01-19 03:10:00) [4]> Bopros
> пишу приложение на WinAPI
А почему бы не подключить SysUtils и не писать себе дальше на WinAPI?
Ведь объем добавляемый к exe файлу будет не так велик в пределах ~30kb.
если уж так невмоготу его использование, тогда последуйте совету Игоря Шевченко.. Сделайте InitExceptions, которую можете вырезать из SysUtils.
Джо (2006-01-18 17:52:00) [5]В общем, убедили меня в том, в чем я уже и был убежден :)
Всего лишь был ответ на [17], возможно, немного более эмоциональный, чем того стоила проблема.
В свое время именно эта функция мне немало попортила крови, так как понадеялся именно на анализ возвращаемого значения с последующим GetLastError. А до никакого GetLastError дело не доходило и в логах было все чисто :) А имя файла, секция и ключ как раз и брались из внешнего потока данных, в котором, как оказалось впоследствии, и была ошибка.
Игорь Шевченко (2006-01-18 17:40:00) [6]Джо © (18.01.06 17:29) [44]
Руссинович с Соломоном в своей книге "Внутреннее устройство Windows 2000" обсуждают причину появления синего экрана смерти. Ход рассуждений примерно такой - системе неизвестно, какие последствия повлечет ошибка, поэтому, во избежание, система просто останавливается, дабы не усугублять ситуацию. При этом проверок в системе, как ты понимаешь, предостаточно.
На пользовательском уровне эта логика тоже является разумным компромиссом, и исключения имеют смысл только при обработке данных.
Leonid Troyanovsky (2006-01-18 17:31:00) [7]
> Джо © (18.01.06 17:11) [38]
> Зачем честной программе завершаться после такого пустяка?
После подобных ошибок, вообще, трудно быть уверенным в том, что
и сама обработка исключения пройдет без исключений.
Т.е., без обработки автору можно было б рассчитывать на пару пинков,
а с оной - на повреждения средней тяжести ;)
--
Regards, LVT.
Джо (2006-01-18 17:29:00) [8]> [42] Игорь Шевченко © (18.01.06 17:21)
Мы говорим практически об одном и том же, просто я, наверное, не очень внятно изъясняюсь (горячий денек сегодня).
Ну, вот даже если брать мой пример с неверным параметром. Обработка исключений в данном случай могла бы именно помочь программисту найти ошибку в программе. Например, система сложная, а отладка ведется по анализу лог-файлов.
VirEx (2006-01-18 17:26:00) [9]да что вы спорите, покопайтесь в InitExceptions и вытащите код
Игорь Шевченко (2006-01-18 17:21:00) [10]Джо © (18.01.06 17:18) [41]
> 2. А зачем тогда вообще обработка исключений? Знай, пиши
> всегда правильно и ошибочных ситуаций возникать не будет.
>
Для того, чтобы обрабатывать ситуации с неверными входными данными. И только для этого. Ошибки программиста обработка исключений не исправит, а ошибки данных вполне можно исправить, например, введя их еще раз.
> 1. Никто не помешает вызываемой функции возбуждать исключение
> даже при правильном параметре (в том числе, и в результате
> ошибки человека, писавшего эту функцию).
В таком случае ошибка укажет программисту, что надо исправить. Пользователю ошибка программиста бесполезна.
Джо (2006-01-18 17:18:00) [11]> [37] Игорь Шевченко © (18.01.06 17:09)
> Джо © (18.01.06 16:37) [31]
> Джо © (18.01.06 16:53) [33]
>
> В этом случае обработка исключений мало чем поможет, если
> передан неправильный параметр.
Эту функцию я привел для примера. Но:
1. Никто не помешает вызываемой функции возбуждать исключение даже при правильном параметре (в том числе, и в результате ошибки человека, писавшего эту функцию).
2. А зачем тогда вообще обработка исключений? Знай, пиши всегда правильно и ошибочных ситуаций возникать не будет.
Повторюсь, что ту функцию я привел как самый простой пример, что функции из Windows API МОГУТ возбуждать исключения. В т.ч., и недокумментированные.
Владислав (2006-01-18 17:16:00) [12]
> Джо © (18.01.06 17:11) [38]
>
> ShowMessage ('Function call failed.');
Зачем пользователю программа, которая делает неверные вызовы функций, а потом об этом сообщает? :о)
Игорь Шевченко (2006-01-18 17:15:00) [13]Джо © (18.01.06 17:11) [38]
procedure TForm1.Button1Click(Sender: TObject);
begin
GetWindowThreadProcessId (Handle, Pointer(123456768));
end;
Запусти
> Зачем честной программе завершаться после такого пустяка?
> ;)
Чтобы программист исправил ошибку.
Джо (2006-01-18 17:11:00) [14]> [36] Leonid Troyanovsky © (18.01.06 17:08)
> Дык, он и так нарушается.
> После AV в дебрях ntdll честной программе остается лишь
> завершиться.
procedure TForm1.Button1Click(Sender: TObject);
begin
try
WriteProfileString('',nil,nil)
except
ShowMessage ('Function call failed.');
end;
ShowMessage ('Here we are!');
end;
Зачем честной программе завершаться после такого пустяка? ;)
Игорь Шевченко (2006-01-18 17:09:00) [15]Джо © (18.01.06 16:37) [31]
Джо © (18.01.06 16:53) [33]
В этом случае обработка исключений мало чем поможет, если передан неправильный параметр. Потому обработка исключений в данной конкретной ситуации есть бессмысленное замусоривание кода.
Leonid Troyanovsky (2006-01-18 17:08:00) [16]
> Джо © (18.01.06 16:37) [31]
> неверного параметра) возбуждает исключение. Соответственно,
> обработка может понадобиться, т.к. в противном случае нарушается
> ход выполнения программы.
Дык, он и так нарушается.
После AV в дебрях ntdll честной программе остается лишь завершиться.
Вот, собс-но, и вся обработка.
--
Regards, LVT.
Владислав (2006-01-18 17:03:00) [17]
> Джо © (18.01.06 16:53) [33]
Заметьте, я этого не говорил. И тем более я не пытаюсь выкидывать обработку исключений из программ на Delphi.
А если говорить о конкретном, а не на отвлеченные темы...
Что нужно было бы написать в обработчике исключения, возникшего в приведенном Вами в 27 посте примере? И что нельзя было бы написать до вызова этого примера, чтобы такое исключение не возникло?
Bopros (2006-01-18 16:56:00) [18]
> Игорь Шевченко © (18.01.06 13:31) [20]
>
> Владислав © (18.01.06 12:31) [19]
>
> InitExceptions надо прикручивать
а подробнее можно?
интересует что неправильно сдела относительно статьи
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=833
http://rafb.net/paste/results/PKDbFs88.html
http://rafb.net/paste/results/sD4v1d94.html
Джо (2006-01-18 16:53:00) [19]> [32] Владислав © (18.01.06 16:50)
> Речь о разумно написанной программе,
> которая не будет передавать подобные параметры.
Да-дад. И еще раз: дадад.
Осталось вам открыть только один секрет: как писать программы без ошибок. И, попутно, отменить обработку исключительных ситуаций, которая, оказывается, не нужна, ибо надо писать программы так, чтобы они выполнялись без ошибок.
Владислав (2006-01-18 16:50:00) [20]
> Джо © (18.01.06 16:37) [31]
Речь, я полагаю, не об этом. Речь о разумно написанной программе, которая не будет передавать подобные параметры.