Меню сайта

Урок 3. Ресурсы и меню

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

Ресурсы, представляют собой двоичные данные,
хранящиеся внутри EXE или DLL файла программы.
Команды меню, например, организованы как ресурсы,
которые программа загружает во время выполнения.
Ресурсы экономят время, сокращая объем
подготовительных операций, выполняемых программой, и
экономят память, так как двоичные ресурсы остаются на
диске до тех пор, пока они не потребуются.

С помощью редактора ресурсов, такого как Borland Resource
Workshop, вы разрабатываете ресурсы вашей программы
так, как если бы вы рисовали картинку, редактировали
текстовый документ или чертили диаграмму. Borland
Resource Workshop – интерактивный редактор ресурсов- то,
что вы видите на экране, выглядит точно так же, как будут,
в конечном счете, выглядеть ресурсы в законченной
программе.

В этой статье я не буду рассматривать процесс работы в
Resource Workshop. Мы рассмотрим только некоторые
моменты, которые нам понадобятся в дальнейшем. В
Resource Workshop вы должны создать файл сценария
ресурсов. Этот файл представляет собой обыкновенный
текстовый документ, содержащий операторы исходного
кода ресурсов приложения. Файлы сценария ресурсов
имеют расширения .RC.

Пример файла сценария ресурсов (menures.rc)

#include «menures.rh»

MENU_1 MENU
{
POPUP «&amp-File»
{
MENUITEM «&amp-First item», CM_FIRSTMENU
MENUITEM «&amp-Second item», CM_SECONDMENU
MENUITEM SEPARATOR
MENUITEM «&amp-Third Menu», CM_THIRDMENU
}
POPUP «&amp-Exit»
{
MENUITEM «&amp-Exit NOW», CM_EXIT
}
}

После того как ресурсы созданы, мы должны связать их с
нашим приложением. Для этого Resource Workshop создает
файлы идентификаторов ресурсов. Эти файлы имеют
расширение .RH.

Пример файлы идентификаторов ресурсов (menures.rh)

#define ICON_1 1
#define MENU_1 1
#define CM_EXIT 104
#define CM_THIRDMENU 103
#define CM_SECONDMENU 102
#define CM_FIRSTMENU 101

Теперь, когда вы понимаете, что создает Resource
Workshop, мы приступим к созданию файла ресурсов.
Файл ресурсов представляет собой бинарный файл и
присоединяется к нашему приложению в процессе
компоновки. Файлы ресурсов имеют расширение .RES.

Для получения файла ресурсов вы можете использовать
две программы:

Resource Workshop.
Borland Resource Compiler.

Для создания файла ресурсов в Resource Workshop вы
должны выбрать в меню File пункт Save As и сохранить
ваши ресурсы как .RES файл.

Для создания файла ресурсов с помощью Borland Resource
Compiler вы должны просто запустить программу brcc.exe и
как параметр передать ей путь и имя файла сценария
ресурсов.

Когда файл ресурсов создан, можно перейти к вопросу
программирования. Для того, что бы Turbo Assembler
понял файл идентификаторов ресурсов его надо немного
переделать. Описания всех идентификаторов начинается с
директивы #define, так как подобной директивы в Turbo
Assembler нет, мы должны подправить все объявления
идентификаторов на идентичную директиве #define
директиву equ.

Например: #define CM_EXIT 1 нужно заменить CM_EXIT
equ 1

После того как вы преобразовали файл идентификаторов
ресурсов, его надо подключить к основной программе. Для
этого используйте директиву include.

ВНИМАНИЕ: Не все ресурсы могут иметь одинаковые
идентификаторы. Однако только ресурсы типов DIALOG
и MENU можно проигнорировать, так как их
использование не связано с идентификатором, ресурсы
остальных типов должны иметь уникальные
идентификаторы.

Пример программы (menures.asm)

locals
jumps
.model large, WINDOWS PASCAL
— Подключаем файл описания констант и структур API
include windows.inc
— Подключаем файл описания идентификаторов ресурсов
include windows.ri
— Описываем используемые функции
extrn BEGINPAINT:PROC
extrn CREATEWINDOW:PROC
extrn DEFWINDOWPROC:PROC
extrn DISPATCHMESSAGE:PROC
extrn ENDPAINT:PROC
extrn GETMESSAGE:PROC
extrn GETSTOCKOBJECT:PROC
extrn INITAPP:PROC
extrn INITTASK:PROC
extrn LOADCURSOR:PROC
extrn MESSAGEBOX:PROC
extrn POSTQUITMESSAGE:PROC
extrn REGISTERCLASS:PROC
extrn SHOWWINDOW:PROC
extrn TEXTOUT:PROC
extrn TRANSLATEMESSAGE:PROC
extrn UPDATEWINDOW:PROC
extrn WAITEVENT:PROC

.data

