Assembler - язык неограниченных возможностей

         

Диалоги


Графические программы для 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


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