Шаг 19.
Пример программы. Вывод текста в окне

    На этом шаге мы рассмотрим пример вывода текста в окне.

    В примере программы, приведенной на этом шаге, можно найти много нового. Поэтому приступим к подробному разбору программы.

  1. В данной программе мы определяем цвет окна и текста через комбинацию трех цветов: красного, зеленого и синего. Цвет определяется одним 32-битным числом. В этом числе первый байт - интенсивность красного, второй байт - интенсивность зеленого, третий байт - интенсивность синего цвета. Последний байт равен нулю. Механизм получения этого числа продемонстрирован в определении константы RGBW:
          RGBW        equ (RED or (GREEN shl 8)) or (BLUE shl 16)
    

  2. Цвет окна задается посредством определения кисти через функцию CreateSolidBrush.

  3. Поскольку при перерисовке окна системой посылается сообщение WM_PAINT, именно при получении этого сообщения и следует перерисовывать содержимое этого окна. В данном случае мы выводим всего лишь одну строку текста. Для того чтобы осуществить вывод информации в окно, необходимо сначала получить контекст окна (контекст устройства - Device Context). Для нас это - просто некоторое число, посредством которого осуществляется связь между приложением и окном. Обычно контекст устройства определяется посредством функции GetDC. При получении сообщения WM_PAINT контекст устройства получается посредствомфункции BeginPaint. Аргументом для этой функции является указатель на специальную структуру, которая у нас называется PAINTSTR и поля которой, впрочем, мы пока не используем:
    WMPAINT:
    ;--------------------------
            PUSH OFFSET PNT  ;Адрес структуры.
            PUSH DWORD PTR [EBP+08H]  ;Дескриптор приложения.
            CALL BeginPaint@8
            PUSH EAX ;Сохранить контекст (дескриптор)
    

  4. Текст выводится посредством функции OutText. Предварительно, посредством функций SetBkColor и SetTextColor, мы определяем цвет фона и цвет букв. Цвет фона, соответственно, совпадает с цветом окна:
    ;------------------------ цвет фона = цвет окна
            PUSH RGBW
            PUSH EAX
            CALL SetBkColor@8
    ;------------------------ цвет текста (красный)
            PUSH RGBT
            PUSH EAX
            CALL SetTextColor@8
    

  5. Несколько слов о системе координат. Центр системы координат находится в левом верхнем углу, ось Y направлена вниз, ось X - вправо. Впрочем, это общепринятый вариант для графических экранов.

  6. Еще один момент также связан с выводом текста в окно. Одним из параметров функции OutText является количество символов выводимой строки. И здесь начинается самое интересное. Определить длину строки (за минусом нулевого элемента) можно по-разному. Например, можно использовать операторы макроассемблера SIZEOF или LENGTHOF. Но в Турбо Ассемблере этих операторов нет. Можно, конечно, решить эту проблему, поставив метку в конце строки или используя старые директивы LENGTH и SIZE. Но, как вы, наверное, уже поняли, для того чтобы легко переходить от MASM32 к TASM32, следует как можно меньше использовать макросредства. Кроме того, раз уже мы употребляем определение строк, как это принято в Си, - естественно и определить функции для работы со строковыми переменными. В данном примере мы определили функцию, которая возвращает длину строки. Не смущайтесь, что функция помещает результат в регистр ЕВХ. Нам просто так удобнее. У функции, кроме того, есть одно очень важное преимущество перед макросредствами - она получает длину при выполнении программы, а не во время ее трансляции.

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


    Заголовочный файл для приложения, содержащий определения констант, внешних процедур и структур (его имя pr19_1.asm):
;Константы.
;Сообщение приходит при  закрытии окна.
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_ARROW         equ  32512
;Режим показа окна - нормальный.
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 ? ;Стиль окна.
           CLWNDPROC    DD ? ;Указатель на процедуру окна.
           CLSCBCLSEX   DD ? ;Информация о доп. байтах для данной структуры.
           CLSCBWNDEX   DD ? ;Информация о доп. байтах для окна.
           CLSHINST     DD ? ;Дескриптор приложения.
           CLSHICON     DD ? ;Идентификатор иконки окна.
           CLSHCURSOR   DD ? ;Идентификатор курсора окна.
           CLBKGROUND   DD ? ;Идентификатор кисти окна.
           CLMENNAME    DD ? ;Имя-идентификатор меню.
           CLNAME       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
Текст этого модуля можно взять здесь.


    Основной файл приложения содержит подключение файла pr19_1.asm (его имя pr19_2.asm):
.386P
;Плоская модель.
.MODEL FLAT, STDCALL
include pr19_1.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 <?>
     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.CLWNDPROC], OFFSET WNDPROC
     MOV   [WC.CLSCBCLSEX], 0
     MOV   [WC.CLSCBWNDEX], 0
     MOV   EAX, [HINST]
     MOV   [WC.CLSHINST], EAX
 
;------------ пиктограмма окна
    PUSH   IDI_APPLICATION
    PUSH   0
    CALL   LoadIconA@8
    MOV    [WC.CLSHICON], EAX
;------------ курсор окна
    PUSH   IDC_ARROW
    PUSH   0
    CALL   LoadCursorA@8
    MOV    [WC.CLSHCURSOR], EAX
;------------
    PUSH   RGBW ;Цвет кисти.
    CALL   CreateSolidBrush@4;Создать кисть.
    MOV    [WC.CLBKGROUND],EAX 
    MOV    DWORD PTR [WC.CLMENNAME],0
    MOV    DWORD PTR [WC.CLNAME], 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   ;Команда перерисовать видимую
                          ;часть окна, сообщение 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
;-----------------------------------------
;Процедура окна.
;Расположение параметров в стеке: 
;[ЕВР+14Н] LPARAM 
;[ЕВР+10Н] WPARAM 
;[ЕВР+0СН] MES 
;[ЕВР+08H] 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                   ;MB_OK
        CALL PostQuitMessage@4   ;Сообщение WM_QUIT.
        MOV  EAX, 0
FINISH:	
        POP  EDI
        POP  ESI
        POP  EBX
        POP  EBP
        RET  16
WNDPROC ENDP
;---------------- ФУНКЦИЯ -----------------------
;Длина строки, [ЕВР+08Н] - указатель на строку.
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
Текст этой программы можно взять здесь.

    Результат работы программы можно увидеть на рисунке 1:


Рис.1. Внешний вид приложения

    На следующем шаге мы немного изменим приведенную на этом шаге программу.




Предыдущий шаг Содержание Следующий шаг