— Для Windows Task Manager’a
freespace db 16 dup(0)
— HINSTANCE нашего приложения
hInstance dw ?
— Параметр просмотра окна
cmdShow dw ?
— Структура PAINTSTRUCT
lppaint PAINTSTRUCT &lt-0&gt-
— Структура сообщения MSGSTRUCT
msg MSGSTRUCT &lt-0&gt-
— Структура описания окна
wc WNDCLASS &lt-0&gt-
— Заголовок окна
lpszTitleName db ‘Menu and Resources Window’,0
— Название класса окна
lpszClassName db ‘ASMCLASS’,0
— Выводимая в окно строка
lpszText db ‘Hello World’
— Длина строки lpszText
lpszTextLength equ $-lpszText
— Заголовок диалогового окна
lpszMenuCaption db ‘Menu Event’,0
— Идентификатор меню
MenuString db ‘MENU_1’,0
— Сообщения диалогового окна
lpszMenu1Msg db ‘First menu item selected’,0
lpszMenu2Msg d
b ‘Second menu item selected’,0
lpszMenu3Msg db ‘Third menu item selected’,0

.code
.286

— Как говоритья в WarLords «Lets The War Begins»
start:
— Инициализируем сегмент данных
mov ax, @data
mov ds, ax
— Инициализируем задачу и получаем входные параметры
call INITTASK
or ax,ax
— Если инициализация прошла успешно
jnz @@OK
— Если ошибка
jmp @@Fail
@@OK:
— Сохраняем HINSTANCE
mov [hInstance],di
— Сохраняем параметр просмотра окна
mov [cmdShow],dx
— Инициализируем приложение
call INITAPP,hInstance
or ax,ax
jnz @@InitOK
@@Fail:
— Если инициализация завершилась неудачно
mov ax, 4CFFh
int 21h
@@InitOK:
— Заполняем структуру описания окна
mov [wc.clsStyle],0
mov word ptr [wc.clsLpfnWndProc],offset WndProc
mov word ptr [wc.clsLpfnWndProc+2],seg WndProc
mov [wc.clsCbClsExtra],0
mov [wc.clsCbWndExtra],0
mov ax,[hInstance]
mov [wc.clsHInstance],ax
— Загружаем пиктограмму ICON_1 и вствляем его в структуру
call LOADICON,ax,ICON_1
mov [wc.clsHIcon],ax
— Загружаем курсор IDC_ARROW и вставляем его в структуру
xor ax,ax
call LOADCURSOR,ax IDC_ARROW
mov [wc.clsHCursor],ax
— Загружаем цвет белого фона и вставляем его в структуру
call GETSTOCKOBJECT,WHITE_BRUSH
mov [wc.clsHbrBackground],ax
mov word ptr [wc.clsLpszMenuName],offset MenuString
mov word ptr [wc.clsLpszMenuName+2],ds
mov word ptr [wc.clsLpszClassName],offset lpszClassName
mov word ptr [wc.clsLpszClassName+2],ds
— Регистрируем структуру описания окна
call REGISTERCLASS,ds offset wc
— Создаем окно
xor ax,ax
mov bx,CW_USEDEFAULT
call CREATEWINDOW,ds offset lpszClassName,ds offset
lpszTitleName&#92-
,WS_OVERLAPPEDWINDOW,ax,bx,bx,bx,bx,ax,ax,&#92-
[hInstance],ax,ax
— Показываем окно
push ax
call SHOWWINDOW,ax,cmdShow
— Обновляем окно
pop ax
call UPDATEWINDOW,ax
— Цикл обработки сообщений
msg_loop:
— Получаем сообщение
call GETMESSAGE,ds offset msg,0,0,0
— Проверяем на наличие сообщения WM_QUIT (AX=0)
cmp ax,0
je end_loop
— Обрабатываем сообщение
call TRANSLATEMESSAGE,ds offset msg
call DISPATCHMESSAGE,ds offset msg
— Обрабатываем следующее сообщение
jmp msg_loop
end_loop:
— Выходим из программы
mov ax,[msg.msWPARAM]
mov ah,4Ch
int 21h

— Процедура обработки сообщений

WndProc PROC
ARG
hwnd:WORD,wmsg:WORD,wparam:WORD,lparam:DWORD

cmp [wmsg],WM_DESTROY
— Если получили сообщение WM_DESTROY (получено сообщение «на
выход»)
je wmdestroy
cmp [wmsg],WM_CREATE
— Если получили сообщение WM_CREATE (получено сообщение
«создать окно»)
je wmcreate
cmp [wmsg],WM_PAINT
— Если получили сообщение WM_PAINT (получено сообщение
«нарисуйся»)
je wmpaint
cmp [wmsg],WM_COMMAND
— Если получили сообщение WM_COMMAND (получено сообщение от
меню)
je wmcommand
— Если мы не обрабатываем ни одно из вышеперечисленных сообщений
передаем
— управление стандартному обработчику
jmp defwndproc

