7.3.3. Меню

Меню - один из краеугольных камней идеологии Windows. Похожие друг на

друга меню разрешают пользоваться абсолютно незнакомыми программами, не чи­тая инструкций, и узнавать об их возможностях путем просмотра содержания раз­личных пунктов меню. Попробуем добавить меню и в нашу программу window.asm. Первое, что нам нужно получить, - это само меню. Его, так же как и иконки,

диалоги и другая информация (вплоть до версии программы), записывают в фай­лы ресурсов. Файл ресурсов имеет расширение *.RC для текстового файла или *.RES для бинарного файла, созданного специальным компилятором ресурсов (RC, BRCC32 или WRC). И те, и другие файлы ресурсов можно редактировать

особыми программами, входящими в дистрибутивы C/C++, или с помощью дру­гих средств разработки для Windows, но мы не будем создавать слишком сложное меню и напишем RC-файл вручную, например так:

// winraenu. гс

// Файл ресурсов для программы

#define ZZZ_TEST 1

#define ZZZ_0PEN 2

#define ZZZ_SAVE 3

#define ZZZ_EXIT 4

MENU і

POPUP "&File" {

menuitem "&0pen",ZZZ_0PEN menuitem. "&Save", zzz_save menuitem separator

menuitem  "E&Xit", ZZZ_EXIT

MENUITEM "&Edit",ZZZ_TEST

}

Чтобы добавить этот файл в программу, его надо скомпилировать и указать имя*.11Е5-файладля компоновщика:

MASM:

ml /с /coff /Cp winmenu. asm rc /г winmenu. rc

link

TASM:

tasm /x /m /ml /D_TASM_ winmenu.asm brcc32 winmenu.res

tlink32 /Тре /аа /с winmenu.obj.....winmenu. res

WASM:

wasm

wrc 11 /bt=nt winmenu. rc ■ '

wlink file winmenu.obj res winmenu. res form windows nt op с

А теперь сам текст программы. Чтобы показать, как мало требуется внести изменений в программу window.asm, комментарии для всех строк, перенесенных оттуда без поправок, заменены символом *.

; winmenu.asm

; Графическое иіп32-приложение, демонстрирующее работу с меню. ;  Звездочками отмечены строки,  скопированные из файла window.asm.

ZZZ_TEST

equ

 

Сообщения от нашего меню

ZZZJJPEN

equ

 

должны

совпадать с определениями из

ZZZ_SAVE

equ

 

Кроме того, в нашем примере их номера

ZZZ_EXIT

equ

 

потому

что они используются как индексы для

 

 

 

таблицы переходов к обработчикам.

include def32.inc

 

 

 

include

inc

 

 

 

include user32.inc

 

 

 

.386

 

 

 

 

.model

flat

 

 

 

.data

 

 

 

 

class_name

db

 

class            • *

window_name

db

 

"Win32 assembly example",0 ;*

menu_name

db

 

"ZZZ„Menu",0

Имя меню в файле

test_msg

db

 

"You selected menu item TESr,0    ; Строки для

openjusg

db

 

"You selected menu item 0PEN",0     ;  демонстрации работы

save_msg

db

 

"You selected menu item SAVE",0    ; меню.

wc          WNDCLASSEX <4*

or

 

C0L0R_WIND0W+1,0, offset class^name,0> ;*

.data?

 

 

 

 

msg_ MSG

<? ?

9 9

9 9>

A

. code

 

 

 

*

_starf.

 

 

 

 

xor

ebx,ebx

 

 

push

ebx

 

 

 

call

GetModuleHandle

f

mov

esi,eax

 

ft

mov

dword

ptr

* *

push

IDI_APPLICATION

' *

 

push

ebx

; .

 

call

Loadlcon

' *

 

mov

wc.hIcon,eax

 

 

push

IDC_ARROW

] *

 

push

ebx

" *

 

call

LoadCursor

;*

 

mov

wc. hCursor, eax

' *

 

push

offset WC

 

 

call

RegisterClassEx

 

 

push

offset menu name

; Имя меню.

 

push

esi

; Наш идентификатор.

 

call

LoadMenu

; Загрузить меню из ресурсов.

 

mov

ecx.CW USEDEFAULT

' *

 

push

ebx

 

 

push

esi '

; .

 

push

eax

; Идентификатор меню или окна

 

push

ebx'

