На этом шаге мы рассмотрим использование ресурсов из 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. Результат работы приложения
Трансляция динамической библиотеки:
ML /с /coff /DMASM pr74_1.asm rc pr74_1a.rc LINK /SUBSYSTEM:WINDOWS /DLL /ENTRY:DLLENTRY pr73_1.obj pr74_1a.res
TASM32 /ml pr74_1.asm brcc32 pr74_1a.rc TLINK32 -aa -Tpd pr74_1.obj,,,,pr74_1.def,pr74_1a.res Содержимое файла pr74_1.def: EXPORTS SETIC
Трансляция программы:
ML /с /coff /DMASM pr74_2.asm rc pr74_1b.rc LINK /SUBSYSTEM:WINDOWS pr74_2.obj pr74_1b.res
TASM32 /ml pr74_2.asm brcc32 pr74_1b.rc TLINK32 -aa pr74_2.obj pr74_1b.res
Как мы уже не раз с вами убеждались, динамически подключаемая библиотека становится частью программы, обладая вместе с процессом всеми ее возможностями, Так, при помощи функций GetMessage и PeekMessage она может получать сообщения, предназначенные для процесса. Если вы хотите создать в DLL окно, то вам следует воспользоваться идентификатором вызвавшей динамически подключаемую библиотеку программы.
На следующем шаге мы рассмотрим совместное использование памяти разными процессами.