Доброго время суток, уважаемые подписчики. В этом выпуске я постараюсь подробно объяснить, что мы делали в процедуре окна.
Итак, в предидущем выпуске рассылки мы закончили обсуждать нашу программу на создании и выводе на дисплей нашего окна. Продолжим:
Этой строкой мы заносим адрес переменной сообщений в edi, так как при обработке сообщений нам придётся несколько раз помещать этот адрес в стек, а "push edi" быстрее и компактнее команды "push offset msg_".
Начало нашего главного цикла обработки сообщений.
push ebx
push ebx
push ebx
push edi
call GetMessage
|
При вызове GetMessage эта процедура забирает из стека 4 параметра и использует их как первое сообщение, второе сообщение, объект, к которому принадлежат сообщения и адрес структуры сообщений. Мы используем её с параметрами 0,0,0,offset msg_, то есть принимаем все сообщения от всех объектов данной задачи в структуру msg_!
Если пользователь закрывает приложение, то эта процедура возвращает 0, поэтому стоит устроить проверку на 0, и в случае равенства выхода.
push edi
call TranslateMessage
push edi
call DispatchMessage
|
Эти две процедуры расшифровывают сообщение, при входе надо поместить в стек адрес структуры сообщения.
Этой строкой мы зацикливаем процесс обработки сообщений, то есть сообщения будут непрерывно, или насколько позволит скорость процессора, повторятся. Наверняка у многих из Вас появился вопрос, а как работает процедура окна, когда о ней даже не упоминается. Спешу ответить на этот вопрос, в Windows каждая часть приложения выполняется как отдельная задача. Заглянем назад, при инициализации переменных и структур мы записали в структуру нашего окна адрес процедуры окна! В связи с этим при создании окна Windows создал отдельную задачу, в которую поместил нашу процедуру обработки окна. Наша программа и процедура окна выполняются параллельно, а так как обе ссылаются на одну и ту же структуру сообщений, то сообщения передаются через неё. При этом при завершении программы мы должны отдельно закрыть каждую часть нашего приложения.
exit_:
push ebx
call ExitProcess
|
Вот и само завершения программы, но не процедура окна. Единственное, что хотел бы здесь отметить, что в отличии от DOS в Windows программа завершается не директивой ret, которая передаёт управление программе терминатору, а вызовом процедуры терминатора напрямую.
win_proc proc
push ebp
mov ebp,esp
wp_hWnd equ dword ptr [ebp+08h]
wp_uMsg equ dword ptr [ebp+0Ch]
wp_wParam equ dword ptr [ebp+10h]
wp_lParam equ dword ptr [ebp+14h]
cmp wp_uMsg,WM_DESTROY
jne not_
push 0
call PostQuitMessage
jmp end_
not_:
leave
jmp DefWindowProc
end_:
leave
ret 16
win_proc endp
end _start
|
А это наша процедура окна! Рассмотрим подробно каждую её строку!
push ebp
mov ebp,esp
Этими двумя командами мы создаём так называемый стековой кадр для нашей процедуры. На самом деле мы помещаем в стек значение ebp, а потом сохраняем размер стека в ebp, после этого мы спокойно можем использовать стек, с условием, что перед завершением процедуры мы загрузим размер стека обратно в esp! Следовательно, мы не должны изменять ebp в течении процедуры!
wp_hWnd equ dword ptr [ebp+08h]
wp_uMsg equ dword ptr [ebp+0Ch]
wp_wParam equ dword ptr [ebp+10h]
wp_lParam equ dword ptr [ebp+14h]
|
Эти четыре строки в программе не участвуют, но существенно облегчают нашу работу!
cmp wp_uMsg,WM_DESTROY
jne not_
|
Так как в этом примере наше окно ничего не делает, то единственное действие, которое может произойти с ним это закрытие. Поэтому стоит поставить проверку на закрытие (сообщение windows wm_destroy). Если окно не было закрыто, то переходим на метку not_,
push 0
call PostQuitMessage
jmp end_
|
Если же оно было закрыто, то помещаем в стек 0 и сообщаем об этом Windows при помощи процедуры PostQuitMessage.
not_:
leave
jmp DefWindowProc
|
Если сообщение не получено, то управление передаётся на эту метку. Команда leave эквивалентна двум командам, mov esp,ebp и pop ebp, то есть она возвращает esp и ebp их изначальные значения! Так как полная обработка окна (вырисовка на экран и т.д.) выполняется Windows, то надо не завершить программу, а передать управление на процедуру окна, jmp DefWindowProc.
А при завершении процедуры нам нужно ещё убрать структуру сообщений из стека, а так как она занимает 4 двойных слова, что равно 16 байтам, это за нас сделает директива ret 16!
Вот вроде и всё! Если есть какие вопросы, пишите, обязательно отвечу. В следующем уроке мы повторим MessageBox и полатаем нашу программу! Пишите, Dark_Lord@RusFAQ.ru или Dark_Lord@land.ru