Доброго здоровья, пишет ищущий чайник. Изучая урок 4 Iczelion'a, задался вопросом Куда возвращает команда RET из WndProc Процедуру окна сама прога не вызывает, это понятно, но логично предположить, что после обработки сообщения, прого должна вернуться в цикл сообщений. Вопрос как в win32 это происходит, и как в айсе это увидеть.
[ Bitfry: и как в айсе это увидеть. ] Добавь int 3 в любое место своей WndProc. В айсе набери i3here on. Когда трапнешься набери p ret и ты в сабже.
[Прога вызывает процедуру окна неявно через DispatchMessage] Loger я это понимаю, я так же понимаю, что и без DispatchMessage может вызваться процедура окна. Я не очень понимаю, что происходит после этой процедуры. Команда ret кидает меня в user32, и даже если я буду выполнять код в айсе дальше, я не попаду в цикл сообщений, почему? [Добавь int 3 в любое место своей WndProc. В айсе набери i3here on. Когда трапнешься набери p ret и ты в сабже.] Four-F у меня не работает или я что делаю не так. Насколько я понял нужно выполнить следующее: В код программы в WndProc добавить строку int 3 Вызвать айс и набрать i3here on Запустить прогу и трапнуца Набрать в айсе p ret И вот здесь айс должен оказаться в сабже. Только он оказываюсь в том же user32 А за сабж я принимаю цикл сообщений, или я неправ?
Bitfry "А за сабж я принимаю цикл сообщений" Насколько я понимаю, тебе нужен call stack - цепочка вызовов. В айсе call stack вызывается комадой STACK (подробности в Command Reference). Если под циклом сообщенний имеется ввиду обработка сообщений в дебажном процессе, то в итоге ты должен попасть в PeekMessage или GetMessage дебажного процесса, а из них в message loop. Поэтому после трапа на int3 смотрим call stack и откуда идет вызов PeekMessage и т.п.
Bitfry > И вот здесь айс должен оказаться в сабже. нажимай F12(p ret) несколько раз, пока не окажешься в адресном пространстве проги.
Оычно цикл сообщений это: если не PeekMessage, то WaitMessage. Поэтому вместо int3 можно попробовать bpx WaitMessage. Затем смотришь адрес возврата в ESP.
Leo, команда stack очень полезная, спасибо, буду пользоваться. [пока не окажешься в адресном пространстве проги.] Asterix, не окажусь я там. Через несколько p ret'ов айс больше не появляется. Да что вы меня путаете! Ставлю простой бряк на строку ret В айсе выполняю эпилог (leave и ret 0010) Прога в user32, и в стеке сверху лежит указатель начала цикла сообщений моей программы. Вот и все! Но суть не в этом, я не хочу возвратиться в цикл по всяким p ret'ам, я хочу понять, кто и где берет из стека этот указатель и возвращается в мой цикл сообщений за новой месагой. Блин, я скоро как программер буду изъясняться!
[Прога в user32, и в стеке сверху лежит указатель начала цикла сообщений моей программы.] Наврал! Там не указатель цикла сообщений. Там указатель WndProc, но почему?
Сообщения виндоса - штука довольно муторная. Помимо DispatchMessage, многие другие функции (например DefWindowProc, GetClientRect и т.п.) так же могут вызывать WndProc. т.е. вызов происходит непосредственно из WndProc рекурсивно, может по многу раз. По RET из WindProc (в XP по крайней маре) попадаем в user32 на cmp [dword ss:esp+4], DCBAABCD так виндос заботится о тех, кто использует RETN, вместо RETN 10h. Ещё поищите Джеффри Рихтер "Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows", там про сообщения есть целая глава. Ссылки на такие вещи запрещены, но поиск поможет
S_T_A_S_ Вот это ответ так ответ, спасибо. Буду читать, оно у меня есть. Если чего не пойму, опять здесь спрашивать буду. Еще раз спасибо.
[ Bitfry: Да что вы меня путаете! ] Так это не мы тебя, а ты нас Ты спросил "Куда возвращает команда RET из WndProc?". И я ответил именно на вопрос. А что ты там имел ввиду - пойди разбери. А Рихтера почитай.
Four-F Да ты прав, я не ясно задал вопрос. Я не имел введу каманду айса. Вопрос был про опкод ret 0010 в конце WndProc в 4 уроке у Iczelion'a А книга дельная, я ее отложил, потому что название меня сбило, а вот сейчас читаю.
Джеффри РИХТЕР "Создание эффективных WIN32-приложений с учетом специфики 64-разрядной версии Windows" Цитата из главы 26 ... Алгоритм выборки сообщений из очереди потока Когда поток вызывает GetMessage или PeekMessage, система проверяет флаги состояния очередей потока и определяет, какое сообщение надо обработать 1. Если флаг QS_SENDMESSAGE установлен, система отправляет сообщение соответствующей оконной процедуре GetMessage и PeekMessage контролируют процесс обработки и не передают управление потоку сразу после того, как оконная процедура обработает сообщение, вместо этого обе функции ждут следующего сообщения. 2. Если очередь асинхронных сообщений потока не пуста, GetMessage и Peek Message заполняют переданную им структуру MSG и возвращают управление в Цикл выборки сообщений (расположенный в потоке) в этот момент обычно обращается к DispatchMessage, чтобы соответствующая оконная процедура обработала сообщение. 3. Если флаг QS_QUIT установлен, GetMessage и PeekMessage возвращают сообщение WM__QUIT (параметр wParam которого содержит указанный код заверше ния) и сбрасывают этот флаг. 4 Если в очереди виртуального ввода потока есть какие-то сообщения, GetMessage и PeekMessage возвращают сообщение, связанное с аппаратным вводом. 5. Если флаг QS_PAINT установлен, GetMessage и PeekMessage возвращают сооб щение WM_PAINT для соответствующего окна ... Если кто может, объясните, пожалуйста, в пункте 1, идет речь о том, куда прога попадет из WndProc? А вообще я не нашел в этой главе про сабж, только это. Может, есть еще дельные книги по архитектуре форточек?
Дык я же написАл - из WndProc мы всегда будем попадать в user32, поскольку именно оттуда и происходит непосредственно вызов. Куда попадём дальше - вопрос неоднозначный, зависит от состояния очереди сообщений. Ты б написАл подробнее зачем это нужно, может тогда кто-нибудь и даст более вразумительный ответ. Досконального описания всего этого механизма imho нигде нет, т.к. он меняется с развитием виндоса. Например, до XP можно было обходиться без ф-ции DispatchMessage, самостоятельно вызывая WndProc. Можно ещё создать окна без цикла выборки сообщений. Или зарегистрировать DefWindowProc в качестве WndProc.
[ Bitfry: Если кто может, объясните, пожалуйста, в пункте 1, идет речь о том, куда прога попадет из WndProc? ] Нет. Из WndProc прога попадает туда, откуда была вызвана WndProc. Т.е. куда-то в user32.dll. Обработка сообщений идет в ядре (в драйвере win32k.sys), куда GetMessage попадает вызвав NtUserGetMessage. Сам процесс весьма сложен, поэтому искать его детальное объяснение в книгах бессмысленно. Вот кусок где проверяется флаг QS_SENDMESSAGE и либо бай-бай, либо xxxReceiveMessages. Код (Text): BOOL xxxInternalGetMessage( LPMSG lpMsg, HWND hwndFilter, UINT msgMin, UINT msgMax, UINT flags, BOOL fGetMessage) { . . . UINT fsWakeMask; . . . /* * Compute the QS* mask that corresponds to the message range * and the wake mask filter (HIWORD(flags)) */ fsWakeMask = CalcWakeMask(msgMin, msgMax, HIWORD(flags)); ptiCurrent->fsChangeBitsRemoved = 0; . . . /* * Check for sent messages. Check the the actual wake bits (i.e, from pcti) * so we know for real. */ if (ptiCurrent->pcti->fsWakeBits & fsWakeMask & QS_SENDMESSAGE) { xxxReceiveMessages(ptiCurrent); } else if (ptiCurrent->pcti->fsWakeBits & QS_SENDMESSAGE) { goto NoMessages; } . . . NoMessages: /* * Looks like we have no input. If we're being called from GetMessage() * then go to sleep until we find something. */ if (!fGetMessage) { /* * This is one last check for pending sent messages. It also * yields. Win3.1 does this. */ if (!(flags & PM_NOYIELD)) { /* * This is the point where windows yields. Here we wait to wake * up any threads waiting for this thread to hit "idle state". */ zzzWakeInputIdle(ptiCurrent); /* * Yield and receive pending messages. */ xxxUserYield(ptiCurrent); } PATHTAKEN(0x800); goto FalseExit; } /* * This is a getmessage not a peekmessage, so sleep. When we sleep, * zzzWakeInputIdle() is called to wake up any apps waiting on this * app to go idle. */ if (!xxxSleepThread(fsWakeMask, 0, TRUE)) goto FalseExit; } /* while (TRUE) */ . . . } [ Bitfry: Может, есть еще дельные книги по архитектуре форточек? ] Есть. Исходный код системы + отладчик + дизассемблер + мозги + ОГРОМНОЕ количество свободного времени
Four-F Спасибо. Поздравляю тебя с днем знаний. =) Я так спросил, я же чайник и еще не знаю, что можно раскопать сразу, а куда лучше с моими знаниями не соваться. Но я еще попробую с этим вопросом разобраться (в рамках XP и в общих чертах). Пункт 1 я толкую так: Отработала процедура окна, строка ret посылает в user32. Если есть еще сообщение, то после колдовства виндов управление вернется к проге в её цикл сообщений. А если сообщений нет, нафига тогда цикл крутить, проц занимать? Вот поэтому возврат происходит не сразу из user32 в цикл сообщений, а через кучу всяких функций. [S_T_A_S_:Ты б написАл подробнее зачем это нужно, может тогда кто-нибудь и даст более вразумительный ответ.] S_T_A_S_ тебя тоже с днем знаний. Я пишу дневник чайника, в котором разбираю уроки Iczelion'a. Чтоб понять, как работает программа в виндах, я захотел ответить на кучу вопросов, которые появляются у начинающих, вот и копаю потихоньку сам, а на этот вопрос сам ответа не нашел. Я просто исследователь, и нет никакой такой проги для которой это нужно. Примерно так появляются темы с плюсиком.
user32, в данном случае - это просто прослойка между приложением и ядром, где и происходит работа с очередью сообщений. Возврат происходит в любом случае через user32, и "через кучу всяких функций" в ядро. И ядро уже решает, то ли усыпить поток, если очередь пуста, то ли отправить оконной процедуре какое-нить сообщение, если таковое имеется. Если очередь пуста, то ожидание происходит в режиме ядра.
Four_F "И ядро уже решает.." Нда ? Очень интересно.. А я-чайник думал, что несколько не так. А зачем тогда message loop ? Мне по мастдайски кажется, что иницатива опроса очереди сообщений исходит от приложения: Код (Text): if PeekMessage (или GetMessage) then ... TranslateMessage DispatchMessage //->...-> WndProc ->...-> ??? xxx: else WaitMessage //-> здесь ес-но засыпаем yyy: ... Что, в данном случае мы после Dispatch застрянем в ядре и не попадем на xxx ? Хотя с другой стороны, если мы спим, то пропудить нас может только ядро - вопрос с какого места - с yyy или, как ты говоришь, "отправить оконной процедуре какое-нить сообщение" ?
Ладно, я не так выразился. Если в очереди есть сообщения, то GetMessage вернется из ядра, а DispatchMessage уже передает его оконной процедуре. Но если сообщений нет, то GetMessage не вернется из ядра, до тех пор пока они не появятся. WaitMessage, скорее всего, тоже в ядро уходит.