платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 17 - Динамические библиотеки

Предыдущая тема Следующая тема Перейти вниз

платформа Win32 - Туториалы Iczelion'a на русском, адаптированные для FreeBasic. Урок 17 - Динамические библиотеки

Сообщение  electrik в Пн Июн 29, 2009 7:46 pm

Win32 API. Урок 17. Динамические библиотеки

В этом туториале мы узнаем о dll, что это такое и как их создавать.

Теория:

Если вы программируете достаточно долго, вы заметите, что программы, которые вы пишете, зачастую используют одни и те же общие процедуры. Из-за того, что вам приходиться переписывать их снова и снова, вы теряете время. Во времена DOS'а программисты сохраняли эти общие процедуры в одной или более библиотеках. Когда они хотели использовать эти функции, они всего лишь прилинковывали библиотеку к объектному файлу и линкер извлекал функции прямо из библиотек и вставлял их в финальный файл. Этот процесс называется статической линковкой. Хорошим примером являются стандартные библиотеки в C. У этого метода есть изъян - то, что в каждой программе у вас находятся абсолютно одинаковые копии функций. Впрочем, для ДОСовских программ это не очень большой недостаток, так как только одна программа могла быть активной в памяти, поэтому не происходила трата драгоценной памяти.

Под Windows ситуация стала более критичной, так как у вас может быть несколько программ, выполняющихся одновременно. Память будет быстро пожираться, если ваша программа достаточно велика. У Windows есть решение этой проблемы: динамические библиотеки (dynamic link libraries). Динамическая библиотека - это что-то вроде сборника общих функций. Windows не будет загружать несколько копий DLL в память; даже если одновременно выполняются несколько экземпляров вашей программы, будет только одна копия DLL в памяти. Здесь я должен остановиться и разъяснить чуть поподробнее. В реальности, у всех процессов, использующих
одну и ту же dll есть своя копия этой библиотеки, однако Windows делает так, чтобы все процессы разделяли один и тот же код этой dll. Впрочем, секция данных копируется для каждого процесса.

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

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

И тут в дело вступают библиотеки импорта. Библиотека импорта содержит информацию о DLL, которую она представляет. Линкер может получить из нее необходимую информацию и вставить ее в исполняемый файл.

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

Вы можете загрузить DLL самостоятельно, не полагаясь на Windows-загрузчик.

• В этом случае вам не потребуется библиотека импорта, поэтому вы сможете загружать и использовать любую DLL, даже если к ней не прилагается библиотеки импорта. Тем не менее, вам все равно нужно знать какие функции находятся внутри нее, сколько параметров они принимают и тому подобную информацию.
• Когда вы поручаете Windows загружать DLL, если та отсутствует, Windows выдаст сообщение "Требуемый .DLL-файл, xxxxx.dll отсутствует" и все! Ваша программа не может сделать ничего, чтоб изменить это, даже если ваша dll не является необходимой. Если же вы будете загружать DLL самостоятельно и библиотека не будет найдена, ваша программа может выдать пользователю сообщение, уведомляющее об этом, и продолжить работу.
• Вы можете вызывать *недокументированные* функции, которые не включены в библиотеки импорта, главное, чтобы у вас было достаточно информации об этих функциях.
• Если вы используете LoadLibrary, вам придется вызывать GetprocAddress для каждой функции, которую вы заходите вызвать. GetprocAddress получает адрес входной точки функции в определенной DLL. Поэтому ваш код будет чуть-чуть больше и медленнее, но не намного.

Теперь, рассмотрев преимущества и недостатки использования LoadLibrary, мы подробно рассмотрим как создать DLL.
Для полного представления механизма создания dll, рекомендуется прочитать:
http://freebasic.justforum.net/forum-f10/tema-t111.htm
http://freebasic.justforum.net/forum-f10/tema-t152.htm

файл mydll.bas

Код:

extern "Windows-MS"
function AddFive alias "AddFive"(byval number as integer) as integer export
number+=5
function = number
end function
end extern

компилировать
fbc -dll mydll.bas

После компиляции вы получите .dll и .a. Последний файл - это библиотека импорта, которую вы можете использовать, чтобы прилинковать к другим программам функции из соответствующей .dll.

Далее я покажу вам как использовать LoadLibrary, чтобы загрузить DLL.

файл usedll.bas

Код:

#include "windows.bi"

#define DllNotFound "Cannot load library"
#define FunctionNotFound "AddFive function not found"
#define AppName "Load Library"
#undef GetProcAddress ' отменим объявление функции GetProcAddress
#undef FARPROC ' и тип FarProc, так как нам оно не потходит
' см "inc/win/windef.bi" и "inc/win/winbase.bi"
type FARPROC as function ( byval num as integer) as integer ' переопределим тип FARPROC под нашу функцию
' и определим функцию возвращающую переопределенный тип FARPROC
extern "windows" lib "kernel32"
declare function GetProcAddress (byval as HINSTANCE, byval as LPCSTR) as FARPROC
end extern
dim hLib as HINSTANCE ' хэндл библиотеки dll

' создадим переменную типа FARPROC, туда запишется адрес полученный GetProcAddress
dim AddFive as FARPROC
hLib = LoadLibrary("mydll.dll") ' загружаем библиотеку
' Вызываем LoadLibrary и передаем имя желаемой DLL. Если вызов проходит успешно,
' будет возвращен хэндл библиотеки (DLL). Если нет, то будет возвращен NULL.
' Вы можете передать хэндл библиотеки функции GetрrocAddress или любой другой
' функции, которая требует его в качестве одного из параметров.
'-------------------------------------------------------------------------------

if hLib = NULL then ' если не получили хэндл библиотеки
MessageBox(NULL,DllNotFound,AppName,MB_OK)
else
AddFive = GetProcAddress _ ' получим адрес функции
(hLib, _ ' хэндл библиотеки
"AddFive") ' название функции
'------------------------------------------------------------------------------
' Когда вы получаете хэндл библиотеки, вы передаете его GetрrocAddress вместе
' с именем функции в этой dll, которую вы хотите вызвать. Она возвратит адрес
' функции, если вызов пройдет успешно. В противном случае, она возвратит NULL.
' Адреса функций не изменятся, пока вы не перезагрузите библиотеку. Поэтому
' их можно поместить в глобальные переменные для будущего использования.
'---------------------------------------------------- --------------------------

if AddFive = 0 then
    MessageBox(NULL,FunctionNotFound,AppName,MB_OK)
else
    MessageBox(NULL,str(AddFive(4)),AppName,MB_OK)
'----------------------------------------------------------------------------
' Затем мы вызываем функцию из переменной, содержащей адрес
' функции.
'----------------------------------------------------------------------------
end if
FreeLibrary(hLib)
'------------------------------------------------------------------------------
' Когда вам больше не требуется библиотека, выгрузте ее с помощью FreeLibrary.
'------------------------------------------------------------------------------
end if

Как вы можете видеть, использование LoadLibrary чуть сложнее, но гораздо гибче.

[C] Iczelion, пер. Aquila.

electrik

Сообщения : 391
Дата регистрации : 2008-09-02
Возраст : 36
Откуда : галактика Млечный путь, система Солнечная, планета Земля, страна россия, город Санкт Петербург

Посмотреть профиль

Вернуться к началу Перейти вниз

Предыдущая тема Следующая тема Вернуться к началу


 
Права доступа к этому форуму:
Вы не можете отвечать на сообщения