На этом шаге мы рассмотрим изменения в программе для использования TASM32 .
После разбора программы из предыдущего шага возникает вопрос по поводу ее реализации на ассемблере TASM. В действительности здесь требуются минимальные изменения:
tasm32 /ml pr13_1.asm tlink32 -aa pr13_1.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:\tasm32\lib\import32.lib ;Структуры. ;Структура сообщения. MSGSTRUCT STRUC MSHWND DD ? ;Идентификатор окна, получающего сообщение. MSMESSAGE 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 ;----------------------------------------- ;Процедура окна. ;Расположение параметров в стеке: ;[ЕВР+014Н] LPARAM ;[ЕВР+10Н] WAPARAM ;[ЕВР+0СН] MES ;[ЕВР+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 ;МВ_ОК 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
Кстати заметьте, что исполняемый модуль, транслируемый в TASM32, всегда несколько длиннее аналогичного модуля, транслируемого с помощью пакета MASM32.
Обратите внимание на то, как задаются свойства окон. Описание этих свойств можно найти в программе помощи для функции CreateWindow.
В принципе, подбор необходимых сочетаний свойств окна — довольно кропотливое занятие. Это одна из причин, из-за которой понятие ресурса стало неотъемлемой частью загружаемого модуля.
Приведенные примеры показывают, что процедура окна должна правильно реагировать на пришедшие сообщения. В дальнейшем вы узнаете, что и сама процедура может посылать сообщения приложению, другим окнам, а также своему окну.
Часть API-функций получила суффикс "А". Дело в том, что функции имеют два прототипа:
На следующем шаге мы рассмотрим передачу параметров через стек.