Суббота, 19.07.2025, 09:47 Приветствую Вас Гость

On-line: Книги, учебники, статьи

Главная | Регистрация | Вход | RSS

Глава 3. Понятие ресурса. Редакторы и трансляторы ресурсов(1)

Глава 3. Понятие ресурса. Редакторы и трансляторы ресурсов

В операционную систему Windows введено понятие ресурса. Ресурс представляет собой некий визуальный элемент с заданными свойствами, хранящийся в исполняемом файле отдельно от кода и данных, который может отображаться специальными функциями.

Использование ресурсов дает две вполне определенные выгоды:

  1. Ресурсы загружаются в память лишь при обращении к ним, т.е. реализуется экономия памяти.
  2. Свойства ресурсов поддерживаются системой автоматически, не требуя от программиста написания дополнительного кода.

Описание ресурсов хранится отдельно от программы в текстовом файле (*.rc) и компилируется (*.res) специальным транслятором ресурсов. В исполняемый файл ресурсы включаются компоновщиком. Транслятором ресурсов в пакете MASM32 является RC.EXE, в пакете TASM32 - BRCC32.EXE.

I

В данном разделе мы займемся изучением языка ресурсов. Зная его, можно вполне обойтись без специального редактора ресурсов. В настоящее время существует большое количество редакторов ресурсов. Видимо, поэтому книги по программированию уделяют мало внимания языку описания ресурсов. Мы, напротив, не будем касаться этих программ31, а как можно подробнее разберем структуру и язык ресурсов. Отметим также, что изложенный стандарт одинаково будет восприниматься обоими компиляторами ресурсов. Исключения будут обговорены отдельно.

Начнем с перечисления наиболее употребляемых ресурсов.

  1. Иконки.
  2. Курсоры.
  3. Битовая картинка.
  4. Строка.
  5. Диалоговое окно.
  6. Меню.
  7. Акселераторы.

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

1. Иконки. Могут быть описаны в самом файле ресурсов, либо храниться в отдельном файле *.ico. Рассмотрим последний случай. Вот файл ресурсов resu.rc:

#define IDI_ICON1 1

IDI_ICON1 ICON "Cdrom01.ico"

Как видите, файл содержит всего две значимых строки. Одна строка определяет идентификатор иконки, вторая - ассоциирует идентификатор с файлом "Cdrom01.ico". Оператор define является Си-оператором препроцессора. Как вы увидите в дальнейшем, язык ресурсов очень напоминает язык Си. Откомпилируем текстовый файл resu.rc: RC resu.rc. На диске появляется объектный файл resu.res. При компоновке укажем этот файл в командной строке:

LINK /subsystem:windows resu.obj resu.res

У читателя возникает вопрос: как использовать данный ресурс в программе? Здесь все просто: предположим, что мы хотим установить новую иконку для окна. Вот фрагмент программы, который устанавливает стандартную иконку для главного окна.

 PUSH IDI_APPLICATION
 PUSH 0
 CALL LoadIconA@8
 MOV [WC.CLSHICON], EAX

А вот фрагмент программы для установки иконки, указанной в файле ресурсов:

 PUSH 1 ; идентификатор иконки (см. файл resu.rc)
 PUSH [HINST] ; идентификатор процесса
 CALL LoadIconA@8
 MOV [WC.CLSHICON], EAX

Компилятор ресурсов brcc32.exe (из пакета TASM32) допускает включение иконки в текст проекта. В этом случае проект будет иметь следующий вид (Рис. 2.3.1):

#define IDI_ICON1 1

