На этом шаге мы рассмотрим работу программы, выводящей заданный текст под произвольным углом.
Здесь мы представляем вам небольшое приложение, реализованное студентом 4 курса факультета математики и информационных технологий Курганского государственного университета Парфеновым Максимом (декабрь 2005 г.).
Передо ним стояла задача создания приложения, позволяющего задать произвольный текст и вывести его под произвольным углом.
Перечислим возможности приложения.
Приведем текст приложения:
.386P ;Плоская модель. .MODEL FLAT, STDCALL include konst.asm ;Директивы компоновщику для подключения библиотек. includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\gdi32.lib ;------------------------------------------------ ;Сегмент данных. _DATA SEGMENT DWORD PUBLIC USE32 'DATA' NEWHWND DD 0 MSG MSGSTRUCT <?> WC WNDCLASS <?> PNT PAINTSTR <?> REC RECT <?> lg LOGFONT <?> CPEDT DB ' ',0 CLSEDIT DB 'EDIT',0 HWNDEDT DWORD 0 TITLENAME DB 'Задание №3',0 HINST DD 0 ;Дескриптор приложения. DLHINST DD 0 ;Дескриптор диалогового окна. CLASSNAME DB 'CLASS32',0 CAP DB 'Сообщение',0 CAP2 DB 'Вы выбрали угол : ',0 KAS DB 'Вы не ввели угол : ',0 MEN DB 'MENUP',0 NFONT DB 'Arial Cyr',0 PA DB 'DIAL1',0 HMENU DD ? X1 DD 0 X2 DD 0 A DD 0 LEN DD 0 PUSTO DB 4 DUP(0) BUF DB 4 DUP(0) BUF2 DB 4 DUP(0) SPOSOB DD 0 S1 DB 'Вы выбрали горизонтальное расположение текста',0 S2 DB 'Вы выбрали вертикальное расположение текста',0 S3 DB 'Вы выбрали расположение текста под углом',0 HDC DWORD ? MEMDC DWORD ? XM DWORD ? YM DWORD ? X DWORD 0 Y DWORD 0 TEXT DB 50 DUP (0) _DATA ENDS ;Сегмент кода. _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ;Получить дескриптор приложения. PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX REG_CLASS: ;Заполнить структуру окна. ;Стиль. MOV [WC.CLSSTYLE],STYLE ;Процедура обработки сообщений. MOV [WC.CLWNDPROC], OFFSET WNDPROC MOV [WC.CLSCBCLSEX], 0 MOV [WC.CLSCBWNDEX], 0 MOV EAX, [HINST] MOV [WC.CLSHINST], EAX ;------------ пиктограмма окна PUSH 1 PUSH [HINST] CALL LoadIconA@8 MOV [WC.CLSHICON], EAX ;------------ курсор окна PUSH 2 PUSH [HINST] CALL LoadCursorA@8 MOV [WC.CLSHCURSOR], EAX ;------------ MOV [WC.CLBKGROUND], 17 ;Цвет окна. MOV DWORD PTR [WC.CLMENNAME], OFFSET MEN MOV DWORD PTR [WC.CLNAME], OFFSET CLASSNAME PUSH OFFSET WC CALL RegisterClassA@4 ;Создать окно зарегистрированного класса. PUSH 0 PUSH [HINST] PUSH 0 PUSH 0 PUSH 400 ; DY - высота окна. PUSH 600 ; DX - ширина окна. PUSH 100 ; Y - координата левого верхнего угла. PUSH 100 ; X - координата левого верхнего угла. PUSH WS_OVERLAPPEDWINDOW PUSH OFFSET TITLENAME ;Имя окна. PUSH OFFSET CLASSNAME ;Имя класса. PUSH 0 CALL CreateWindowExA@48 ;Проверка на ошибку. CMP EAX,0 JZ _ERR MOV [NEWHWND], EAX ;Дескриптор окна. ;Определить идентификатор меню. PUSH EAX CALL GetMenu@4 MOV HMENU,EAX PUSH SW_SHOWNORMAL PUSH [NEWHWND] CALL ShowWindow@8 ;Показать созданное окно. ;------------------------------------ PUSH [NEWHWND] CALL UpdateWindow@4 ;Команда перерисовать видимую ;часть окна, сообщение WM_PAINT. ;Цикл обработки сообщений MSG_LOOP: PUSH 0 PUSH 0 PUSH 0 PUSH OFFSET MSG CALL GetMessageA@16 CMP EAX, 0 JE END_LOOP PUSH OFFSET MSG CALL TranslateMessage@4 PUSH OFFSET MSG CALL DispatchMessageA@4 JMP MSG_LOOP END_LOOP: ;Выход из программы (закрыть процесс). PUSH [MSG.MSWPARAM] CALL ExitProcess@4 _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 ;Cообщение WM_DESTROY - при закрытии окна. CMP DWORD PTR [EBP+0CH], WM_DESTROY JE WMDESTROY ;Сообщение WM_CREATE - при создании окна. CMP DWORD PTR [EBP+0CH], WM_LBUTTONDOWN JE LBUTTON CMP DWORD PTR [EBP+0CH], WM_CREATE JE WMCREATE ;Сообщение WM_COMMAND - при событиях ;с элементами на окне. CMP DWORD PTR [EBP+0CH],WM_COMMAND JE WMCOMMND CMP DWORD PTR [EBP+0CH], WM_PAINT JE WMPAINT ;Остальные события возвращаем обратно. JMP DEFWNDPROC LBUTTON: PUSH OFFSET TEXT PUSH 50 ; получаем строку из поля редактирования PUSH WM_GETTEXT PUSH HWNDEDT CALL SendMessageA@16 MOV EAX,0H MOV AX,WORD PTR [EBP+14H] MOV Y,EAX ; сохраняем координаты щелчка MOV EAX,0H MOV AX,WORD PTR [EBP+16H] MOV X,EAX CMP SPOSOB, 2 JE M2 CMP SPOSOB, 3 ; проверяем какой был выбран способ вывода текста JE M3 CMP SPOSOB, 4 JE M4 JMP FINISH M2: MOV lg.LfEscapement,0 ;горизонтально JMP VSE M3: MOV lg.LfEscapement,900 ;вертикально JMP VSE M4: ; под углом PUSH OFFSET BUF2 CALL LENSTR MOV LEN,EBX CMP LEN,0 ;проверяем, введен ли угол JNE DALS PUSH 0 PUSH OFFSET CAP PUSH OFFSET KAS PUSH DWORD PTR [EBP+08H] ;Дескриптор окна. CALL MessageBoxA@16 JMP FINISH DALS: PUSH OFFSET BUF2 CALL PEREVOD ; перевод строки в число XOR EBX,EBX MOV EBX,X1 MOV lg.LfEscapement,EBX VSE: MOV lg.LfHeight,12 ;Высота шрифта. MOV lg.LfWidth,9 ;Ширина шрифта. MOV lg.LfOrientation,0 ;вертикальная. MOV lg.LfWeight,400 ;Толщина линий шрифта. MOV lg.LfItalic,0 ;курсив MOV lg.LfUnderline,0 ;Подчеркивание. MOV lg.LfStrikeOut,0 ;Перечеркивание. MOV lg.LfCharSet,0 ;Набор шрифтов. MOV lg.LfOutPrecision,0 MOV lg.LfClipPrecision,0 MOV lg.LfQuality,2 MOV lg.LfPitchAndFamily,0 PUSH OFFSET lg ;Задать название шрифта. PUSH OFFSET NFONT PUSH OFFSET lg.LfFaceName CALL COPYSTR CALL CreateFontIndirectA@4 ;-------------------- выбрать созданный объект PUSH EAX PUSH MEMDC CALL SelectObject@8 ;-------------------- вывести PUSH OFFSET TEXT CALL LENSTR PUSH EBX ;Длина строки. PUSH OFFSET TEXT ;Адрес строки. PUSH X PUSH Y PUSH MEMDC ;Контекст окна. CALL TextOutA@20 ; выводим текст. KONEC: ;Дать команду перерисовать окно. PUSH 0 PUSH OFFSET RECT PUSH DWORD PTR [EBP+08H] CALL InvalidateRect@12 JMP FINISH WMCOMMND: ;Проверить, не выбран ли пункт меню MENUC - выход. CMP WORD PTR [EBP+10H],1 JE WMDESTROY CMP WORD PTR [EBP+10H],5 JE CHISTO CMP WORD PTR [EBP+10H],2 JE GORIZ CMP WORD PTR [EBP+10H],3 JE VERT CMP WORD PTR [EBP+10H],4 JE DIAG JMP FINISH GORIZ: MOV EAX,2 MOV SPOSOB,EAX PUSH OFFSET PUSTO PUSH OFFSET BUF2 CALL COPYSTR ;очищаем BUF2 PUSH 0 ;MB_OK PUSH OFFSET CAP PUSH OFFSET S1 PUSH DWORD PTR [EBP+08H] ;Дескриптор окна. CALL MessageBoxA@16 JMP FINISH VERT: MOV EAX,3 MOV SPOSOB,EAX PUSH OFFSET PUSTO PUSH OFFSET BUF2 CALL COPYSTR ;очищаем BUF2 PUSH 0 ;MB_OK PUSH OFFSET CAP PUSH OFFSET S2 PUSH DWORD PTR [EBP+08H] ;Дескриптор окна. CALL MessageBoxA@16 JMP FINISH DIAG: MOV EAX,4 MOV SPOSOB,EAX PUSH 0 CALL GetModuleHandleA@4 MOV [DLHINST], EAX ;------------------------------------- PUSH 0 PUSH OFFSET DIALPROC PUSH 0 PUSH OFFSET PA PUSH [DLHINST] CALL DialogBoxParamA@20 ;------------------------------------- CMP EAX,-1 JNE KOL KOL: JMP MSG_LOOP PUSH 0 CALL ExitProcess@4 ;------------------------------------- JMP FINISH ;Заполнить данную прямоугольную область. CHISTO: PUSH RGBW CALL CreateSolidBrush@4 ;Создать кисть. ;Выбрать кисть в данном контексте. PUSH EAX PUSH MEMDC CALL SelectObject@8 PUSH 0F00021h ;PATCOPY=заполнить данным цветом. PUSH YM PUSH XM PUSH 0 PUSH 0 PUSH MEMDC CALL PatBlt@24 PUSH 0 PUSH OFFSET RECT PUSH DWORD PTR [EBP+08H] CALL InvalidateRect@12 JMP FINISH WMPAINT: ;-------------------------- PUSH OFFSET PNT PUSH DWORD PTR [EBP+08H] CALL BeginPaint@8 MOV HDC,EAX ;Сохранить контекст (дескриптор) ;Скопировать виртуальное окно на реальное. PUSH 0CC0020h ;SRCCOPY=Изображение как есть PUSH 21 ;у источника. PUSH 0 ;х источника. PUSH MEMDC ;Контекст источника. PUSH YM ;Высота куда. PUSH XM ;Ширина куда. PUSH 21 ;у куда. PUSH 0 ;х куда. PUSH HDC ;Контекст куда. CALL BitBlt@36 ;---------------------- закрыть контекст окна PUSH OFFSET PNT PUSH DWORD PTR [EBP+08H] CALL EndPaint@8 MOV EAX, 0 JMP FINISH WMCREATE: ;Размеры экрана. PUSH 0 ;X CALL GetSystemMetrics@4 MOV XM,EAX PUSH 1 ;Y CALL GetSystemMetrics@4 MOV YM,EAX ;Открыть контекст окна. PUSH DWORD PTR [EBP+08H] CALL GetDC@4 MOV HDC,EAX ;Создать совместимый с данным окном контекст. PUSH EAX CALL CreateCompatibleDC@4 MOV MEMDC,EAX ;Создать в памяти растровое изображение, совместимое с hdc. PUSH YM PUSH XM PUSH HDC CALL CreateCompatibleBitmap@12 ;Выбрать растровое изображение в данном контексте. PUSH EAX PUSH MEMDC CALL SelectObject@8 ;Цвет кисти PUSH RGBW CALL CreateSolidBrush@4 ;Создать кисть. ;Выбрать кисть в данном контексте. PUSH EAX PUSH MEMDC CALL SelectObject@8 ;Заполнить данную прямоугольную область. PUSH 0F00021h ;PATCOPY=заполнить данным цветом. PUSH YM PUSH XM PUSH 0 PUSH 0 PUSH MEMDC CALL PatBlt@24 ;Удалить контекст. PUSH HDC PUSH DWORD PTR [EBP+08H] CALL ReleaseDC@8 MOV EAX, 0 ;Создать окно редактирования. PUSH 0 PUSH [HINST] PUSH 0 PUSH DWORD PTR [EBP+08H] PUSH 20 ;DY PUSH 150 ;DX PUSH 0 ;Y PUSH 250 ;X PUSH STYLEDT PUSH OFFSET CPEDT ;Имя окна. PUSH OFFSET CLSEDIT ;Имя класса. PUSH 0 CALL CreateWindowExA@48 MOV HWNDEDT,EAX PUSH HWNDEDT CALL SetFocus@4 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@16 JMP FINISH WMDESTROY: PUSH 0 CALL PostQuitMessage@4 ;Сообщение WM_QUIT. MOV EAX, 0 FINISH: POP EDI POP ESI POP EBX POP EBP RET 16 WNDPROC ENDP PEREVOD PROC PUSH EBP MOV EBP,ESP PUSH ESI MOV ESI,DWORD PTR [EBP+08H] MOV X1,0 MOV X2,0 CHIS : XOR EBX,EBX CMP BYTE PTR [ESI],'0' JE P INC EBX CMP BYTE PTR [ESI],'1' JE P INC EBX CMP BYTE PTR [ESI],'2' JE P INC EBX CMP BYTE PTR [ESI],'3' JE P INC EBX CMP BYTE PTR [ESI],'4' JE P INC EBX CMP BYTE PTR [ESI],'5' JE P INC EBX CMP BYTE PTR [ESI],'6' JE P INC EBX CMP BYTE PTR [ESI],'7' JE P INC EBX CMP BYTE PTR [ESI],'8' JE P INC EBX CMP BYTE PTR [ESI],'9' P: INC ESI MOV A,EBX CMP LEN,1 JE P3 CMP LEN,2 JE P2 CMP LEN,3 JE P1 JMP EN P1: MOV EAX,A MOV EDX,100 IMUL EDX ;Умножение на 100. MOV X1,EAX DEC LEN JMP CHIS P2: MOV EAX,A MOV EDX,10 IMUL EDX ;Умножение на 10. MOV X2,EAX DEC LEN JMP CHIS P3: MOV EAX,A ADD EAX,X1 ;Прибавим X1. ADD EAX,X2 ;Прибавим X2. MOV X1,EAX MOV EAX,X1 MOV EDX,10 IMUL EDX ;Умножение на 10. MOV X1,EAX EN: POP ESI POP EBP RET 4 PEREVOD ENDP LENSTR PROC PUSH EBP MOV EBP,ESP PUSH ESI MOV ESI,DWORD PTR [EBP+8] XOR EBX,EBX LBL1: CMP BYTE PTR [ESI],0 JZ LBL2 INC EBX INC ESI JMP LBL1 LBL2: POP ESI POP EBP RET 4 LENSTR ENDP COPYSTR PROC PUSH EBP MOV EBP,ESP MOV ESI,DWORD PTR [EBP+0CH] MOV EDI,DWORD PTR [EBP+08H] L1: MOV AL, BYTE PTR [ESI] MOV BYTE PTR [EDI], AL CMP AL,0 JE L2 INC ESI INC EDI JMP L1 L2: POP EBP RET 8 COPYSTR ENDP DIALPROC PROC PUSH EBP MOV EBP, ESP PUSH EBX PUSH ESI PUSH EDI ;------------------------------------- CMP DWORD PTR [EBP+0CH],WM_INITDIALOG JE MET1 CMP DWORD PTR [EBP+0CH] ,WM_COMMAND JE COM MET1: MOV EAX,0 JMP KONETC COM: CMP WORD PTR [EBP+10H], 6 JE DELAJ CMP WORD PTR [EBP+10H], 7 JE EXT2 CMP DWORD PTR [EBP+10H], 8 JE SHOW JMP KONETC DELAJ: PUSH OFFSET BUF PUSH 20 PUSH WM_GETTEXT PUSH 6 PUSH DWORD PTR [EBP+08H] CALL SendDlgItemMessageA@20 JMP KONETC SHOW: PUSH OFFSET BUF CALL LENSTR CMP EBX,0 JE NEVVOD PUSH OFFSET BUF PUSH OFFSET BUF2 CALL COPYSTR PUSH 0 PUSH OFFSET CAP2 PUSH OFFSET BUF2 PUSH DWORD PTR [EBP+08H] ;Дескриптор окна. CALL MessageBoxA@16 JMP EXT2 NEVVOD: PUSH 0 PUSH OFFSET CAP PUSH OFFSET KAS PUSH DWORD PTR [EBP+08H] ;Дескриптор окна. CALL MessageBoxA@16 JMP KONETC EXT2: PUSH 0 PUSH DWORD PTR [EBP+08H] CALL EndDialog@8 KONETC: POP EDI POP ESI POP EBX POP EBP RET 16 DIALPROC ENDP _TEXT ENDS END START
Результат работы приложения изображен на рисунке 1:
Рис.1. Результат работы приложения
Перечислим используемые процедуры.
Приведем краткое описание приложения.
В процедуре окна обрабатываются следующие сообщения:
Меню:
Диалоговое окно:
При щелчке левой кнопкой мыши:
Со следующего шага мы дадим краткий обзор отладчиков и дизассемблеров.