|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Сен 6, 2004 18:58:08 Привет всем! Прошу Вас помочь мне разобраться с тем, как работает API-функция MessageBox. Собственно, проблема вот в чем: я столкнулся с неожиданным для меня эффектом, когда использовал эту функцию в обработчике исключений (SEH) который был установлен в потоке, создавшем диалоговое окно и задачей которого была защита процедуры диалогового окна. Этот эффект проявляется вот как: если в процедуре диалога происходит исключение, а в обработчике исключения я сообщаю о возникшей ситуации пользователю (через MessageBox), то почему-то возобновляется работа потока вызвавшего исключение до того как исключение будет обработано. Таким образом, если исключение происходит при обработке сообщения от таймера (WM_TIMER), то я на экране монитора имею целую кучу сообщений об ошибке:( Кстати, аналогичную ситуацию я видел в одной фирменной программе, но только теперь понял, чем это могло быть вызвано. В общем-то, с чем-то подобным я сталкивался и раньше, когда при определенных условиях пользовался этой функцией в обработчике сообщения WM_TIMER. Странно, но я не нашел инфы по этой проблеме ни в одном из доступных мне доков, поэтому пришлось изобретать велосипед. В общем, я придумал для себя два варианта решения этой проблемы: 1. Если функция MessageBox используется, для того чтобы просто проинформировать юзера о возникшей ситуации, то ее нужно ставить после кода выполняющего собственно обработку исключения (который, к примеру, устраняет причину исключения); 2. Если функция MessageBox используется, для того чтобы не просто проинформировать пользователя о возникшей ситуации, но и предлагает выбрать, к примеру, один из двух вариантов дальнейших действий, то можно использовать глобальный флажок. Этот флажок должен устанавливаться в начале процесса обработки исключения и сбрасываться в его конце. В начале оконной (диалоговой) процедуры этот флажок проверяется и если он установлен, то происходит выход из нее без обработки сообщения (хотя тут возможны варианты). Вот так я сейчас делаю, но может быть существует другой более элегантный способ решения этой проблемы? И вообще, хотелось бы знать, как работает функция MessageBox, чтобы понять почему появляется эта проблема. Может быть, кто ни будь из Вас это знает? Поделитесь инфой, плиз! З.Ы.: Я приаттачил архив. В этом архиве находится программка, которая демонстрирует описанную здесь проблему, а также ее исходник. После запуска программы появится диалоговое окно, в котором будет находиться только одна кнопка. После того, как вы нажмете эту кнопку, в диалоговой процедуре при обработке сообщения WM_TIMER, будет происходить исключение, а после повторного нажатия генерация исключения будет прекращена. При обработке исключения будет выдаваться сообщение, после чего будет устраняться причина исключения. |
|
|
Дата: Сен 6, 2004 19:00:51 |
|
|
Дата: Сен 6, 2004 20:11:40 · Поправил: bogrus как работает функция MessageBox, чтобы понять почему появляется эта проблема. Да почти обычное окно , со своей очередью сообщений и обработчиком в user32.dll , тут оно не при чём . Если это проблема - то глобальная , вместо MessageBox ты можешь вставить хоть CreateProcess , и он будет тебе создавать НОВЫЕ и НОВЫЕ процессы , потому что WM_TIMER будет приходить пока ты не прибьёшь таймер , а MessageBox-ы будут висеть пока не нажмёшь OK . Думаю использования флажка самый простой способ , как вариант , можно примерно так : ;===================================================================
flag dd -1
;===================================================================
cmp flag,-1
jz @F ; первый раз
cmp flag,0
jz exit
@@: mov flag,0
invoke MessageBox,NULL,addr Text,addr Caption,MB_OK
mov flag,eax
exit: ret
;=================================================================== |
|
|
Дата: Сен 6, 2004 20:23:34 Oleg_SK , ты неправильно юзаешь SEH!!! На скорую руку я исправил тебе твою прогу, смотри аттач. В твоем обработчике SEH: 1. не хватало одного параметра 2. возвращая из него 0 (ExceptionContinueExecution) ты не восстанавлиал eip, ebp, esp 1956644938__Oleg_SK.rar |
|
|
Дата: Сен 6, 2004 20:53:26 bogrus Если это проблема - то глобальная , вместо MessageBox ты можешь вставить хоть... Хм, почему же тогда, если я заменю вызов MessageBox на вызов Sleep, то все работает правильно (т.е. так как я ожидаю)? rsrc Oleg_SK , ты неправильно юзаешь SEH!!! Вполне возможно. Я только начал изучать его использование на ASM... 1. не хватало одного параметра Хм, но судя по статье Джереми Гордона в обработчик передается только три параметра: * [esp+04h] - Указатель на структуру: EXCEPTION_RECORD; * [esp+08h] - Указатель на структуру: ERR; * [esp+0ch] - Указатель на структуру: CONTEXT record. и все... А что передается через четвертый параметр? 2. возвращая из него 0 (ExceptionContinueExecution) ты не восстанавлиал eip, ebp, esp А разве это нужно делать? В статье Джереми Гордона об этом нет ни слова. Ведь, IMHO, это система делает на автомате... Да и прога моя работает в этом плане вроде правильно... З.Ы.: Если я не прав, то пинайте меня... |
|
|
Дата: Сен 6, 2004 21:11:05 · Поправил: bogrus Oleg_SK то все работает правильно (т.е. так как я ожидаю)? Тю , да закоментируй вообще MessageBox , и прога будет пикать тебе каждые 2 секунды . Ты этого ожидаешь ? з.ы. а Sleep-ы бывают разные , попробуй Sleep,1 и Sleep,-1 :) |
|
|
Дата: Сен 6, 2004 21:18:13 bogrus Ты этого ожидаешь ? Нет не этого. Если я заменю вызов MessageBox на следующую строку: invoke Sleep, 10000 то пикать будет через каждые 10 сек... |
|
|
Дата: Сен 6, 2004 21:35:13 · Поправил: bogrus то пикать будет через каждые 10 сек... Правильно , поток будет спать 10 сек. В чём проблема то осталась ? |
|
|
Дата: Сен 6, 2004 21:47:20 bogrus В чём проблема то осталась ? Я ожидаю, что пока не отработает процедура обработчика исключения выполнение потока, который вызвал это исключение, не должно возобновляться. При Sleep, 10000 все работает правильно, т.е. выполнение потока не возобновляется (даже если поступит сообщение WM_TIMER) пока не отработает процедура обработки исключения, которая, в данном случае, работает в течении ~10 сек. В случае же использования функции MessageBox все летит кувырком, т.к. выполнение потока возобновляется в то время, когда процедура обработчика исключений еще не отработала:( |
|
|
Дата: Сен 6, 2004 21:56:44 · Поправил: volodya и все... А что передается через четвертый параметр? А-то! А твой Гордон - отнюдь не предел мечтаний :/
EXCEPTION_DISPOSITION
__cdecl
_except_handler(
struct _EXCEPTION_RECORD *ExceptionRecord, //+0x4
void * EstablisherFrame, //+0x8
struct _CONTEXT *ContextRecord, //+0xC
void * DispatcherContext ) //+0x10
{
У мя в статье-то побольше расписано будет :) http://www.wasm.ru/article.php?article=packers2 |
|
|
Дата: Сен 6, 2004 22:10:57 bogrus Да, что-то я запутался. Не знаю поможет тебе мой предидущий пост понять суть вопроса или нет... Ладно, давай я объясню тебе, как я тебя понял: выполнение процедуры обработки исключения будет прервано в ЛЮБОМ случае при поступлении сообщения WM_TIMER. Поэтому я привел пример, когда этого прерывания не происходит. |
|
|
Дата: Сен 6, 2004 22:15:38 volodya А-то! А твой Гордон - отнюдь не предел мечтаний :/ Вполне возможно, но к сожалению кроме этой статьи я больше ни чего ни где не нашел по этой теме (использование SEH на ассемблере):( И, кстати, Гордон - не мой;) |
|
|
Дата: Сен 6, 2004 22:29:41 · Поправил: rsrc Oleg_SK, видать зря я сидел и код твой правил! Ты даже и не взглянул на него :( А на счет MessageBox'ов я вот, что скажу: MessageBox() - это окно и поэтому твой поток не тормозиться где-то в недрах user32.dll->MessageBox..., а вытаскивает из очереди сообщений потока мессаги, которые приходят окну(ам) потока, чтобы окно(а) могло жить и в какие-то моменты времени приходят туда и WM_TIMER'ы и пока хватает стека все у тебя хорошо... :) |
|
|
Дата: Сен 6, 2004 22:36:49 Да, забыл сказать о том, что WM_TIMER'ы не аккумулируются или другими словами - пока енто сообщение не обработалося не приходит НОВОЕ! |
|
|
Дата: Сен 6, 2004 23:10:18 · Поправил: Oleg_SK rsrc Oleg_SK, видать зря я сидел и код твой правил! Ты даже и не взглянул на него :( Извини, я сейчас снова глянул! Я так понял, что в твоем варианте программы после отработки процедуры обработчика происходит переход на код завершения программы (метка @@Exit:). Конечно, в том случае если при возникновении исключения программу нужно корректно завершить, то так и нужно делать. Но в моем же варианте в процессе обработки исключения устранялась его причина и следовательно программа могла продолжать корректно выполняться. А на счет MessageBox'ов я вот, что скажу:... Теперь понятно, откуда взялась проблема. В общем-то, я и сам мог бы догадаться. А не догадался потому, что где-то краем уха слышал, что в процессе работы MessageBox порождает новый поток, а уже в этом потоке создает окно, это меня запутало. Я не знал так это или нет, поэтому и попросил объяснить мне то, как работает эта функция. |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.063 |