Шаг 33.
Язык описания ресурсов. Пиктограммы

    На этом шаге мы рассмотрим включение пиктограмм в приложение.

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

    #define IDI_ICON1 1 
    IDI_ICON1 ICON "help.ico"

    Как видите, файл содержит всего две значимых строки. Одна строка определяет идентификатор пиктограммы, вторая - ассоциирует идентификатор с файлом help.ico. Оператор define является С-оператором препроцессора. Как вы увидите в дальнейшем, язык ресурсов очень напоминает язык С. Откомпилируем текстовый файл resu.rc:

    RC resu.rc                 . 

    На диске появляется объектный файл resu.RES. При компоновке укажем этот файл в командной строке:

    LINK /subsystem:windows <имя объектного файла> 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
    .     .     .     .

    Изменим программу из шага 16, разместив в ней идентификатор пиктограммы из файла ресурса.


    Заголовочный файл для приложения, содержащий определения констант, внешних процедур и структур (его имя pr33_1.asm). Из него мы убрали определение идентификатора пиктограммы окна (константу IDI_APPLICATION) :
;Константы.
;Сообщение приходит при закрытии окна.
WM_DESTROY	equ 2
;Сообщение приходит при создании окна.
WM_CREATE	equ 1
;Сообщение при щелчке левой кнопкой мыши в области окна.
WM_LBUTTONDOWN	equ 201h
WM_COMMAND	equ 111h
;Свойства окна.
CS_WREDRAW	equ 1h
CS_HREDRAW	equ 2h
CS_GLOBALCLASS	equ 4000h
WS_OVERLAPPEDWINDOW     equ  000CF0000H
STYLE equ CS_HREDRAW+CS_WREDRAW+CS_GLOBALCLASS
BS_DEFPUSHBUTTON  equ  1h
WS_VISIBLE        equ  10000000h
WS_CHILD          equ  40000000h
STYLBTN equ WS_CHILD+BS_DEFPUSHBUTTON+WS_VISIBLE
;Идентификатор курсора.
IDC_ARROW  equ  32512
;Режим показа окна - нормальный.
SW_SHOWNORMAL	equ  1
;Прототипы внешних процедур.
EXTERN    MessageBoxA@16:NEAR
EXTERN    CreateWindowExA@48:NEAR
EXTERN    DefWindowProcA@16:NEAR
EXTERN    DispatchMessageA@4:NEAR
EXTERN    ExitProcess@4:NEAR
EXTERN    GetMessageA@16:NEAR
EXTERN    GetModuleHandleA@4:NEAR
EXTERN    LoadCursorA@8:NEAR
EXTERN    LoadIconA@8:NEAR
EXTERN    PostQuitMessage@4:NEAR 
EXTERN    RegisterClassA@4:NEAR
EXTERN    ShowWindow@8:NEAR
EXTERN    TranslateMessage@4:NEAR
EXTERN    UpdateWindow@4:NEAR
;Структуры
;Структура сообщения.
MSGSTRUCT  STRUC	
           MSHWND     DD ? ;Идентификатор окна, получающего сообщение.
           MSMESSAGE  DD ? ;Идентификатор сообщения.
           MSWPARAM   DD ? ;Доп. информация о сообщении.
           MSLPARAM   DD ? ;Доп. информация о сообщении.
           MSTIME     DD ? ;Время посылки сообщения.
           MSPT       DD ? ;Положение курсора во время посылки сообщения.
MSGSTRUCT ENDS	
;-----------------------
WNDCLASS  STRUC	
           CLSSTYLE     DD ? ;Стиль окна.
           CLWNDPROC    DD ? ;Указатель на процедуру окна.
           CLSCBCLSEX   DD ? ;Информация о доп. байтах для данной структуры.
           CLSCBWNDEX   DD ? ;Информация о доп. байтах для окна.
           CLSHINST     DD ? ;Дескриптор приложения.
           CLSHICON     DD ? ;Идентификатор иконки окна.
           CLSHCURSOR   DD ? ;Идентификатор курсора окна.
           CLBKGROUND   DD ? ;Идентификатор кисти окна.
           CLMENNAME    DD ? ;Имя-идентификатор меню.
           CLNAME       DD ? ;Специфицирует имя класса окон.
