Задания.
- Изучить процедуру главного окна
- Изучить цикл обработки сообщений
- Изучить используемые в программе API-функции
- Изменить параметры функции GetMessageA
- Изменить параметры функции CreateWindowExA
6. Изменить главную процедуру окна WNDPROC
Методические рекомендации по выполнению лабораторной работы
Рассмотрим простую программу графического приложения. Разберите ее внимательно – она будет фундаментом, на котором мы будем строить дальнейшее рассмотрение.
Прежде всего обратите внимание на директиву INCLUDELIB. В пакете TASM32 довольно много разных библиотек. Для данного примера необходима: import32.lib. При наборе текста программы нужно изменить путь к библиотеке.
Сначала определяются константы и внешние библиотечные процедуры. В действительности все эти определения можно найти в include-файлах, прилагаемых к пакету TASM32. Мы не будем использовать стандартные include-файлы, т.к. так удобнее понять технологию программирования.
Необходимо четко понимать способ функционирования процедуры окна, так как именно это определяет суть программирования под Windows. Задача данной процедуры – правильная реакция на все приходящие сообщения. Нужно детально разобратся в работе нашего приложения. Сначала обратите внимание на то, что необработанные сообщения должны возвращаться в систему при помощи функции DefWindowProcA.
|
|
Программа отслеживает четыре сообщения: WM_CREATE, WM_DESTROY, WM_LBUTTONDOWN, WM_RBUTTONDOWN. Сообщения WM_CREATE и WM_DESTROY в терминах объектного программирования играют роль конструктора и деструктора: они приходят в функцию окна при создании окна и при уничтожении окна. Если щелкнуть по крестику в правом углу окна, то в функцию окна придет сообщение WM_DESTROY. Далее будет выполнена функция PostQuitMessage и приложению будет послано сообщение WM_QUIT, которое вызовет выход из цикла ожидания и выполнение функции ExitProcess, что, в свою очередь, приведет к удалению приложения из памяти.
Обратите внимание на метку _ERR – переход на нее происходит при возникновении ошибки, и здесь можно поместить соответствующее сообщение.
Выполните набор программы в блокноте или в любом другом простом текстовом редакторе. Чтобы получить загружаемый модуль, выполните следующие команды:
TASM32 /ml prog.asm
TLINK32 –aa prog.obj
Текст программы:
.386P
.MODEL FLAT, stdcall
; константы
; сообщение приходит при закрытии окна
WM_DESTROY equ 2
; сообщение приходит при создании окна
WM_CREATE equ 1
; сообщение при щелчке левой кнопкой мыши в области окна
WM_LBUTTONDOWN equ 201h
; сообщение при щелчке праввой кнопкой мыши в области окна
WM_RBUTTONDOWN equ 204h
; свойства окна
CS_VREDRAW equ 1h
CS_HREDRAW equ 2h
CS_GLOBALCLASS equ 4000h
WS_OVERLAPPEDWINDOW equ 000CF0000H
style equ CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS
|
|
; идентификатор стандартной иконки
IDI_APPLICATION equ 32512
; идентификатор курсора
IDC_CROSS equ 32515
; режим показа окна - нормальный
SW_SHOWNORMAL equ 1
; прототипы внешних процедур
EXTERN MessageBoxA: NEAR
EXTERN CreateWindowExA: NEAR
EXTERN DefWindowProcA: NEAR
EXTERN DispatchMessageA: NEAR
EXTERN ExitProcess: NEAR
EXTERN GetMessageA: NEAR
EXTERN GetModuleHandleA: NEAR
EXTERN LoadCursorA: NEAR
EXTERN LoadIconA: NEAR
EXTERN PostQuitMessage: NEAR
EXTERN RegisterClassA: NEAR
EXTERN ShowWindow: NEAR
EXTERN TranslateMessage: NEAR
EXTERN UpdateWindow: NEAR
; директивы компоновщику для подключения библиотек
includelib c:\win32\tasm32\lib\import32.lib
;-------------------------------------------------------------------------
; структуры
; структура сообщения
MSGSTRUCT STRUC
MSHWND DD?; идентификатор сообщения
MSWPARAM DD?; доп. информация о сообщении
MSLPARAM DD?; доп. информация о сообщении
MSTIME DD?; время посылки сообщения
MSPT DD?; положение курсора во время посылки сообщения
MSGSTRUCT ENDS
;---------------------------
WNDCLASS STRUC
CLSSTYLE DD?; стиль окна
CLWNDPROC DD?; указатель на процедуру окна
CLSCEXTRA DD?; информация о доп. байтах для данной структуры
CLWNDEXTRA DD?; информация о доп. байтах для окна
CLSHINSTANCE DD?; дискриптор приложения
CLSHICON DD?; идентификатор иконы окна
CLSHCURSOR DD?; идентификатор курсора окна
CLBKGROUND DD?; идентификатор кисти окна
CLMENUNAME DD?; имя-идентификатор меню
CLNAME DD?; специфицирует имя класса окна
WNDCLASS ENDS
; сенмент данных
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
NEWHWND DD 0
MSG MSGSTRUCT <?>
WC WNDCLASS <?>
HINST DD 0; здесь хранится дескриптор приложения
TITLENAME DB 'Простой пример 32-битного приложения',0
CLASSNAME DB 'CLASS32',0
CAP DB 'Сообщение',0
MES1 DB 'Вы нажали левую кнопку мыши',0
MES2 DB 'Выход из программы. Пока!',0
_DATA ENDS
; сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:
; получить дескриптор приложения
PUSH 0
CALL GetModuleHandleA
MOV [HINST],EAX
REG_CLASS:
; заполнить структуру окна
MOV [WC.CLSSTYLE], style
; процедура обработки сообщений
MOV [WC.CLWNDPROC], OFFSET WNDPROC
MOV [WC.CLSCEXTRA], 0
MOV [WC.CLWNDEXTRA], 0
MOV EAX, [HINST]
MOV [WC.CLSHINSTANCE],EAX
;------------------иконка окна
PUSH IDI_APPLICATION
PUSH 0
CALL LoadIconA
MOV [WC.CLSHICON], EAX
;------------------курсор окна
PUSH IDC_CROSS
PUSH 0
CALL LoadCursorA
MOV [WC.CLSHCURSOR], EAX
;-------------------
MOV [WC.CLBKGROUND],17; цвет окна
MOV DWORD PTR [WC.CLMENUNAME], 0
MOV DWORD PTR [WC.CLNAME], OFFSET CLASSNAME
PUSH OFFSET WC
CALL RegisterClassA
; создать окно зарегистрированного класса
PUSH 0
PUSH [HINST]
PUSH 0
PUSH 0
PUSH 400; DY - высота окна
PUSH 400; DX - ширина окна
PUSH 100; Y - координата левого верхнего угла
PUSH 100; X - координата левого верхнего угла
PUSH WS_OVERLAPPEDWINDOW
PUSH OFFSET TITLENAME; имя окна
PUSH OFFSET CLASSNAME; имя класса
PUSH 0
CALL CreateWindowExA
; проверка на ошибку
CMP EAX, 0
JZ _ERR
MOV [NEWHWND], EAX
PUSH SW_SHOWNORMAL
PUSH [NEWHWND]
CALL ShowWindow; показать созданное окно
PUSH [NEWHWND]
CALL UpdateWindow; команда перерисовать видимую часть окна, сообщение WM_PAINT
; цикл обработки сообщений
MSG_LOOP:
PUSH 0
PUSH 0
PUSH 0
PUSH OFFSET MSG
CALL GetMessageA
CMP EAX, 0
JE END_LOOP
PUSH OFFSET MSG
CALL TranslateMessage
PUSH OFFSET MSG
CALL DispatchMessageA
JMP MSG_LOOP
END_LOOP:
; выход из программы (закрыть процесс)
PUSH [MSG.MSWPARAM]
CALL ExitProcess
_ERR:
JMP END_LOOP
;----------------------------------------------------------------------------
; процедура окна
; расположение параметров в стеке
; [EBP+14H] LPARAM
; [EBP+10H] WPARAM
; [EBP+0CH] MES
; [EBP+8] HWND
WNDPROC PROC
PUSH EBP
MOV EBP, ESP
PUSH EBX
PUSH ESI
PUSH EDI
CMP DWORD PTR [EBP+0CH], WM_DESTROY
JE WMDESTROY
CMP DWORD PTR [EBP+0CH], WM_CREATE
JE WMCREATE
CMP DWORD PTR [EBP+0CH], WM_LBUTTONDOWN; левая кнопка
JE LBUTTON
CMP DWORD PTR [EBP+0CH], WM_RBUTTONDOWN; правая кнопка
JE RBUTTON
JMP DEFWNDPROC
; нажатие правой кнопки приводит к закрытию окна
RBUTTON:
JMP WMDESTROY
; нажатие левой кнопки мыши
LBUTTON:
; выводим сообщение
PUSH 0; MB_OK
PUSH OFFSET CAP
PUSH OFFSET MES1
PUSH DWORD PTR [EBP+08H]
CALL MessageBoxA
MOV EAX, 0
JMP FINISH
WMCREATE:
MOV EAX, 0
JMP FINISH
DEFWNDPROC:
PUSH DWORD PTR [EBP+14H]
PUSH DWORD PTR [EBP+10H]
PUSH DWORD PTR [EBP+0CH]
PUSH DWORD PTR [EBP+08H]
CALL DefWindowProcA
JMP FINISH
WMDESTROY:
PUSH 0; MB_OK
PUSH OFFSET CAP
PUSH OFFSET MES2
PUSH DWORD PTR [EBP+08H]; дескриптор окна
CALL MessageBoxA
PUSH 0
CALL PostQuitMessage; сообщение WM_QUIT
MOV EAX, 0
FINISH:
POP EDI
POP ESI
POP EBX
POP EBP
RET 16
WNDPROC ENDP
_TEXT ENDS
END START
Основная литература – 5[27-68]
Контрольные вопросы.
- Какие API-функции используются в программе?
- Какие структуры используются в программе?
- Структура графического приложения.
- Какие API-функции включает цикл обработки сообщений?