IDI_ICON1 ICON
{
'00 00 01 00 02 00 20 20 10 00 00 00 00 00 E8 02'
'00 00 26 00 00 00 10 10 10 00 00 00 00 00 28 01'
'00 00 0E 03 00 00 28 00 00 00 20 00 00 00 40 00'
'00 00 01 00 04 00 00 00 00 00 80 02 00 00 00 00'
'00 00 00 00 00 00 10 00 00 00 00 00 00 00 00 00'
'00 00 00 00 BF 00 00 BF 00 00 00 BF BF 00 BF 00'
'00 00 BF 00 BF 00 BF BF 00 00 C0 C0 C0 00 80 80'
'80 00 00 00 FF 00 00 FF 00 00 00 FF FF 00 FF 00'
'00 00 FF 00 FF 00 FF FF 00 00 FF FF FF 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 77 78 33 AA 00 00 00 00 00 00 00 00'
'00 00 07 7F 77 78 33 AA 77 80 00 00 00 00 00 00'
'00 0F F7 F7 77 78 33 AA 77 C8 60 00 00 00 00 00'
'00 FF FF 7F 77 78 33 AA 78 C6 66 00 00 00 00 00'
'0F FF FF F7 77 78 38 A7 7C 86 66 60 00 00 00 00'
'77 FF FF 7F 77 78 37 A7 8C 66 66 77 00 00 00 07'
'87 7F FF F7 F7 78 37 A7 C8 66 67 77 70 00 00 08'
'78 77 FF FF 77 78 3A A8 C6 66 77 77 E0 00 00 87'
'87 87 7F FF F7 78 3A AC 86 67 77 EE EE 00 00 78'
'78 78 77 FF 7F 78 3A 8C 66 77 EE EE BB 00 07 87'
'87 87 87 7F F7 78 3A C8 67 7E EB BB BA A0 08 78'
'78 78 78 77 F8 88 88 C6 7E BB BB AA AA A0 07 87'
'87 87 87 87 88 00 00 88 BB BA AA A3 33 30 08 78'
'78 78 78 78 80 8F F8 08 33 33 33 DD DD D0 08 88'
'88 88 88 88 80 FF FF 08 5D 5D 5D 5D 5D 50 05 D5'
'D5 D5 D5 D5 80 FF FF 08 88 88 88 88 88 80 0D DD'
'DD 33 33 33 80 8F F8 08 87 87 87 87 87 80 03 33'
'3A AA AB BB 88 00 00 88 78 78 78 78 78 70 0A AA'
'AA BB BB E7 6C 88 88 8F 77 87 87 87 87 80 0A AB'
'BB BE E7 76 8C A3 87 7F F7 78 78 78 78 70 00 BB'
'EE EE 77 66 C8 A3 87 F7 FF 77 87 87 87 00 00 EE'
'EE 77 76 68 CA A3 87 7F FF F7 78 78 78 00 00 0E'
'77 77 66 6C 8A A3 87 77 FF FF 77 87 80 00 00 07'
'77 76 66 8C 7A 73 87 7F 7F FF F7 78 70 00 00 00'
'77 66 66 C8 7A 73 87 77 F7 FF FF 77 00 00 00 00'
'06 66 68 C7 7A 83 87 77 7F FF FF F0 00 00 00 00'
'00 66 6C 87 AA 33 87 77 F7 FF FF 00 00 00 00 00'
'00 06 8C 77 AA 33 87 77 7F 7F F0 00 00 00 00 00'
'00 00 08 77 AA 33 87 77 F7 70 00 00 00 00 00 00'
'00 00 00 00 AA 33 87 77 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 FF F0'
'0F FF FF 80 01 FF FE 00 00 7F FC 00 00 3F F8 00'
'00 1F F0 00 00 0F E0 00 00 07 C0 00 00 03 C0 00'
'00 03 80 00 00 01 80 00 00 01 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 80 00 00 01 80 00 00 01 C0 00 00 03 C0 00'
'00 03 E0 00 00 07 F0 00 00 0F F8 00 00 1F FC 00'
'00 3F FE 00 00 7F FF 80 01 FF FF F0 0F FF 28 00'
'00 00 10 00 00 00 20 00 00 00 01 00 04 00 00 00'
'00 00 C0 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 80 80 80 00 C0 C0 C0 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 00 00 00 00 00 00 00 00 00 00'
'08 87 3A 80 00 00 00 0F F8 87 32 CC 60 00 00 08'
'F8 87 32 C6 68 00 00 87 8F 87 2C 66 86 00 08 78'
'78 87 2C 68 AA A0 07 87 87 70 08 2A A2 20 08 78'
'78 0F F0 II 15 50 05 51 II 0F F0 87 87 80 02 2A'
'A2 80 08 78 78 70 0A AA 86 C2 78 87 87 80 00 68'
'66 C2 78 F8 78 00 00 86 6C 23 78 8F 88 00 00 06'
'CC 23 78 8F F0 00 00 00 08 A3 78 80 00 00 00 00'
'00 00 00 00 00 00 F8 IF 00 00 E0 07 00 00 C0 03'
'00 00 80 01 00 00 80 01 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 80 01 00 00 80 01 00 00 C0 03 00 00 E0 07'
'00 00 F8 1F 00 00'
}

Рис. 2.3.1. Пример файла ресурсов с включенным туда кодом иконки.

2. Курсоры. Подход здесь полностью идентичен. Привожу ниже файл ресурсов, где определен и курсор, и иконка.

#define IDI_ICON1 1
#define IDI_CUR1 2

IDI_ICON1 ICON "Cdrom01.ico"
IDI_CUR1 CURSOR "4way01.cur"