;.

 

push

ecx .

 

 

push

ecx

' *

 

push

ecx

; *

 

push

ecx

' *

 

push

WS OVERLAPPEDWINDOW

 

 

push

offset window name

 

 

push

offset class name

 

 

push

ebx

 

 

call

CreateWindowEx

; -

 

push

eax

* *

 

push

SW_SH0WN0RMAL

 

 

push

eax

* *

 

call

ShowWindow

* *

 

call

UpdateWindow

" -к

 

mov

edi, offset msg_

 

 

message loop:

 

" *

 

push

ebx

 

 

push

ebx

1 *

 

push

ebx

" *■

 

push

edi

1 *

 

call

GetMessage

 

 

test

eax,eax

' *

 

jz

exit msg loop

 

 

push

. edi

 

 

call

TranslateMessage

" *

 

push

edi

 

 

call

DispatchMessage

 

 

jmp

short

;*

 

exit msg loop:

 

■ *

 

push

ebx

; *

 

call

ExitProcess

; .

 

І    Программирование для Windows 95/NT

Процедура і«п_ргос.

Вызывается окном каждый раз, когда оно получает какое-нибудь сообщение. Именно здесь будет происходить вся работа программы.

';  Процедура не должна изменять регистры ЕВР, ЕРІ, ЕбІ и* ЕВХ!

win_proc

push

mov

crop

jne

push

call jmp

not_wm_destroy: cmp

jne mov jmp

proc

ebp

ebp.esp

wp.hWnd equ dword ptr [ebp+08h] wp_uMsg equ dword ptr [ebp+OCh]

ptr

ptr

[ebp+10h] [ebp+14h]

equ dword

wp_lParam equ dword wp_uMsg,WM_DESTROY not_wm_destroy

0

PostQuitMessage

short end wm check

wp_uMsg,WM_COMMAND not_wm_command eax,wp_wParam

dword ptr menu_handlers[eax.4] ; Косвенный переход

Если мы получили ИМ_СОММАШ -это от нашего меню и в иРагаш лежит наше подсообщение.

(в 32-битном режиме можно осуществлять переход по любому регистру).

menu_handlers

; Обработчики

; Обработчик

menu_test •.

mov jmp

menu_open: mov jmp

menu_save'.

mov

show_msg:

push push push push call jmp menu_exit:

push

call

end_wm_check: •leave

xor ret

dd offset menu_test,offset menu_open

dd offset menu_save,offset menu_exit

событий test, open и save выводят MessageBox.

exit выходит из программы.

eax,offset test msg

short showjnsg

eax,offset open_msg

short show_msg

eax,offset savejnsg

MB_OK

offset menu_name eax

wp_hWnd ■ MessageBox short end_wm_check

wpJiWnd DestroyWindow

eax, eax 16

Сообщение для MessageBox.

Сообщение для MessageBox.

Сообщение для MessageBox.

Стиль для MessageBox.

Заголовок.

Сообщение.

Идентификатор окна-предка. Вызов функции. Выход из win_proc. Если выбрали пункт EXIT,

уничтожить наше окно.

; Вернуть 0 как результат работы процедуры.

not_wm_command: ; not_wm_command,  чтобы избавиться от лишнего jmp.

leave   ' ; -

jmp       DefWindowProc ;*

win_proc endp ; *

end _start

Итак, из 120 строк программы новыми оказались всего 36, а сама программа, с точки зрения пользователя, стала намного сложнее. Таким образом выглядит программирование под Windows на ассемблере - берется одна написанная раз и навсегда шаблонная программа, модифицируются ресурсы и пишутся обработ­чики для различных событий меню и диалогов. Фактически все программирова­ние оказывается сосредоточенным именно в этих процедурах-обработчиках. ■

Добавления к включаемым файлам в этом примере тоже оказываются незна­чительными по сравнению с

В user32.inc между ifdef _TASM_ и else: extrn extrn

LoadMenu equ и между else и endif: extrn extrn

LoadMenu equ DestroyWindow equ

и в

;  Из winuser.h. WM_COMMAND equ MB_0K equ

LoadMenuAmear DestroyWindow :nea r LoadMenuA

_imp_LoadMemjA(§>8: dwo rd _imp_Dest royWindow@4: dwo rd _imp_LoadMenuA@8 . _imp_Dest royWindow@8

111h 0