— Обработка сообщения WM_PAINT

wmpaint:
— Начинаем рисование и получаем указатель на текущий DC
call BEGINPAINT,hwnd,ds offset lppaint
— AX содержит контекст устройства вывода DC, полученный после
вызова BEGINPAINT
— Вызываем TEXTOUT для вывода строки lpszText
call TEXTOUT,ax,5,5,ds offset lpszText,lpszTextLength
— Заканчиваем рисование
call ENDPAINT,hwnd,ds offset lppaint
— Обнуляем AX и на выход
xor ax,ax
jmp finish

— Обработка сообщения WM_CREATE

wmcreate:
— Обнуляем AX и на выход
xor ax,ax
jmp finish

— Вызов стандартного обработчика сообщений

defwndproc:
call DEFWINDOWPROC,hwnd,wmsg,wparam,lparam
jmp finish

— Обработка сообщения WM_DESTROY

wmdestroy:
— Вызываем POSTQUITMESSAGE
call POSTQUITMESSAGE,0
— Обнуляем AX и на выход
xor ax,ax
jmp finish

— Обработка сообщения WM_COMMAND

wmcommand:
— Если выбран первый пункт меню File
cmp [wparam],CM_FIRSTMENU
jne wmcommand1
— Выводим на экран диалоговое окно
call MESSAGEBOX,0,ds offset lpszMenu1Msg,ds offset
lpszMenuCaption,0
— Выход из обработчика WM_COMMAND
jmp exit_wmcommand
wmcommand1:
— Если выбран второй пункт меню File
cmp [wparam],CM_SECONDMENU
jne wmcommand2
— Выводим на экран диалоговое окно
call MESSAGEBOX,0,ds offset lpszMenu2Msg,ds offset
lpszMenuCaption,0
— Выход из обработчика WM_COMMAND
jmp exit_wmcommand
wmcommand2:
— Если выбран третий пункт меню File
cmp [wparam],CM_THIRDMENU
jne wmcommand3
— Выводим на экран диалоговое окно
call MESSAGEBOX,0,ds offset lpszMenu3Msg,ds offset
lpszMenuCaption,0
— Выход из обработчика WM_COMMAND
jmp exit_wmcommand
wmcommand3:
— Если выбран пункт Exit NOW меню Exit
cmp [wparam],CM_EXIT
— Вызываем POSTQUITMESSAGE
call POSTQUITMESSAGE,0
— Выход из обработчика WM_COMMAND
jmp exit_wmcommand
— Выход из обработчкиа WM_COMMAND
exit_wmcommand:
— Выходим из обработчика WM_COMMAND
xor ax,ax
jmp finish

— «Финишная прямая»

finish:
— Обнуляем DX и на выход
xor dx,dx
ret
WndProc ENDP

end start

В этой программе я использовал два типа ресурсов MENU
и ICON. Подключение ресурса ICON выглядит очень
наглядно, и объяснять его я не буду. Однако подключение
ресурса MENU осуществляется немного по-другому.

Ресурсы типа DIALOG и MENU подключаются не через
идентификаторы ресурсов, а через их текстовые имена,
которые они имели при создании в Resource Workshop. В
нашем случае ресурс MENU имеет имя «MENU_1». Вы
просто должны объявить строку, содержащую имя ресурса
и заканчивающуюся символом 0.

Например:

lpszMenu db ‘MENU_1’,0

Все остальные типы ресурсов (кроме MENU и DIALOG)
подключаются по методу подключения ресурсы ICON.

Теперь рассмотрим подробнее функцию WndProc. По
сравнению с предыдущей статьей она стала немного

сложнее. Это связано с тем, что теперь наше приложение
обрабатывает все пункты меню. Когда вы нажимаете на
какой-либо пункт меню, Windows посылает программе
сообщение WM_COMMAND. Через параметр wParam
передается идентификатор нажатого пункта меню. Так на
нашем примере, если вы нажимаете на кнопку Second Item
в меню файл, то приложению передается сообщение
WM_COMMAND с wParam=CM_SECONDITEM. Т.е. со
значением которые вы присвоили данному пункту меню
во время создания ресурса MENU в Resource Workshop.

Теперь опишем еще раз процесс создания приложения,
содержащего ресурсы:

Создаем файл сценария ресурсов (.RC) и файл
идентификатора ресурсов (.RH) в Resource Workshop.
menures.rc, menures.rh
Преобразуем файл сценария ресурсов (.RC) в файл
ресурсов (.RES), с помощью Resource Workshop или
программы brcc.exe.
brcc.exe menures.rc
Преобразуем файл идентификаторов ресурсов (.RH) в
язык, понятный Turbo Assembler. (.RI) Компилируем
приложение
tasm.exe menures.asm
Компонуем приложение
tlink.exe
menures.obj,menures.exe,menures.map,import.lib,menures.def,menures.res.


Меню раздела
Блок