Шаг 74.
Использование общего адресного пространства (окончание)

    На этом шаге мы рассмотрим использование ресурсов из DLL.

    На этом шаге мы рассмотрим весьма интересный пример. Основной процесс использует ресурсы загруженной им динамической библиотеки. Мы уже отмечали, что файлы шрифтов, по сути, являются динамическими библиотеками. Не правда ли, удобно: ресурсы можно поместить отдельно от основной программы в динамическую библиотеку, загружая их по мере необходимости? Наша программа вначале загружает пиктограмму из ресурсов динамической библиотеки и устанавливает ее на окно. Если вы будете щелкать левой кнопкой мыши, направив курсор на окно, то будет вызываться процедура из динамической библиотеки, которая будет поочередно устанавливать то один, то другой значок на окно.

    Файл pr74_1a.rc - файл ресурсов динамически подключаемой библиотеки.

//Идентификаторы. 
#define IDI_ICON1  3 
#define IDI_ICON2 10 
//Определили пиктограмму. 
IDI_ICON1  ICON   "delphi.ico" 
IDI_ICON2  ICON   "cbuilder.ico"

    Файл pr74_1.asm - динамически подключаемая библиотека.

.386P
PUBLIC SETIC
;Плоская модель.
IFDEF MASM
.MODEL FLAT, STDCALL
ELSE
.MODEL FLAT
ENDIF
;Константы.
WM_SETICON     equ  80h     
IFDEF MASM
;MASM
;Прототипы внешних процедур.
    EXTERN  LoadIconA@8:NEAR
    EXTERN  PostMessageA@16:NEAR 
;Директивы компоновщику для подключения библиотек.
;Для компоновщика  LINK.EXE.
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
ELSE
;TASM
    EXTERN  LoadIconA:NEAR
    EXTERN  PostMessageA:NEAR 
    LoadIconA@8     =  LoadIconA
    PostMessageA@16 =  PostMessageA
;Для компоновщика  TLINK32.EXE.
    includelib c:\tasm32\lib\import32.lib
ENDIF
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     PRIZ   DB  0
_DATA ENDS 
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
; [EBP+10H] - Резервный параметр.
; [ЕВР+0СН] - Причина вызова.
; [ЕВР+8]   - Идентификатор DLL-модуля.
DLLENTRY:
     MOV  EAX,1
     RET  12
;-------------------------------------
;Адреса параметров
; [EBP+8]	
; [ЕВР+0СН]	
SETIC PROC EXPORT
      PUSH EBP
      MOV  EBP,ESP
;Выбрать, какую пиктограмму устанавливать.
      CMP  PRIZ,0
      JZ   IC_1
      MOV  PRIZ,0
      PUSH 3
      JMP  CONT 
IC_1:
      MOV  PRIZ,1
      PUSH 10 
CONT: 
;Загрузить пиктограмму из ресурсов библиотеки.
      PUSH DWORD PTR [EBP+0CH] ;Идентификатор динамической библиотеки.
      CALL LoadIconA@8 
;Установить  значок окна.
      PUSH EAX
      PUSH 0
      PUSH WM_SETICON
      PUSH DWORD PTR [EBP+08H] ;Дескриптор окна.
      CALL PostMessageA@16
      POP  EBP
      RET  8 
SETIC ENDP 
_TEXT ENDS 
      END DLLENTRY

    Файл pr74_1b.rc - файл ресурсов основной программы.

//Определение констант.
#define WS_SYSMENU      0x00080000L
#define WS_MINIMIZEBOX  0x00020000L
#define WS_MAXIMIZEBOX  0x00010000L
#define DS_3DLOOK       0x0004L
//Определение диалогового окна.
DIAL1  DIALOG  0,   0,   340,   120
STYLE WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | DS_3DLOOK
CAPTION  "Диалоговое окно с пиктограммой из динамической библиотеки"
FONT 8,   "Arial"
{
}

    Файл pr74_2.asm - основной модуль, вызывающий процедуру из DLL.

.386P
;Плоская модель.
IFDEF MASM
.MODEL FLAT, STDCALL
ELSE
.MODEL FLAT
ENDIF
;Константы.
;Сообщение приходит при закрытии окна.
WM_CLOSE       equ 10h
WM_INITDIALOG  equ 110h
WM_SETICON     equ 80h
WM_LBUTTONDOWN equ 201h
;Прототипы внешних процедур.
IFDEF MASM
;MASM
     EXTERN  PostMessageA@16:NEAR 
     EXTERN  GetProcAddress@8:NEAR 
     EXTERN  LoadLibraryA@4:NEAR 
     EXTERN  FreeLibrary@4:NEAR 
     EXTERN  ExitProcess@4:NEAR 
     EXTERN  GetModuleHandleA@4:NEAR 
     EXTERN  DialogBoxParamA@20:NEAR 
     EXTERN  EndDialog@8:NEAR 
     EXTERN  LoadIconA@8:NEAR
