Ассемблер для Windows

Первый пример



I

Первый пример, рассматриваемый в данном разделе, представляет простейший пример таймера. Таймер отсчитывает десять тиков и закрывает диалоговое окно, выдавая MessageBox с сообщением об окончании работы программы. Данная программа являет собой пример организации таймера на базе самой функции окна.

Заметим, что начиная с данной главы большинство приводимых программ могут транслироваться и в пакете MASM32, и в пакете TASM32 без всяких изменений.

// файл timer.rc // определение констант #define WS_SYSMENU 0x00080000L #define WS_MINIMIZEBOX 0x00020000L #define WS_MAXIMIZEBOX 0x00010000L

// стиль - кнопка #define BS_PUSHBUTTON 0x00000000L // кнопка в окне должна быть видимой #define WS_VISIBLE 0x10000000L // центрировать текст на кнопке #define BS_CENTER 0x00000300L // стиль кнопки #define WS_CHILD 0х40000000L // возможность фокусировать элемент // при помощи клавиши TAB #define WS_TABSTOP 0x00010000L #define DS_3DLOOK 0x0004L //определение диалогового окна DIAL1 DIALOG 0, 0, 240, 120 STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK CAPTION "Пример диалогового окна с таймером" FONT 8, "Arial" { // кнопка, идентификатор 5 CONTROL "Выход", 5, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 180, 76, 50, 14 }

; файл timer.inc ; константы ; сообщение приходит при закрытии окна WM_CLOSE equ 10h WM_INITDIALOG equ 110h WM_COMMAND equ 111h WM_TIMER equ 113h

; прототипы внешних процедур IFDEF MASM EXTERN ReleaseDC@8:NEAR EXTERN GetDC@4:NEAR EXTERN TextOutA@20:NEAR EXTERN MessageBoxA@16:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN DialogBoxParamA@20:NEAR EXTERN EndDialog@8:NEAR EXTERN SendMessageA@16:NEAR EXTERN SetTimer@16:NEAR EXTERN KillTimer@8:NEAR ELSE EXTERN ReleaseDC:NEAR EXTERN GetDC:NEAR EXTERN TextOutA:NEAR EXTERN MessageBoxA:NEAR EXTERN ExitProcess:NEAR EXTERN GetModuleHandleA:NEAR EXTERN DialogBoxParamA:NEAR EXTERN EndDialog:NEAR EXTERN SendMessageA:NEAR EXTERN SetTimer:NEAR EXTERN KillTimer:NEAR ReleaseDC@8 = ReleaseDC GetDC@4 = GetDC TextOutA@20 = TextOutA MessageBoxA@16 = MessageBoxA ExitProcess@4 = ExitProcess GetModuleHandleA@4 = GetModuleHandleA DialogBoxParamA@20 = DialogBoxParamA EndDialog@8 = EndDialog SendMessageA@16 = SendMessageA SetTimer@16 = SetTimer KillTimer@8 = KillTimer ENDIF




; структуры ; структура сообщения MSGSTRUCT STRUC MSHWND DD ? MSMESSAGE DD ? MSWPARAM DD ? MSLPARAM DD ? MSTIME DD ? MSPT DD ? MSGSTRUCT ENDS

; файл timer.asm

.386P ; плоская модель .MODEL FLAT, stdcall include timer.inc ; директивы компоновщику для подключения библиотек IFDEF MASM ; для компоновщика LINK.EXE includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\gdi32.lib ELSE ; для компоновщика TLINK32.EXE includelib c:\tasm32\lib\import32.lib ENDIF ;-------------------------------------------------

; сегмент данных _DATA SEGMENT DWORD PUBLIC USE32 'DATA' MSG MSGSTRUCT <?> HINST DD 0 ; дескриптор приложения PA DB "DIAL1",0 COUNT DD 0 TEXT DB 0 CAP DB 'Сообщение',0 MES DB 'Выход по таймеру',0 _DATA ENDS

; сегмент кода

_TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; получить дескриптор приложения PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX ;---------------------------------------- PUSH 0 PUSH OFFSET WNDPROC PUSH 0 PUSH OFFSET PA PUSH [HINST] CALL DialogBoxParamA@20 CMP EAX,-1 JNE KOL KOL: ;---------------------------------------- PUSH 0 CALL ExitProcess@4 ;----------------------------------------

; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10Н] ; WAPARAM ; [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_CLOSE JNE L1 ; здесь реакция на закрытие окна L3: ; удалить таймер PUSH 1 ; идентификатор таймера PUSH DWORD PTR [EBP+08H] CALL KillTimer@8 ; закрыть диалог PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 JMP FINISH L1: CMP DWORD PTR [EBP+0CH], WM_INITDIALOG JNE L5 ; здесь начальная инициализация ; установить таймер PUSH 0 ; параметр = NULL PUSH 1000 ; интервал 1 с. PUSH 1 ; идентификатор таймера PUSH DWORD PTR [EBP+08H] CALL SetTimer@16 JMP FINISH L5: CMP DWORD PTR [EBP+0CH], WM_COMMAND JNE L2 ; кнопка выхода? CMP WORD PTR [EBP+10H],5 JNE FINISH JMP L3 L2: CMP DWORD PTR [EBP+0CH],WM_TIMER JNE FINISH ; не пора ли заканчивать ? CMP COUNT,9 ; выход без предупреждения JA L3 ; выход через сообщение JE L4 ; пришло сообщение таймера ; подготовить текст MOV EAX, COUNT ADD EAX,49 MOV TEXT, AL ; получить контекст PUSH DWORD PTR [EBP+08H] CALL GetDC@4 ; запомнить контекст PUSH EAX ; вывести значение счетчика PUSH 1 PUSH OFFSET TEXT PUSH 10 PUSH 10 PUSH EAX CALL TextOutA@20 ; удалить контекст POP EAX PUSH EAX PUSH DWORD PTR [EBP+08H] CALL ReleaseDC@8 ; увеличить счетчик INC COUNT JMP FINISH L4: INC COUNT ; сообщение о выходе по таймеру PUSH 0 PUSH OFFSET CAP PUSH OFFSET MES PUSH DWORD PTR [EBP+08H] ; дескриптор окна CALL MessageBoxA@16 JMP L3 FINISH: POP EDI POP ESI POP EBX POP EBP MOV EAX,0 RET 16 WNDPROC ENDP ;------------------------------------------------- _TEXT ENDS END START


Содержание раздела