Шаг 125.
Небольшое отступление: изменение цвета фона окна приложения

    На этом шаге мы рассмотрим пример программы, в которой меняется цвет фона окна приложения.

    Студент 4 курса факультета математики и информационных технологий Курганского государственного университета (2006-07 уч.год) Борзов Виталий Викторович представляет решение следующей задачи: в приложении имеется список цветов. Выбор соответствующего цвета приводит к изменению текущего цвета фона окна приложения в соответствии со сделанным выбором.

    В данной программе изменение цвета фона окна реализовано с помощью API-функций SetClassLong и RedrawWindow.

    Функция

DWORD SetClassLong (
    HWND hWnd,	
    int nIndex,	
    LONG dwNewLong
   );

помещает значение dwNewLong в структуру окна с дескриптором hWnd. Элемент структуры, в который помещается новое значение, определяется параметром nIndex. В нашем примере, чтобы изменить элемент структуры, в котором хранится дескриптор кисти фона, мы передаем в качестве параметра nIndex значение константы GCL_HBRBACKGROUND. Соответствующие константы имеются для каждого элемента структуры окна (см. справку по функциям Windwos API).

    Функция

BOOL RedrawWindow(
    HWND hWnd,	
    CONST RECT *lprcUpdate,	
    HRGN hrgnUpdate,	
    UINT flags 	
   );

обновляет заданный прямоугольник (lprcUpdate) или область (hrgnUpdate) клиентской части окна (hWnd). Если оба параметра lprcUpdate и hrgnUpdate имеют нулевое значение, то перерисовывается вся клиентская область окна. Способ перерисовки определяется параметром flags. В нашем примере константа RDW_FLAGS является комбинацией констант RDW_ERASE и RDW_INVALIDATE. Использование константы RDW_ERASE означает, что при перерисовке окна произойдет стирание фона окна. Но этого не произойдет без добавления константы RDW_INVALIDATE.

    Приведем текст приложения.

.386P
;Плоская модель.
.MODEL FLAT, STDCALL
include pr_h.asm
;Директивы компоновщику для подключения библиотек.
includelib \masm32\lib\user32.lib 
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     NEWHWND     DD 0
     MSG         MSGSTRUCT <?>
     WC          WNDCLASS <?>
     HINST       DD 0 ;Здесь хранится дескриптор приложения.
     TITLENAME   DB 'Изменение цвета фона',0
     CLASSNAME   DB 'CLASS32',0
     BRUSH       DWORD ? ; Дескриптор кисти.
     BGCOLOR     DWORD ? ; Цвет фона.
;-----
     CPEDT       DB ' ',0
     CLSEDIT     DB 'EDIT',0
     HWNDEDT     DWORD 0
;-----
     CPBUT       DB 'Выход',0 ;Выход.
     CPBUT2      DB 'Выбрать',0; Выбрать.
     CPLST       DB ' ',0
     CLSLIST     DB 'LISTBOX',0
     CLSBUTN     DB 'BUTTON',0
     HWNDBTN     DWORD 0 ;Дескриптор кнопки "Выход".
     HWNDBTN2    DWORD 0 ;Дескриптор кнопки "Выбрать".
     HWNDLST     DWORD 0
     BUF         DB  30 DUP(0)
     ;Массив строк.
     STR1        DB 'Красный',0
     STR2        DB 'Зеленый',0
     STR3        DB 'Синий',0
     STR4        DB 'Желтый',0
     STR5        DB 'Черный',0
     STR6        DB 'Белый',0
     ;Указатели на строки.
     PS          DWORD OFFSET  STR1
                 DWORD OFFSET  STR2
                 DWORD OFFSET  STR3
                 DWORD OFFSET  STR4
                 DWORD OFFSET  STR5
                 DWORD OFFSET  STR6
_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   IDI_APPLICATION
    PUSH   0
    CALL   LoadIconA@8
    MOV    [WC.CLSHICON], EAX
;------------ Курсор окна.
    PUSH   IDC_ARROW
    PUSH   0
    CALL   LoadCursorA@8
    MOV    [WC.CLSHCURSOR], EAX
;------------
    PUSH   00555555H ;Цвет кисти.
    CALL   CreateSolidBrush@4;Создать кисть.
    MOV    [WC.CLBKGROUND],EAX 
;-------------
    MOV    DWORD PTR [WC.CLMENNAME],0
    MOV    DWORD PTR [WC.CLNAME], OFFSET  CLASSNAME
    PUSH   OFFSET WC
    CALL   RegisterClassA@4
;Создать окно зарегистрированного класса.
    PUSH   0
    PUSH   [HINST]
    PUSH   0
    PUSH   0
    PUSH   200 ;  DY - высота окна.
    PUSH   250 ;  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  SW_SHOWNORMAL
    PUSH  [NEWHWND]
    CALL  ShowWindow@8      ;Показать созданное окно.
