На этом шаге мы рассмотрим пример программы, в которой меняется цвет фона окна приложения.
Студент 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. Результат работы приложения
Со следующего шага мы начнем рассматривать вопросы, связанные с исправленим исполняемых модулей.