Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Обработка исключительных ситуаций без SysUtils [D6]


Страницы:   1 2 3

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]


Речь, я полагаю, не об этом. Речь о разумно написанной программе, которая не будет передавать подобные параметры.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо