| [Назад] [Далее] | ![]() |
Графические программы для Windows практически никогда не ограничиваются одним меню, потому что меню не позволяет ввести никакой реальной информации — только выбрать тот или иной пункт из предложенных. Конечно, можно в цикле после GetMessage или PeekMessage обрабатывать события передвижения мыши и нажатия клавиш, и так делают в интерактивных программах, например в играх, но, если требуется ввод текста с возможностью его редактирования, выбор файла на диске и любые другие нетривиальные действия, основным средством ввода информации в программах для Windows оказываются диалоги.
Диалог описывается, так же как и меню, в файле ресурсов, но, если меню было очень просто написать вручную, ради диалогов, скорее всего, придется пользоваться каким-нибудь редактором диалогов, идущим в комплекте с вашим любимым компилятором, если, конечно, вы не знаете в точности, по каким координатам будет располагаться каждый контрол (активный элемент диалога).
// windlg.rc
// Файл ресурсов, описывающий диалог, используемый в программе windlg.asm.
// Все следующие определения можно заменить на #include
// <winuser.h>, если он есть:
// стили для диалогов
#define DS_CENTER 0x0800L
#define DS_MODALFRAME 0x80L
#define DS_3DLOOK 0x0004L
// стили для окон
#define WS_MINIMIZEBOX 0x00020000L
#define WS_SYSMENU 0x00080000L
#define WS_VISIBLE 0x10000000L
#define WS_OVERLAPPED 0x00000000L
#define WS_CAPTION 0xC00000L
// стили для редактора
#define ES_AUTOHSCROLL 0x80L
#define ES_LEFT 0
#define ZDLG_MENU 7
// идентификаторы контролов диалога
#define IDC_EDIT 0
#define IDC_BUTTON 1
#define IDC_EXIT 2
// идентификаторы пунктов меню
#define IDM_GETTEXT 10
#define IDM_CLEAR 11
#define IDM_EXIT 12
ZZZ_Dialog DIALOG 10,10,205,30 // x, у, ширина, высота
STYLE DS_CENTER | DS_MODALFRAME | DS_3DLOOK | WS_CAPTION | WS_MINIMIZEBOX |
WS_SYSMENU | WS_VISIBLE | WS_OVERLAPPED
CAPTION "Win32 assembly dialog example" // заголовок
MENU ZDLG_MENU // меню
BEGIN // начало списка контролов
EDITTEXT IDC_EDIT,15,7,111,13,ES_AUTOHSCROLL | ES_LEFT
PUSHBUTTON "E&xit",IDC_EXIT,141,8,52,13
END
ZDLG_MENU MENU // меню
BEGIN
POPUP "Test"
BEGIN
MENUITEM "Get Text",IDM_GETTEXT
MENUITEM "Clear Text",IDM_CLEAR
MENUITEM SEPARATOR
MENUITEM "E&xit",IDM_EXIT
END
END
В качестве простого примера использования диалога покажем, как можно его применять, даже не регистрируя новый класс. Для этого надо просто создать диалог командой CreateDialog или одним из ее вариантов, не создавая никакого окна-предка. Все сообщения от диалога и окон, которые он создает, будут посылаться в процедуру-обработчик типа DialogProc, аналогичную процедуре WindowProc.
; windlg.asm
; Графическое win32-приложение, демонстрирующее работу с диалогом
; идентификаторы контролов (элементов диалога)
IDC_EDIT equ 0
IDC_BUTTON equ 1
IDC_EXIT equ 2
; идентификаторы элементов меню
IDM_GETTEXT equ 10
IDM_CLEAR equ 11
IDM_EXIT equ 12
include def32.inc
include kernel32.inc
include user32.inc
.386
.model flat
.data
dialog_name db "ZZZ_Dialog",0 ; имя диалога в ресурсах
.data?
buffer db 512 dup(?) ; буфер для введенного текста
.code
_start:
xor ebx,ebx ; в EBX будет 0 для команд push 0
; (короче в 2 раза)
; определить идентификатор нашей программы
push ebx
call GetModuleHandle
; запустить диалог
push ebx ; значение, которое перейдет как параметр WM_INITDIALOG
push offset dialog_proc ; адрес процедуры типа DialogProc
push ebx ; идентификатор окна-предка (0 - ничей диалог)
push offset dialog_name ; адрес имени диалога в ресурсах
push eax ; идентификатор программы, в ресурсах которой
; находится диалог (наш идентификатор в ЕАХ)
call DialogBoxParam
; выход из программы
push ebx
call ExitProcess
;
; процедура dialog_proc
; вызывается диалогом каждый раз, когда в нем что-нибудь происходит
; именно здесь будет происходить вся работа программы
;
; процедура не должна изменять регистры EBP,EDI,ESI и ЕВХ!
;
dialog_proc proc near
; так как мы получаем параметры в стеке, построим стековый кадр
push ebp
mov ebp,esp
; процедура типа DialogProc вызывается со следующими параметрами:
dp_hWnd equ dword ptr [ebp+08h] ; идентификатор диалога
dp_uMsg equ dword ptr [ebp+0Ch] ; номер сообщения
dp_wParam equ dword ptr [ebp+10h] ; первый параметр
dp_lParam equ dword ptr [ebp+14h] ; второй параметр
mov ecx,dp_hWnd ; ECX будет хранить идентификатор диалога,
mov eax,dp_uMsg ; a EAX - номер сообщения,
cmp eax,WM_INITDIALOG ; если мы получили WM_INITDIALOG
jne not_initdialog
push IDC_EDIT
push dp_hWnd
call GetDlgItem ; определить идентификатор
push eax ; окна редактирования текста
call SetFocus ; и передать ему фокус,
not_initdialog:
cmp eax,WM_CLOSE ; если мы получили WM_CLOSE,
jne not_close
push 0
push ecx
call EndDialog ; закрыть диалог,
not_close:
cmp eax,WM_COMMAND ; если мы получили WM_COMMAND,
jne not_command
mov eax,dp_wParam ; EAX = wParam (номер сообщения),
cmp dp_lParam,0 ; если lparam ноль - сообщение от меню,
jne lParam_not_0
cmp ax,IDM_GETTEXT ; если это пункт меню Get Text
jne not_gettext
push 512 ; размер буфера
push offset buffer ; адрес буфера
push IDC_EDIT ; номер конрола редактирования
push ecx
call GetDlgItemText ; считать текст в buffer
push MB_OK
push offset dialog_name
push offset buffer
push dp_hWnd
call MessageBox ; и показать его в MessageBox,
not_gettext:
cmp eax,IDM_CLEAR ; если это пункт меню Clear
jne not_clear
push 0 ; NULL
push IDC_EDIT ; номер контрола
push ecx
call SetDlgItemText ; установить новый текст,
not_clear:
cmp eax,IDM_EXIT ; если это пункт меню Exit
jne not_exit
push 0 ; код возврата
push ecx ; идентификатор диалога
call EndDialog ; закрыть диалог
lParam_not_0: ; lParam не ноль - сообщение от контрола,
cmp eax,IDC_EXIT ; если сообщение от кнопки Exit,
jne not_exit
shr eax,16
cmp eax,BN_CLICKED ; если ее нажали
push 0 ; код возврата
push ecx ; идентификатор диалога
call EndDialog ; закрыть диалог
not_exit:
xor eax,eax ; после обработки команды
inc eax ; DialogProc должен возвращать TRUE (eax = 1)
leave
ret 16 ; конец процедуры
not_command: ; сюда передается управление, если мы получили
; какое-то незнакомое сообщение
xor еах,еах ; код возврата FALSE (eax = 0)
leave
ret 16 ; конец процедуры
dialog_proc endp
end _start
Добавления в наш user32.inc:
между ifdef _TASM_ и else:
extrn DialogBoxParamA:near
extrn GetDlgItem:near
extrn SetFocus:near
extrn GetDlgItemTextA:near
extrn SetDlgItemTextA:near
extrn EndDialog:near
DialogBoxParam equ DialogBoxParamA
GetDlgltemText equ GetDlgItemTextA
SetDlgltemText equ SetDlgItemTextA
между else и endif:
extrn __imp__DialogBoxParamA@20:dword
extrn __imp__GetDlgItem@8:dword
extrn __imp__SetFocus@4:dword
extrn __imp__GetDlgItemTextA@16:dword
extrn __imp__SetDlgItemTextA@12:dword
extrn __imp__EndDialog@8:dword
DialogBoxParam equ __imp__DialogBoxParamA@20
GetDlgItem equ __imp__GetDlgItem@8
SetFocus equ __imp__SetFocus@4
GetDlgItemText equ __imp__GetDlgItemTextA@16
SetDlgItemText equ __imp__SetDlgItemTextA@12
EndDialog equ __imp__EndDialog@8
Добавления к файлу def32.inc:
; из winuser.h WM_INITDIALOG equ 110h WM_CLOSE equ 10h BN_CLICKED equ 0