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

       

Если вы только начинаете программировать под Windows



I

Если вы только начинаете программировать под Windows, то в программе на Рисунок 2.1.1 найдете много нового. Поэтому приступим к подробному разбору программы.

  1. В данной программе мы определяем цвет окна и текста через комбинацию трех цветов: красного, зеленого и синего. Цвет определяется одним 32-битным числом. В этом числе первый байт - интенсивность красного, второй байт - интенсивность зеленого, третий байт - интенсивность синего цвета. Последний байт равен нулю. Механизм получения этого числа продемонстрирован в определении константы RGBW.
  2. Цвет окна задается посредством определения кисти через функцию CreateSolidBrush.
  3. Поскольку при перерисовке окна системой посылается сообщение WM_PAINT, именно при получении этого сообщения и следует перерисовывать содержимое этого окна. В данном случае мы выводим всего лишь одну строку текста. Для того чтобы осуществить вывод информации в окно, необходимо сначала получить контекст окна (контекст устройства - Device Context). Для нас это — просто некоторое число, посредством которого осуществляется связь между приложением и окном. Обычно контекст устройства определяется посредством функции GetDC. При получении сообщения WM_PAINT контекст устройства получается посредством функции BeginPaint. Аргументом для этой функции является указатель на специальную структуру, которая у нас называется PAINTSTR и поля которой, впрочем, мы пока не используем.
  4. Текст, как Вы уже, надеюсь, поняли из текста программы, выводится посредством функции OutText. Предварительно, посредством функций SetBkColor и SetTextColor, мы определяем цвет фона и цвет букв. Цвет фона, соответственно, совпадает с цветом окна.
  5. Несколько слов о системе координат. Центр системы координат находится в левом верхнем углу, ось Y направлена вниз, ось Х - вправо. Впрочем, это общепринятый вариант для графических экранов.
  6. Еще один момент также связан с выводом текста в окно. Одним из параметров функции OutText является количество символов выводимой строки. И здесь начинается самое интересное. Определить длину строки (за минусом нулевого элемента) можно по-разному. Например, можно использовать операторы макроассемблера SIZEOF или LENGTHOF. Но вот беда, в Турбо Ассемблере этих операторов нет. Можно, конечно, решить эту проблему, поставив метку в конце строки или используя старые директивы LENGTH и SIZE. Но, как Вы, наверное, уже поняли, для того чтобы легко переходить от MASM32 к TASM32, следует как можно меньше использовать макросредства. Кроме того, раз уже мы употребляем определение строк, как это принято в Си, — естественно и определить функции для работы со строковыми переменными (см. замечание в конце главы). В данном примере мы определили функцию, которая возвращает длину строки. Не смущайтесь, что функция помещает результат в регистр EBX. Нам просто так удобнее. У функции, кроме того, есть одно очень важное преимущество перед макросредствами - она получает длину при выполнении программы, а не во время ее трансляции.



  7. Теперь, чтобы добиться транслируемости программы на Турбо Ассемблере, нужно проделать те же манипуляции, которые мы производили раньше: убрать суффиксы @N и подключить библиотеку import32.lib.

    ; файл text1.inc ; константы ; сообщение приходит при закрытии окна WM_DESTROY equ 2 ; сообщение приходит при создании окна WM_CREATE equ 1 ; сообщение приходит при перерисовке окна WM_PAINT equ 0FH ; свойства окна CS_VREDRAW equ 1h CS_HREDRAW equ 2h CS_GLOBALCLASS equ 4000h WS_OVERLAPPEDWINDOW equ 000CF0000H stylcl equ CS_HREDRAW + CS_VREDRAW + CS_GLOBALCLASS DX0 equ 300 DY0 equ 200 ; компоненты цветов RED equ 50 GREEN equ 50 BLUE equ 255 RGBW equ (RED or (GREEN shl 8)) or (BLUE shl 16) RGBT equ 255 ; красный ; идентификатор стандартной иконки IDI_APPLICATION equ 32512 ; идентификатор курсора IDC_CROSS equ 32515 ; режим показа окна — нормальный SW_SHOWNORMAL equ 1 ; прототипы внешних процедур EXTERN CreateWindowExA@48:NEAR EXTERN DefWindowProcA@16:NEAR EXTERN DispatchMessageA@4:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetMessageA@16:NEAR EXTERN GetModuleHandleA@4:NEAR EXTERN LoadCursorA@8:NEAR EXTERN LoadIconA@8:NEAR EXTERN PostQuitMessage@4:NEAR EXTERN RegisterClassA@4:NEAR EXTERN ShowWindow@8:NEAR EXTERN TranslateMessage@4:NEAR EXTERN UpdateWindow@4:NEAR EXTERN BeginPaint@8:NEAR EXTERN EndPaint@8:NEAR EXTERN TextOutA@20:NEAR EXTERN GetStockObject@4:NEAR EXTERN CreateSolidBrush@4:NEAR EXTERN SetBkColor@8:NEAR EXTERN SetTextColor@8:NEAR ; структуры ; структура сообщения MSGSTRUCT STRUC MSHWND DD ? ; идентификатор окна, ; получающего сообщение MSMESSAGE DD ? ; идентификатор сообщения MSWPARAM DD ? ; доп. информация о сообщении MSLPARAM DD ? ; доп. информация о сообщении MSTIME DD ? ; время посылки сообщения MSPT DD ? ; положение курсора во время ; посылки сообщения MSGSTRUCT ENDS

    WNDCLASS STRUC CLSSTYLE DD ? ; стиль окна CLSLPFNWNDPROC DD ? ; указатель на процедуру окна CLSCBCLSEXTRA DD ? ; информация о доп. байтах для ; данной структуры CLSCBWNDEXTRA DD ? ; информация о доп. байтах для окна CLSHINSTANCE DD ? ; дескриптор приложения CLSHICON DD ? ; идентификатор иконы окна CLSHCURSOR DD ? ; идентификатор курсора окна CLSHBRBACKGROUND DD ? ; идентификатор кисти окна MENNAME DD ? ; имя-идентификатор меню CLSNAME DD ? ; специфицирует имя класса окон WNDCLASS ENDS



    PAINTSTR STRUC hdc DWORD 0 fErase DWORD 0 left DWORD 0 top DWORD 0 right DWORD 0 bottom DWORD 0 fRes DWORD 0 fIncUp DWORD 0 Reserv DB 32 dup(0) PAINTSTR ENDS

    ; файл text1.asm .386P ; плоская модель .MODEL FLAT, stdcall ;------------------------------------------------------------ include text1.inc ; подключения библиотек 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 <?> HINST DD 0 TITLENAME DB 'Текст в окне',0 NAM DB 'CLASS32',0 XT DWORD 30 YT DWORD 30 TEXT DB 'Текст в окне красный',0 _DATA ENDS

    ; сегмент кода _TEXT SEGMENT DWORD PUBLIC USE32 'CODE' START: ; получить дескриптор приложения PUSH 0 CALL GetModuleHandleA@4 MOV [HINST], EAX REG_CLASS: ; заполнить структуру окна стиль MOV [WC.CLSSTYLE] , stylcl ; процедура обработки сообщений MOV [WC.CLSLPFNWNDPROC], OFFSET WNDPROC MOV [WC.CLSCBCLSEXTRA],0 MOV [WC.CLSCBWNDEXTRA],0 MOV EAX, [HINST] MOV [WC.CLSHINSTANCE],EAX ; иконка окна PUSH IDI_APPLICATION PUSH 0 CALL LoadIconA@8 MOV [WC.CLSHICON], EAX ;----------курсор окна PUSH IDC_CROSS PUSH 0 CALL LoadCursorA@8 MOV [WC.CLSHCURSOR],EAX PUSH RGBW ; цвет кисти CALL CreateSolidBrush@4 ; создать кисть MOV [WC.CLSHBRBACKGROUND],EAX MOV DWORD PTR [WC.MENNAME],0 MOV DWORD PTR [WC.CLSNAME], OFFSET NAM PUSH OFFSET WC CALL RegisterClassA@4 ; создать окно зарегистрированного класса PUSH 0 PUSH [HINST] PUSH 0 PUSH 0 PUSH DY0 ; DY0 - высота окна PUSH DX0 ; DX0 - ширина окна PUSH 100 ; координата Y PUSH 100 ; координата X PUSH WS_OVERLAPPEDWINDOW PUSH OFFSET TITLENAME ; имя окна PUSH OFFSET NAM ; имя класса PUSH 0 CALL CreateWindowExA@48 ; проверка на ошибку CMP EAX, 0 JZ _ERR MOV [NEWHWND], EAX ; дескриптор окна ;------------------------------------------------------------ PUSH SW_SHOWNORMAL PUSH [NEWHWND] CALL ShowWindow@8 ; показать созданное окно ; ———————————————————— PUSH [NEWHWND] CALL UpdateWindow@4 ; перерисовать видимую часть окна ; петля обработки сообщений MSG_LOOP: PUSH 0 PUSH 0 PUSH 0 PUSH OFFSET MSG CALL GetMessageA@16 CMP AX, 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 ; процедура окна ; расположение параметров в стеке ; [EBP+014Н] ; LPARAM ; [EBP+10H] ; 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_DESTROY JE WMDESTROY CMP DWORD PTR [EBP+0CH], WM_CREATE JE WMCREATE CMP DWORD PTR [EBP+0CH], WM_PAINT JE WMPAINT JMP DEFWNDPROC WMPAINT: PUSH OFFSET PNT PUSH DWORD PTR [EBP+08H] CALL BeginPaint@8 PUSH EAX ; сохранить контекст (дескриптор) ;---------------- цвет фона = цвет окна PUSH RGBW PUSH EAX CALL SetBkColor@8 ;---------------- контекст POP EAX PUSH EAX ;---------------- цвет текста (красный) PUSH RGBT PUSH EAX CALL SetTextColor@8 ;---------------- контекст POP EAX ;---------------- вывести текст PUSH OFFSET TEXT CALL LENSTR PUSH EBX ; длина строки PUSH OFFSET TEXT ; адрес строки PUSH YT ; Y PUSH XT ; X PUSH EAX ; контекст окна CALL TextOutA@20 ;---------------- закрыть PUSH OFFSET PNT PUSH DWORD PTR [EBP+08H] CALL EndPaint@8 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@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

    ;----------- функция -------------------------- ; длина строки ; [EBP+08H] - указатель на строку 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 _TEXT ENDS END START


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