WNDCLASS  ENDS 
Текст этого модуля, а также исходный, откомпилированный файлы ресурсов и файл с пиктограммой можно взять здесь.


    Основной файл приложения, содержит подключение файла pr33_1.asm (его имя pr33_2.asm). В этом файле мы закомментировали установку стандартной пиктограммы окна и ниже разместили установку пиктограммы из файла ресурсов:
.386P
;Плоская модель.
.MODEL FLAT, STDCALL
include pr33_1.asm
;Директивы компоновщику для подключения библиотек.
includelib c:\masm32\lib\user32.lib 
includelib c:\masm32\lib\kernel32.lib
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     NEWHWND    DD 0
     MSG        MSGSTRUCT <?>
     WC         WNDCLASS <?>
     HINST       DD 0 ;Здесь хранится дескриптор приложения.
     TITLENAME   DB 'Пример - кнопка выхода',0
     CLASSNAME   DB 'CLASS32',0
     CPBUT       DB 'Выход',0 ;Выход.
     CLSBUTN     DB 'BUTTON',0
     HWNDBTN     DWORD 0
     CAP         DB 'Сообщение',0
     MES         DB 'Конец работы программы',0
_DATA ENDS 
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START: 
;Получить дескриптор приложения.
     PUSH  0
     CALL  GetModuleHandleA@4
     MOV   [HINST], EAX
REG_CLASS:
;Заполнить структуру окна.
;Стиль.
     MOV [WC.CLSSTYLE],STYLE 
;Процедура обработки сообщений.
     MOV   [WC.CLWNDPROC], OFFSET WNDPROC
     MOV   [WC.CLSCBCLSEX], 0
     MOV   [WC.CLSCBWNDEX], 0
     MOV   EAX, [HINST]
     MOV   [WC.CLSHINST], EAX
 
;------------ пиктограмма окна
;    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
;------------ курсор окна
    PUSH   IDC_ARROW
    PUSH   0
    CALL   LoadCursorA@8
    MOV    [WC.CLSHCURSOR], EAX
;------------
    MOV    [WC.CLBKGROUND], 17   ;Цвет окна.
    MOV    DWORD PTR [WC.CLMENNAME],0
    MOV    DWORD PTR [WC.CLNAME], OFFSET  CLASSNAME
    PUSH   OFFSET WC
    CALL   RegisterClassA@4
;Создать окно зарегистрированного класса.
    PUSH   0
    PUSH   [HINST]
    PUSH   0
    PUSH   0
    PUSH   400 ;   DY - высота окна.
    PUSH   400 ;   DX - ширина окна.
    PUSH   100 ;  Y - координата левого верхнего угла.
    PUSH   100 ;  X - координата левого верхнего угла.
    PUSH   WS_OVERLAPPEDWINDOW
    PUSH      OFFSET TITLENAME  ;Имя окна.
    PUSH      OFFSET CLASSNAME  ;Имя класса.
    PUSH   0
    CALL    CreateWindowExA@48
;Проверка на ошибку.
    CMP    EAX,0
    JZ    _ERR
    MOV   [NEWHWND], EAX  ;Дескриптор окна.
;------------------------------------
    PUSH  SW_SHOWNORMAL
    PUSH  [NEWHWND]
    CALL  ShowWindow@8      ;Показать созданное окно.
;------------------------------------
    PUSH  [NEWHWND]
    CALL UpdateWindow@4     ;Команда перерисовать видимую
                            ;часть окна, сообщение WM_PAINT.