;------------------------------------
;Цикл обработки сообщений. 
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_COMMAND
        JE   WMCOMMND
        JMP  DEFWNDPROC
WMCOMMND:
        MOV  EAX,HWNDBTN
        CMP  DWORD PTR [EBP+14H], EAX ;Кнопка выхода?
        JE   WMDESTROY
        MOV  EAX, HWNDBTN2 
        CMP  DWORD PTR [EBP+14H], EAX ;Кнопка выбора?
        JNE  NOLIST

;Сначала индекс.
        PUSH 0
        PUSH 0
        PUSH LB_GETCURSEL
        PUSH HWNDLST
        CALL SendMessageA@16
;Теперь сам текст.
        PUSH OFFSET BUF
        PUSH EAX  
        PUSH LB_GETTEXT
        PUSH HWNDLST
        CALL SendMessageA@16
;Помещаем текст в строку редактирования.
        PUSH OFFSET BUF
        PUSH 0
        PUSH WM_SETTEXT 
        PUSH HWNDEDT
        CALL SendMessageA@16
;Определяем выбранный цвет.
        MOV ECX,7
        LEA EDI,STR1
        CALL CMPSTR
        CMP ECX,0     ; Красный?
        JNE NORED           
        MOV BGCOLOR,00000099H
        JMP CHANGE 
NORED: 
        MOV ECX,7
        LEA EDI,STR2
        CALL CMPSTR
        CMP ECX,0     ; Зеленый?
        JNE NOGREEN
        MOV BGCOLOR,00009900H
        JMP CHANGE
NOGREEN: 
        MOV ECX,5
        LEA EDI,STR3
        CALL CMPSTR
        CMP ECX,0
        JNE NOBLUE    ; Синий?
        MOV BGCOLOR,00990000H
        JMP CHANGE
NOBLUE:
        MOV ECX,6
        LEA EDI,STR4
        CALL CMPSTR
        CMP ECX,0
        JNE NOYELLOW  ; Желтый?
        MOV BGCOLOR,0000FFFFH
        JMP CHANGE
NOYELLOW:
        MOV ECX,6
        LEA EDI,STR5
        CALL CMPSTR
        CMP ECX,0
        JNE NOBLACK  ; Черный?
        MOV BGCOLOR,0
        JMP CHANGE
NOBLACK:
        MOV BGCOLOR,00FFFFFFH


;Изменяем цвет фона окна.
CHANGE:    
    PUSH BGCOLOR
    CALL CreateSolidBrush@4 ; Создаем кисть с выбранным цветом.
    MOV  BRUSH,EAX

    PUSH BRUSH
    PUSH GCL_HBRBACKGROUND  
    PUSH [NEWHWND]
    CALL SetClassLongA@12  ; Помещаем дескриптор кисти в структуру,
                           ; описывающую окно
    PUSH RDW_FLAGS
    PUSH 0
    PUSH 0
    PUSH [NEWHWND]
    CALL RedrawWindow@16  ; Перерисовываем окно.
NOLIST:
        MOV  EAX, 0
        JMP FINISH 
WMCREATE:	
;Создать окно-кнопку.
        PUSH 0
        PUSH [HINST]
        PUSH 0
        PUSH DWORD PTR [EBP+08H]
        PUSH 20  ;DY
        PUSH 60  ;DX
        PUSH 10  ;Y
        PUSH 10  ;X
        PUSH STYLBTN
        PUSH OFFSET CPBUT   ;Имя окна.
        PUSH OFFSET CLSBUTN ;Имя класса.
        PUSH 0
        CALL CreateWindowExA@48
        MOV  HWNDBTN,EAX    ;Запомнить дескриптор кнопки.
;Создать окно выбора.
        PUSH 0
        PUSH [HINST]
        PUSH 0
        PUSH DWORD PTR [EBP+08H]
        PUSH 20  ;DY
        PUSH 70  ;DX
        PUSH 10  ;Y
        PUSH 80  ;X
        PUSH STYLBTN
        PUSH OFFSET CPBUT2  ;Имя окна.
        PUSH OFFSET CLSBUTN ;Имя класса.
        PUSH 0
        CALL CreateWindowExA@48
        MOV  HWNDBTN2,EAX    ;Запомнить дескриптор кнопки.

;Создать окно LISTBOX.
        PUSH 0
        PUSH [HINST]
        PUSH 0
        PUSH DWORD PTR [EBP+08H]
        PUSH 90   ;DY
        PUSH 150  ;DX
        PUSH 50   ;Y
        PUSH 10   ;X
        PUSH STYLLST
        PUSH OFFSET CPLST    ;Имя окна.
        PUSH OFFSET CLSLIST  ;Имя класса.
        PUSH 0
        CALL CreateWindowExA@48
        MOV  HWNDLST,EAX    