;Директивы компоновщику для подключения библиотек.
;Для компоновщика  LINK.EXE.
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
ELSE
;TASM
     EXTERN  PostMessageA:NEAR 
     EXTERN  GetProcAddress:NEAR 
     EXTERN  LoadLibraryA:NEAR 
     EXTERN  FreeLibrary:NEAR 
     EXTERN  ExitProcess:NEAR 
     EXTERN  GetModuleHandleA:NEAR 
     EXTERN  DialogBoxParamA:NEAR 
     EXTERN  EndDialog:NEAR 
     EXTERN  LoadIconA:NEAR
     PostMessageA@16     = PostMessageA 
     LoadIconA@8         = LoadlconA 
     EndDialog@8         = EndDialog 
     GetModuleHandleA@4  = GetModuleHandleA 
     DialogBoxParamA@20  = DialogBoxParamA 
     GetProcAddress@8    = GetProcAddress 
     LoadLibraryA@4      = LoadLibraryA 
     FreeLibrary@4       = FreeLibrary 
     ExitProcess@4       = ExitProcess
;Для компоновщика  TLINK32.EXE.
    includelib c:\tasm32\lib\import32.lib
ENDIF
;------------------------------------------------
;Сегмент данных. 
_DATA SEGMENT DWORD PUBLIC USE32 'DATA'
     LIBR  DB   'pr74_1.DLL',0
     HLIB  DD   ?
     HINST DD   ?
     PA    DB   'DIAL1',0
IFDEF MASM	
     NAMEPROC  DB   '_SETIC@0',0
ELSE	
     NAMEPROC  DB   'SETIC',0
ENDIF	
_DATA ENDS 
;Сегмент кода.
_TEXT SEGMENT DWORD PUBLIC USE32 'CODE'
START:	
;Получить дескриптор приложения.
      PUSH  0
      CALL  GetModuleHandleA@4
;Создать диалог.
      MOV   [HINST], EAX
      PUSH  0
      PUSH  OFFSET WNDPROC
      PUSH  0
      PUSH  OFFSET PA
      PUSH  [HINST]
      CALL  DialogBoxParamA@20
;Выход.
_EXIT:
      PUSH  0
      CALL  ExitProcess@4 
;Процедура окна.
;Расположение параметров в стеке. 
;[ВР+14Н]  - 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_CLOSE
      JNE   L1
;Закрыть библиотеку.
;Библиотека автоматически закрывается также 
;при выходе из программы.
      PUSH  HLIB
      CALL  FreeLibrary@4
      PUSH  0
      PUSH  DWORD PTR [EBP+08H]
      CALL  EndDialog@8
      JMP   FINISH 
L1:
      CMP   DWORD PTR [EBP+0CH] ,WM_INITDIALOG
      JNE   L2 
;Загрузить библиотеку.
      PUSH  OFFSET LIBR
      CALL  LoadLibraryA@4
      MOV   HLIB,EAX 
;Загрузить пиктограмму.
      PUSH  3      ;Идентификатор пиктограммы.
      PUSH  [HLIB] ;Идентификатор процесса.
      CALL  LoadIconA@8 
;Установить пиктограмму.
      PUSH  EAX
      PUSH  0     ;Тип пиктограммы (маленькая).
      PUSH  WM_SETICON
      PUSH  DWORD PTR [EBP+08H]
      CALL  PostMessageA@16
      JMP   FINISH 
L2:
      CMP   DWORD PTR [EBP+0CH],WM_LBUTTONDOWN
      JNE   FINISH 
;Получить адрес процедуры из динамической библиотеки.
      PUSH  OFFSET NAMEPROC
      PUSH  HLIB
      CALL  GetProcAddress@8 
;Вызвать процедуру с двумя параметрами.
      PUSH  [HLIB]
      PUSH  DWORD PTR [EBP+08H]
      CALL  EAX 
FINISH:
      POP   EDI
      POP   ESI
      POP   EBX
      POP   EBP
      MOV   EAX,0
      RET   16 
WNDPROC ENDP 
_TEXT ENDS 
      END START
Тексты этох файлов, а также используемые пиктограммы, можно взять здесь.

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


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

    Трансляция динамической библиотеки:

    Трансляция программы:

    Как мы уже не раз с вами убеждались, динамически подключаемая библиотека становится частью программы, обладая вместе с процессом всеми ее возможностями, Так, при помощи функций GetMessage и PeekMessage она может получать сообщения, предназначенные для процесса. Если вы хотите создать в DLL окно, то вам следует воспользоваться идентификатором вызвавшей динамически подключаемую библиотеку программы.

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




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