Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
20-05-2004 11:45
to Kate:
Попробуйте использовать подмену обработчика исключений:
..........
type
P_EXCEPTION_POINTERS = ^ EXCEPTION_POINTERS;
function MainFilter(P: P_EXCEPTION_POINTERS): integer; stdcall;
begin
Result := 0; // показывать системный диалог
// обработка возникших исключений
case P.ExceptionRecord.ExceptionCode of
EXCEPTION_ACCESS_VIOLATION:
begin
end;
EXCEPTION_DATATYPE_MISALIGNMENT:
begin
end;
else
begin
// можно данные скинуть в лог файл
MessageBox(0, 'MainFilter','Error', MB_OK );
Result := 1; // не показывать системный диалог
end;
end;
end;
Перед созданием потока произвести подмену обработчика:
begin
......
SetUnhandledExceptionFilter(@MainFilter);
TYourThread.Create(False);
.....
end;
Kate, я перестаю понимать, чего вы хотите. Как обрабатываются исключения в главной нити, вы, судя по всему, хорошо представляете, и знаете, что никакого чуда в OnException нет. Вы также не хуже меня знаете, что VCL работает только в основной нити, а обработка исключений в вашей нити целиком на вашей совести. Если исключение, возникшее в нити, не снято, обработкой исключения начинает заниматься операционная система, а у неё свои взгляды на то, как его нужно обрабатывать. Например, в линии NT система прежде всего заботится о том, чтобы не нарушить работу других программ, поэтому с той программой, которая сгененрировала исключение, система особо не церемонится - сама, мол, виновата. И как бы вы ни старались, запретить системе перехватывать любые исключения можно только одним способом - поместить весь код целиком в try/except. И в неглавной нити за вас это никто не сделает. Весь вопрос только в том, как вы это оформите. Можно даже сделать у объекта нити событие, которое возникает, когда управление передаётся в главный Except. Можно даже сделать так, чтобы при наступлении этого события вызывался тот же обработчик, что и для Application.OnException. Только это всё придётся писать самостоятельно. Если вы ищете готовые средства, должен вас разочаровать - их нет.
Антону Григорьеву:
Не придирайтесь к словам. Под необработанным исключением я, разумеется, подразумевала необработанное программистом исключение. И как работает Application.OnException я тоже не вчера узнала. И ненормальным его никто не называл. Он абсолютно нормален, но только для главного потока. Из нити в него исключения не передаются. Вообще говоря, если в нити возникло исключение, и оно не обработано (программистом), то поток просто завершает свою работу. Но не всегда! Иногда (и кто бы знал, при каком стечении обстоятельств это происходит) выдается сообщение об ошибке. Главный поток и остальные нити шуршат, как ни в чем не бывало, а эта зараза ждет, когда я "ОК" нажму. Так вот от этой неприятности и хочется избавиться.
Для RIVco:
Сначала выучите матчасть, прежде чем меня просвещать. Специально для тех, кто в танке, повторяю: тот код, который пишет программист, VCL заключает в try/except, и когда возникает исключение, не обработанное этим кодом, управление передаётся в этот except, откуда и происходит вызов OnException. На всякий случай повторяю ещё раз: вызов OnException есть результат выполнения блока except, но не того, который написан автором программы, а того, который содержится в VCL. Именно это я и сказал в своём предыдущем посте. И это не противоречит результатам вашего эксперимента. А чтобы не быть голословным, советую вам заглянуть в модуль Forms и посмотреть, во-первых, код метода TApplication.HandleException, который вызывает OnException, а во-вторых, TApplication.WndProc, из которого вызывается HandleException, и убедиться, что этот вызов сделан изнутри блока except. Так что это я вам должен желать успехов в деле, которое для вас оказалось и в самом деле трудным.
А вообще, картина получается нерадостная. Сначала вы посоветовали использовать OnException, не заметив, что речь в вопросе идёт не о главном потоке и что Kate уже написала, что Application.OnException ей не подходит. Затем вы прокомментировали мой ответ - и опять не в тему. Может, в следующий раз, перед тем как написать ответ, вы всё-таки хотя бы чуть-чуть подумаете?
Григорьеву Антону:
try except - это как раз и есть обработанное исключение и из блока except вы не получите выполнения Application.OnException, а вот когда нет этого блока и есть необработанное исключение.
Application.OnException возникает когда исключение не обработано.
Простой пример на форме 2 кнопки (их обработчики с небольшим отличем друг от друга)
(вот все листинги примера):
------------ Project1 ---------------
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas';
{$R *.RES}
begin
GlobalExp := TGlobalExp.Create;
Application.OnException := GlobalExp.HandleProc;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
------------ end Project1 ---------------
Григорьеву Антону: По вашему ответу диалог будет показан при выполнении блока try except (нажатие на кнопку 1), а показывается диалог при не обработанном исключении (нажатие на кнопку 2).
И возвращаясь к сути вопроса, try/except - это обработанная исключительная ситуация, и здесь все понятно. А как с необработанными-то быть? Неужели нет нормальных механизмов?
А Application.OnException, по-вашему, как работает? Внутри объекта Application стоит вызов вашего кода, обрамлённый try/except. И когда возникает необработанное исключение и управление передаётся в блок except, из него вызывается событие OnException. Так что прежде чем обзывать какие-то механизмы ненормальными, вы бы разобрались с тем, как "нормальные" работают.
Теоретически, конечно, можно и большой try/except сделать. На практике, откинув логику программы и возможность кому-либо во всем этом разобраться, придется поместить энное количество модулей примерно по 1000 строк каждый в одну ну очень большую процедуру. Даже представить себе этого не могу. И возвращаясь к сути вопроса, try/except - это обработанная исключительная ситуация, и здесь все понятно. А как с необработанными-то быть? Неужели нет нормальных механизмов?
А сообщения среды отключены? По умолчанию Delphi в любом случае сначала выдаёт сообщение, а потом проболжает работу программы, если программа запущена из-под Delphi.
Все так и сделано. Только, если ошибка возникает во внешнем модуле и она не обработана, то try/except в Thread.Execute не помогает, поскольку сначала появляется сообщение об ошибке, а уж по нажатию "ОК" возвращается в Execute. Блоков try/except по программе полно, но, видимо, недостаточно. Ошибка появляется редко, и отловить ее затруднительно. Поэтому и нужно перехватывать все необработанные исключительные ситуации.
По хорошему это должен делать менеджер нитей(Thread, не Stream), но если говорить о простой реализации, то в Thread.Execute достаточно сделать try/except, а обрабатку данных выполнять не внутри этой процедуры, а во внешнем модуле. Так и локализовать проблему проще и создавать новые нити с обработчиками легче.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.