;Заполнить список.
        PUSH PS
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH HWNDLST
        CALL SendMessageA@16
        PUSH PS+4
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH HWNDLST
        CALL SendMessageA@16
        PUSH PS+8
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH HWNDLST
        CALL SendMessageA@16
        PUSH PS+12
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH HWNDLST
        CALL SendMessageA@16
        PUSH PS+16
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH HWNDLST
        CALL SendMessageA@16
        PUSH PS+20
        PUSH 0
        PUSH LB_ADDSTRING
        PUSH HWNDLST
        CALL SendMessageA@16
;Создаем строку редактирования.
        PUSH 0
        PUSH [HINST]
        PUSH 0
        PUSH DWORD PTR [EBP+08H]
        PUSH 20   ;DY
        PUSH 150  ;DX
        PUSH 140   ;Y
        PUSH 10   ;X
        PUSH STYLEDT
        PUSH OFFSET CPEDT   ;Имя окна.
        PUSH OFFSET CLSEDIT ;Имя класса.
        PUSH 0
        CALL CreateWindowExA@48
        MOV  HWNDEDT,EAX
;------------------------------------
        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
        ;PUSH OFFSET CAP
        ;PUSH OFFSET MES
        ;PUSH DWORD PTR [EBP+08H] ;Дескриптор окна.
        ;CALL MessageBoxA@16
        PUSH 0
        CALL PostQuitMessage@4   ;Сообщение WM_QUIT.
        MOV  EAX, 0
FINISH:	
        POP  EDI
        POP  ESI
        POP  EBX
        POP  EBP
        RET  16
WNDPROC ENDP
;Процедура сравнения строк.
CMPSTR PROC
        LEA ESI,BUF
        REPE CMPSB
        RET 
CMPSTR ENDP

_TEXT   ENDS	
        END START

    Вспомогательный файл pr_h.asm:

;Константы.
;Сообщение приходит при  закрытии окна.
WM_DESTROY	equ 2
;Сообщение приходит при создании окна.
WM_CREATE	equ  1
;Сообщение, если что-то происходит с элементами на окне.
WM_COMMAND	    equ 111h
;Сообщение, позволяющее послать элементу строку.
WM_SETTEXT	    equ 0Ch
;Сообщение, позволяющее получить строку.
WM_GETTEXT	    equ 0Dh
;Сообщение - команда добавить строку.
LB_ADDSTRING        equ 180h
LB_GETTEXT          equ 189h
LB_GETCURSEL        equ 188h

;Свойства окна.
CS_VREDRAW	    equ 1h
CS_HREDRAW	    equ 2h
CS_GLOBALCLASS      equ 4000h
WS_TABSTOP	    equ 10000h
WS_SYSMENU          equ 80000h
WS_THICKFRAME       equ 40000h
WS_OVERLAPPEDWINDOW equ WS_TABSTOP+WS_SYSMENU
STYLE               equ CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS
BS_DEFPUSHBUTTON    equ 1h
WS_VISIBLE          equ 10000000h
WS_CHILD            equ 40000000h
WS_BORDER           equ 800000h
WS_VSCROLL          equ 200000h
LBS_NOTIFY          equ 1h

STYLBTN    equ WS_CHILD+BS_DEFPUSHBUTTON+WS_VISIBLE+WS_TABSTOP
STYLLST    equ WS_THICKFRAME+WS_CHILD+WS_VISIBLE+WS_BORDER + 
           WS_TABSTOP+WS_VSCROLL+LBS_NOTIFY
STYLEDT    equ WS_CHILD+WS_VISIBLE+WS_BORDER+WS_TABSTOP
;Идентификатор стандартной пиктограммы.
IDI_APPLICATION   equ  32512
;Идентификатор курсора.
IDC_ARROW         equ  32512
;Режим показа окна - нормальный.
SW_SHOWNORMAL	  equ  1

RDW_ERASE equ 4h
RDW_INVALIDATE equ 1h
RDW_FLAGS equ RDW_ERASE+RDW_INVALIDATE
GCL_HBRBACKGROUND equ -10

;Прототипы внешних процедур.
EXTERN  SendMessageA@16:NEAR
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  CreateSolidBrush@4:NEAR
EXTERN  UpdateWindow@4:NEAR
EXTERN  SetClassLongA@12:NEAR
EXTERN  RedrawWindow@16: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 
;-------------------------------- 
Текст этой программы можно взять здесь.

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


Рис.1. Результат работы приложения

    Со следующего шага мы начнем рассматривать вопросы, связанные с исправленим исполняемых модулей.




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