Ассемблер под Windows №17

Dynamic Link Library #2


Доброго времени суток, уважаемые подписчики.


Сегодня, как я и обещал, мы рассмотрим способы использования динамической библиотеки в программе. Как было упомянуто в прошлом уроке, процесс определения адресов процедуры называется связыванием. Связывание, в свою очередь может быть произведено явно или неявно. Сначала рассмотрим неявное связывание, так как на самом деле именно его мы использовали во всех наших программах. Неявное связывание подразумевает собой создание таблицы импорта, которую при загрузке программы заполняет система. Таблица составляется из .lib файлов и содержит все имена процедур API, используемых в программе. Система же, при заполнении таблицы, записывает в неё адреса этих процедур, после чего вызов процедуры может быть произведён call - ом по соответствующему адресу. Однако всё это делает за нас компилятор, поэтому единственное, что требуется от нас, это создать .inc файл и указать в нём, какие процедуры нам могут понадобиться. Рассмотрим пример неявного связывания с нашей библиотекой DLL1.dll:

include kernel32.inc
include user32.inc
include DLL1.inc
include def32.inc
.386
.model flat
.data
str1_db'Строка скопирована!',0
str2_db20 dup(0)
title_db'MessageBox',0
.code
_start:
xor ebx,ebx
push offset str1_
push offset str2_
call CopyString
push MB_OK
push offset title_
push offset str2_
push ebx
call MessageBox
push ebx
call ExitProcess
end _start

Если всё сделано правильно, то при запуске программы (если DLL1.dll находится в том же директории, что и программа) будет выдано сообщение "Срока скопирована!". При этом следует учесть, что Вы должны создать файл .inc к нашей библиотеке.

Теперь переделаем нашу программу так, чтоб она использовала явное связывание. При явном связывании таблицы импорта не создаётся, и связывание возлагается на программу. Для этих целей существуют свои API функции, LoadLibrary (получает один параметр, имя библиотеки), FreeLibrary (идентификатор загруженной библиотеки) и GetProcAddress (имя функции и идентификатор библиотеки). Естественно явно связать kernel32.dll с программой не получится, так как функции, предназначенные для этого, находятся в этой библиотеке. Также нет смысла явно связывать библиотеки постоянно находящиеся в памяти (user32, shell32 и т.д.), так как главным достоинством явного связывания является возможность лучше использовать память (загружая и выгружая библиотеки по мере надобности). Посмотрим что же получится из нашей программы:

include kernel32.inc
include user32.inc
include def32.inc
.386
.model flat
.data
str1_db'Строка скопирована!',0
str2_db20 dup(0)
title_db'MessageBox',0
librarydb'DLL1.dll',0
CopyStrdb'CopyString',0
.code
_start:
xor ebx,ebx
push offset library
call LoadLibrary
push offset CopyStr
push eax
call GetProcAddress
push offset str1_
push offset str2_
call eax
push MB_OK
push offset title_
push offset str2_
push ebx
call MessageBox
push ebx
call ExitProcess
end _start

Рассмотрим выделенный красным участок кода. Вначале мы загружаем библиотеку в память, получая идентификатор загруженной библиотеки в eax. Используя этот идентификатор, мы вызываем функцию GetProcAddress, получая в eax смещение нужной нам процедуры, и выполняем её! Так как всё используемое процессом удаляется при его закрытии, в этом случае нет смысла закрывать библиотеку, так как она будет закрыта процедурой ExitProcess.

Следующие файлы доступны для скачивания:
0017asm - код обеих программ
0017inc - файлы дополнения
0017lib - библиотеки импорта
0017exe - скомпилированные файлы
0016asm - код библиотеки
0016dll - скомпилированная библиотека


На сегодня это всё. Если есть какие вопросы, пишите, обязательно отвечу. Пишите, Dark_Lord@RusFAQ.ru, Dark_Lord@land.ru.
Или свяжитесь со мной по ICQ, мой номер 126222874!

Сайт управляется системой uCoz