А вот фрагмент программы, вызывающей иконку и курсор.

 ;----------иконка окна
 PUSH 1 ; идентификатор иконки
 PUSH [HINST]
 CALL LoadIconA@8
 MOV [WC.CLSHICON], EAX
 ; ----------курсор окна
 PUSH 2 ; идентификатор курсора
 PUSH [HINST]
 CALL LoadCursorA@8
 MOV [WC.CLSHCURSOR], EAX

Как и для иконки, программа brcc32.exe обрабатывает определение курсора в тексте файла ресурсов.

3. Битовые картинки (*.BMP). Здесь ситуация аналогична двум предыдущим. Вот пример файла ресурсов с битовой картинкой.

#define ВIТ1 1

BIT1 BITMAP "PIR2.BMP"

4. Строки. Чтобы задать строку или несколько строк используется ключевое слово STRINGTABLE. Ниже представлен текст ресурса, задающий две строки. Для загрузки строки в программу используется функция LoadString (см. ниже). Строки, задаваемые в файле ресурсов, могут играть роль констант.

#define STR1 1
#define STR2 2

STRINGTABLE
{
STR1, "Сообщение"
STR2, "Версия 1.01"
}

5. Диалоговые окна. Диалоговые окна являются наиболее сложными элементами ресурсов. В отличие от ресурсов, которые мы до сих пор рассматривали, для диалога не задается идентификатор. Обращение к диалогу происходит по его имени (строке).

#define WS_SYSMENU 0x00080000L
#define WS_MINIMIZEBOX 0x00020000L
#define WS_MAXIMIZEBOX 0x00010000L

DIAL1 DIALOG 0, 0, 240, 120
STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
CAPTION "Пример диалогового окна"
FONT 8, "Arial"
{
}

Как видим, определение диалога начинается со строки, содержащей ключевое слово DIALOG. В этой же строке далее указывается положение и размер диалогового окна. Далее идут строки, содержащие другие свойства окна. Наконец идут фигурные скобки. В данном случае они пусты. Это означает, что на окне нет никаких управляющих элементов. Тип окна, а также других элементов определяется константами, которые мы поместили в начале файла. Эти константы стандартны, и для языка Си хранятся в файле RESOURCE.H. Мы, как и раньше, все константы будем определять непосредственно в файле ресурсов. Обращаю ваше внимание, что константы определяются согласно нотации языка Си.

Прежде чем разбирать пример на Рис. 2.3.2, рассмотрим особенности работы с диалоговыми окнами. Диалоговое окно очень похоже на обычное окно. Так же как обычное окно, оно имеет свою процедуру. Процедура диалогового окна имеет те же параметры, что и процедура обычного окна. Сообщений, которые приходят на процедуру диалогового окна, гораздо меньше. Но те, которые у диалогового окна имеются, в основном совпадают с аналогичными сообщениями для обычного окна. Только вместо сообщения WM_CREATE приходит сообщение WM_INITDIALOG. Процедура диалогового окна может возвращать либо нулевое, либо ненулевое значение. Ненулевое значение должно возвращаться в том случае, если процедура обрабатывает (берет на себя обработку) данное сообщение, и ноль - если предоставляет обработку системе.

Отличия в поведении диалогового окна от обычного окна легко объяснить. Действительно, если Вы создаете обычное окно, то все его свойства определяются тремя факторами: свойствами класса, свойствами, определяемыми при создании окна, реакцией процедуры окна на определенные сообщения. При создании диалогового окна все свойства заданы в ресурсах. Часть этих свойств задается, когда при вызове функции создания диалогового окна (DialogBox, DialogBoxParam и др.) неявно вызывается функция CreateWindow. Остальная же часть свойств определяется поведением внутренней функции, которую создает система при создании диалогового окна. Если с диалоговым окном что-то происходит, то сообщение сначала приходит на внутреннюю процедуру, а затем вызывается процедура диалогового окна, которую мы создаем в программе. Если процедура возвращает 0, то внутренняя процедура продолжает обработку данного сообщения, если же возвращается ненулевое значение, внутренняя процедура не обрабатывает сообщение. Вот, вкратце, как работают механизмы, регулирующие работу диалогового окна. Рассмотрите теперь программу на Рис. 2.3.2, ниже будет дано ее разъяснение.

// файл dial.rc
// определение констант
#define WS_SYSMENU 0x00080000L
#define WS_MINIMIZEBOX 0x00020000L
#define WS_MAXIMIZEBOX 0x00010000L

// идентификаторы
#define STR1 1
#define STR2 2
#define IDI_ICON1 3

// определили иконку
IDI_ICON1 ICON "ico1.ico"

// определение диалогового окна
DIAL1 DIALOG 0, 0, 240, 120
STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
CAPTION "Пример диалогового окна"
FONT 8, "Arial"
{
}

// определение строк
STRINGTABLE
{
STR1, "Сообщение"
STR2, "Версия программы 1.00"
}
; файл dial.inc
; константы

; сообщение приходит при закрытии окна
WM_CLOSE equ 10h
WM_INITDIALOG equ 110h
WM_SETICON equ 80h
; прототипы внешних процедур
EXTERN MessageBoxA@16:NEAR
EXTERN ExitProcess@4:NEAR
EXTERN GetModuleHandleA@4:NEAR
EXTERN DialogBoxParamA@20:NEAR
EXTERN EndDialog@8:NEAR
EXTERN LoadStringA@16:NEAR
EXTERN LoadIconA@8:NEAR
EXTERN SendMessageA@16:NEAR
; структуры
; структура сообщения
MSGSTRUCT STRUC
 MSHWND DD ?
 MSMESSAGE DD ?
 MSWPARAM DD ?
 MSLPARAM DD ?
 MSTIME DD ?
 MSPT DD ?
MSGSTRUCT ENDS

;файл dial.asm
.386P

; плоская модель
.MODEL FLAT, stdcall
include dial.inc

; директивы компоновщику для подключения библиотек
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib
;--------------------------------------------------

; сегмент данных
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
 MSG MSGSTRUCT <?>
 HINST DD 0 ; дескриптор приложения
 PA DB "DIAL1",0
 BUF1 DB 40 dup(0)
 BUF2 DB 40 dup(0)
_DATA ENDS

; сегмент кода
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:
; получить дескриптор приложения
 PUSH 0
 CALL GetModuleHandleA@4
 MOV [HINST],EAX
;------
; загрузить строку
 PUSH 40
 PUSH OFFSET BUF1
 PUSH 1
 PUSH [HINST]
 CALL LoadStringA@16
; загрузить строку
 PUSH 40
 PUSH OFFSET BUF2
 PUSH 2
 PUSH [HINST]
 CALL LoadStringA@16
;------------------------------------------------------------
 PUSH 0 ; MB_OK
 PUSH OFFSET BUF1
 PUSH OFFSET BUF2
 PUSH 0
 CALL MessageBoxA@16
; создать диалоговое окно
 PUSH 0
 PUSH OFFSET WNDPROC ; процедура окна
 PUSH 0
 PUSH OFFSET PA ; название ресурса (DIAL1)
 PUSH [HINST]
 CALL DialogBoxParamA@20
 CMP EAX,-1
 JNE KOL
KOL:
 PUSH 0
 CALL ExitProcess@4
;--------------------------

; процедура диалогового окна
; расположение параметров в стеке
; [EBP+014Н] ; LPARAM
; [EBP+10H] ; WAPARAM
; [EBP+0CН] ; MES
; [EBP+8] ; HWND
WNDPROC PROC
 PUSH EBP
 MOV EBP,ESP
 PUSH EBX
 PUSH ESI
 PUSH EDI
;-----
 CMP DWORD PTR [EBP+ОСН], WM_CLOSE
 JNE L1
 PUSH 0
 PUSH DWORD PTR [EBP+08H]
 CALL EndDialog@8
 JMP FINISH
L1:
 CMP DWORD PTR [EBP+ОСН], WM_INITDIALOG
 JNE FINISH
; загрузить иконку
 PUSH 3 ; идентификатор иконки
 PUSH [HINST] ; идентификатор процесса
 CALL LoadIconA@8
; установить иконку
 PUSH EAX
 PUSH 0 ; тип иконки (маленькая)
 PUSH WM_SETICON
 PUSH DWORD PTR [EBP+08H]
 CALL SendMessageA@16
FINISH:
 POP EDI
 POP ESI
 POP EBX
 POP EBP
 MOV EAX, 0
 RET 16
WNDPROC ENDP
_TEXT ENDS
END START


Рис. 2.3.2. Демонстрация использования простых ресурсов.




Вход на сайт
Поиск
Календарь
«  Июль 2025  »
ПнВтСрЧтПтСбВс
 123456
78910111213
14151617181920
21222324252627
28293031
Архив записей
Наш опрос
Как Вам удобнее??
Всего ответов: 341
Мини-чат
Друзья сайта
  • Официальный блог
  • Сообщество uCoz
  • FAQ по системе
  • Инструкции для uCoz
  • Статистика

    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0