;Цикл обработки сообщений 
MSG_LOOP:
    PUSH 0
    PUSH 0
    PUSH 0
    PUSH OFFSET MSG
    CALL GetMessageA@16
    CMP  EAX, 0
    JE   END_LOOP
    PUSH  OFFSET MSG
    CALL TranslateMessage@4
    PUSH OFFSET MSG
    CALL DispatchMessageA@4
    JMP  MSG_LOOP 
END_LOOP: 
;Выход из программы (закрыть процесс).
    PUSH  [MSG.MSWPARAM]
    CALL ExitProcess@4
_ERR:
    JMP  END_LOOP
;-----------------------------------------
;Процедура окна.
;Расположение параметров в стеке: 
;[ЕВР+014Н] LPARAM 
;[ЕВР+10Н] WAPARAM 
;[ЕВР+0СН] MES 
;[ЕВР+8] HWND 
WNDPROC PROC
        PUSH EBP
        MOV  EBP, ESP
        PUSH EBX
        PUSH ESI
        PUSH EDI
        CMP  DWORD PTR [EBP+0CH], WM_DESTROY
        JE   WMDESTROY
        CMP  DWORD PTR [EBP+0CH], WM_CREATE
        JE   WMCREATE
        CMP  DWORD PTR   [EBP+0CH],WM_COMMAND
        JE   WMCOMMAND
        JMP  DEFWNDPROC
;Нажатие правой кнопки приводит к закрытию окна.
WMCOMMAND:
        MOV  EAX,HWNDBTN
        CMP  DWORD PTR [EBP+14H], EAX ;Не кнопка ли нажата?
        JE   WMDESTROY
        MOV  EAX,0
        JMP  FINISH
WMCREATE:	
;Создать окно-кнопку.
        PUSH 0
        PUSH [HINST]
        PUSH 0
        PUSH DWORD PTR [EBP+08H]
        PUSH 20  ;DY
        PUSH 60  ;DX
        PUSH 10  ;Y
        PUSH 10  ;X
        PUSH STYLBTN
        PUSH OFFSET CPBUT   ;Имя окна.
        PUSH OFFSET CLSBUTN ;Имя класса.
        PUSH 0
        CALL CreateWindowExA@48
        MOV  HWNDBTN,EAX    ;Запомнить дескриптор кнопки.
        JMP  FINISH
DEFWNDPROC:	
        PUSH DWORD PTR [EBP+14H]
        PUSH DWORD PTR [EBP+10H]
        PUSH DWORD PTR [EBP+0CH]
        PUSH DWORD PTR [EBP+08H]
        CALL DefWindowProcA@16
        JMP  FINISH
WMDESTROY:	
        PUSH 0  ;MB_OK
        PUSH OFFSET CAP
        PUSH OFFSET MES
        PUSH DWORD PTR [EBP+08H]   ;Дескриптор окна.
        CALL MessageBoxA@16
        PUSH 0
        CALL PostQuitMessage@4   ;Сообщение WM_QUIT.
        MOV  EAX, 0
FINISH:	
        POP  EDI
        POP  ESI
        POP  EBX
        POP  EBP
        RET  16
WNDPROC ENDP
_TEXT   ENDS	
        END START
Текст этой программы можно взять здесь.

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

  1. Откомпилировать файл ресурсов, выполнив команду:
                   RC resu.rc                 . 
    
  2. Откомпилировать исходный файл, выполнив команду:
                  ML.EXE  /c /coff  pr33_2.asm          .
    
    Файл pr33_1.asm должен находиться в той же папке, что и pr33_2.asm

  3. Отлинковать полученный OBJ-файл, выполнив команду:
        LINK /subsystem:windows pr33_2.obj resu.res
    

    Результат работы программы представлен на рисунке 1 (обратите внимание на пиктограмму окна - она изменилась!):


Рис.1. Результат работы приложения

    В заключение отметим, что компилятор ресурсов brcc32.exe (из пакета TASM32) допускает включение пиктограммы в текст проекта.

    На следующем шаге мы рассмотрим использование курсоров.




Предыдущий шаг Содержание Следующий шаг