![]() |
Модераторы: Snowy, MetalFan, bems, Poseidon |
![]() ![]() ![]() |
|
Avers |
|
||||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
Не могу разобраься, какой объект вызвал ошибку, а какой метод (в котором эта ошибка возникла)
Простой пример: бросаем на форму кнопку и пишем код
Как бы кнопку не нажимали, в сообщении будет TButton А если написать свой обработчик исключений))... начинается самое интересное
При фокусировке на кнопке жмем энтер и тоже получаем TButton. Но вот если нажать кнопку мышью, то получим TForm1 (!!!!) Почему? --------------------
Born to be wild |
||||
|
|||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Вообще-то метод, в котором возникло исключение, стандартными средствами не отслеживается никак.
Стандартный Application.HandleMessage всегда вызывается с Sender = форме, в методах которой расположен его вызов, а если он вызывается вне формы - то в Sender передаётся Application. Если вас интересует диагностика места возникновения ошибки - см., например, Вопрос КС №57687 -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
Avers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
В данный момент мне хотелось бы узнать, почему MyException передатся один раз TButton, другой раз TForm1
То, что нельзя легко и просто узнать метод, вызвавший ошибку, я смирюсь. Но хочется хотя бы знать объект и/или модуль, в котором ошибка возникла. --------------------
Born to be wild |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Здесь я немного наврал. Не заметил:
Вероятно это связанно с особенностями обработки сообщений в Windows. Дело в том, что многие сообщения шлются не самому контролу, а его контейнеру. При низкоуровневом программировании это позволяет положить на окно кнопку, не создавая для неё отдельный класс, а управляя ей (ловить её сообщения) из контейнера. Соответственно VCL для эмуляции того поведения, что мы видим сейчас, должна ловить сообщения в контейнере и перенапрявлять их (прямым вызовом через Perform) дочерним контролам (CN_COMMAND с BN_CLICKED для случая OnClick кнопки). Обработчик исключений при этом остаётся установленным на контейнер. Такую работу выполняет, например, DoControlMsg. Соответственно, кто будет в Sender зависит от того, кому было направлено сообщение. Объект - это как? Объект - это вообще-то адрес в памяти. Вы хотите узнать число типа 0A34F3A7? ![]() Обычно узнают класс и имя метода. Если объект - это компонент, то при сильном желании можно вытащить его свойство Name. Только в этом случае некрасиво получится. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
Avers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
я неверно выразился - мне нужно имя класса.
Т.е., если бы не было этой канители то, все было бы замечательно: по Sender можно было определить класс от которого пришло исключение, а следовательно и модуль и т.п. и во многих (пусть не всех, но во многих) случаях метод, в котором произошло исключение... (а мне больше и н надо). Но не зная класса.... все остальное становится бессмыслено. Как же тогда определить модуль, в котором произошло исключение? --------------------
Born to be wild |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Ну вот поскольку Sender равен тому, кто поймал сообщение, а часть сообщений для кнопки отправляются именно форме, то так вот запросто это сделать не получится. 1. В принципе, на руках есть ExceptAddr - точный адрес инструкции, возбудившей исключение. У нас на руках есть и RTTI - в частности, список имён published-методов (в том числе обработчиков событий) и их адресов. Проблема состоит в том, как определить, какому методу принадлежит ExceptAddr. Имеется ввиду, что начало каждого метода известно, а вот сколько он занимает байт в длинну - нет. Может здесь и можно что-то придумать, но мне ничего в голову не приходит. 2. Простейшее в реализации будет подключить JclDebug, включить в опциях генерацию map-файлов и вызвать функцию GetLocationInfo. Простейшее в том смысле, что уже всё готово и написано. 3. Ну и, конечно, как вариант можно рассмотреть применение грязных хаков - например, подмена функций и методов перенаправления сообщения. В частности, обернуть Control.Perform в try ... except Application.HandleException(Control); end; Тогда бы Sender указывал на того, кого вы хотите. Но, помимо того, что это очень грязно, проблема ещё и в том, что некоторые нужные нам функции (например, тот же DoControlMsg) находятся в implementation-секциях модулей и не имеют внешних ссылок. Т.е. неизвестен их адрес. Аналогично - готового решения здесь мне не видно. Добавлено через 1 минуту и 54 секунды ...хотя... с другой стороны, сам Perform ведь в интерфейсной части, можно попробовать подменить его... -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
По способу номер 3 в последнем моём посте - если хотите, то можете попробовать такой код (для подмены стандартного класса используется метод Geo):
На первый взгляд вроде бы это работает, но, блин, серьёзно это не тестировалось. Я не рекомендую вам применять этот код как есть - это просто пример. Дело в том, что полностью ловить исключение в NewWndProc неправильно - т.к. существующий код (в том числе и VCL) рассчитывает на то, что исключение будет передаваться наружу. Поэтому вместо HandleException должно стоять запоминание экземпляра в глобальную переменную и её анализ и сброс в OnException. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
Avers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
1. Здесь идейка одна была и она заработала (по крайней мере в простом случае.
Кажется, в другой теме я выкладывал этот код:
но это для малой программы, где всего один моудль, поэтому можно уверенно искать в медоах Selfю 2. Не спорю. Смотрю как работает эврика лог - загляденье. Но столь мощый обработчик не требуется (раз). Нужен свой, бесплатный (специфика работы, можно сказать) - это два. 3.... сложно и запутанно.... (имхо). Нужен просто модуль (реализация в виде пакета bpl) подключаемый к написанной программе. Т.е. так, чобы не переписывать код. --------------------
Born to be wild |
|||
|
||||
CodeMonkey |
|
||||||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Вообще-то это число в точности равно переменной ExceptAddr ;)
Здесь как раз проблемы нет: вы всегда можете перебрать Screen.Forms. И перебрать методы у каждой формы. А настоящая проблема с приведённым способом в том, что он может давать ложную информацию. Например, пусть у вас в модуле есть (именно в таком порядке) OnButton1Click, затем в модуле идёт какой-то код (функция) и далее расположен Button2Click. Так вот, в Button2Click вы вызываете функцию, которая расположена между Button1Click и Button2Click. Предположим, что в ней возникнет исключение. Что сделает ваш код? Код возьмёт адрес исключения (он расположен где-то между Button1Click и Button2Click) и начнёт уменьшать его, сдвигаясь к Button1Click, на каждом шаге пытаясь получить имя метода. Поскольку код между Button1Click и Button2Click не входит в RTTI (это просто какая-то функция), то сделать вам этого не удасться. Это значит, что ближайшее место, где вы остановитесь - это Button1Click. В итоге, в реальности мы вызывали Button2Click -> SomeFunc, а обработчик исключений сообщит нам, что ошибка возникла в Button1Click. Ложная информация. Добавлено через 1 минуту и 22 секунды P.S. Это в точности та проблема, что я говорил чуть ранее: известны только адреса методов, но не их размер. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
||||||
|
|||||||
Avers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
Упс)) Кста, как воспользоваться этой самой переменной?? Т.е. где она объявлена. Стыдно, но я не знаю. Я ею ни разу не пользовался. Добавлено через 2 минуты и 57 секунд Нашел)) Это сообщение отредактировал(а) Avers - 11.11.2008, 12:06 --------------------
Born to be wild |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
JclDebug - бесплатен. P.S. Эй, это же ваш вопрос: http://forum.vingrad.ru/forum/topic-231665.html Все ссылки сами и нашли. Это сообщение отредактировал(а) CodeMonkey - 11.11.2008, 12:27 -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
Avers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
Можете считать меня упрямым, но я все равно хочу написать что-нить свое))
Буду развиваться, как программист=))) --------------------
Born to be wild |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Ну так что, исчерпан вопрос или нет?
Вариант ответа на исходный вопрос был. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
Avers |
|
|||
![]() Шустрый ![]() Профиль Группа: Участник Сообщений: 113 Регистрация: 20.6.2008 Где: 26rus Репутация: нет Всего: нет |
ответ на вопрос был.
Признаюсь, про контейнеры - не очень ясно, но суть понял - Sender в MyException - малополезный параметр (имхо). Прост хотелось бы стабильности. Однорвеменно с тем появились новые вопросы. Например: Какие есть еще способы, кроме Self.MethodName, по адресу получить имя процедуры или фнуции.... Ведь, если посмотреть View -> Debug Windows -> Modules, то обнаружиться, что там есть адреса процедур и не принадлежащих объекту.... Application.MethodName - вообще ничего не дает (ни от одного адреса) ![]() Наверняка все проще, чем кажется... --------------------
Born to be wild |
|||
|
||||
CodeMonkey |
|
|||
Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1839 Регистрация: 24.6.2008 Где: Россия, Тверь Репутация: 29 Всего: 89 |
Этот и другие (CallStack и т.п.) инструменты используют отладочную информацию. В готовую программу отладочная информация по-умолчанию не подключается. Попасть в exe она может несколькими способами, примеры каждого есть.... эээ... в JclDebug ;) Есть только единственный верный способ это сделать - воспользоваться отладочной информацией. Ваши попытки использовать для этого MethodName (читай: RTTI) некорректны, что я показал в этом посте. Ну нет в exe-файле информации о принадлежности адреса функции. Нету. Хоть головой об стенку бейтесь, но её там нет ![]() Единственный вариант - это её туда добавить. И вот здесь уже напридумывать можно много разных способов. Добавлено через 1 минуту и 50 секунд По самой идее - проще некуда ;) по реализации - готовых стандартных решений нет, писать нужно всё самому или использовать написанное другими. -------------------- Опытный программист на C++ легко решает любые не существующие в Паскале проблемы. |
|||
|
||||
![]() ![]() ![]() |
Правила форума "Delphi: Для новичков" | |
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader. |
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей) | |
0 Пользователей: | |
« Предыдущая тема | Delphi: Для новичков | Следующая тема » |
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |