7.Явная загрузка библиотек

Предыдущие примеры объединяет одна особен­ность — динамическая библиотека загружается автоматически при старте программы. В этом просматриваются два недостатка.

- Загрузка программы немного теряет в скорости (не сильно, но все же), а функции из библиотеки могут вообще не понадобиться за все время вы­полнения программы.

- Может понадобиться поставлять программу в укороченном варианте без некоторых функций (без каких-либо DLL-файлов), но это не получится, потому что программа на этапе загрузки будет выдавать ошибку о том, что библиотека не найдена.

Задача: научиться использовать явную загрузку биб­лиотеки и в определенный момент.

В предыдущем примере будем использовать явную загрузку библиотеки для вызова функции ShowAbout. В принципе, если делать явную загрузку, то это нужно делать для всех функций и процедур библиотеки, по­тому что если вы оставите хотя бы одну неявной, то библиотека все равно будет грузиться на этапе старта программы, а явная загрузка будет только повторять уже выполненные действия. Для примера мы взяли только одну функцию, а процедуру попробуйте перевести на явную загрузку самостоя­тельно. Тем более что для этого не надо делать много изменений.

Итак, загрузите приложение, написанное в прошлом разделе главы, которое использует динамическую библиотеку. В основном модуле уберите объявле­ние функции ShowAbout. Теперь в разделе type напишите объявление но­вого типа:

ShowA = function (Handle: THandle):LongInt; stdcall;

Здесь мы объявляем новый тип ShowA, который является процедурным типом с парамет­рами функции ShowAbout из динамической библиотеки. Параметры должны быть точными, как при объявлении.

НЕ нашли? Не то? Что вы ищете?

Переходиим к обработчику события OnClick для первой кнопки, где мы показывали окно. Код, который вы должны здесь написать, приведен в листинге 1.4.

Листинг 1.4. Код явной загрузки библиотеки

procedure TForm1.Button1Click(Sender: TObject);

var

DLLHandle: THandle;

sa:ShowA;

begin

if f > 0 then

FreeAbout(f);

DLLHandle := LoadLibrary(‘ProjectDLL. DLL’);

if DLLHandle = 0 then

exit; //Библиотека не загрузилась

@sa := GetProcAddress(DLLHandle, ‘ShowAbout’);

if @sa = nil then

exit; //Функция не найдена

f := sa(Handle);

FreeLibrary(DLLHandle);

end;

Здесь объявлены две локальные переменные:

- DLLHandle - будет храниться указатель на загруженную библиотеку;

- sa - имеет тип ShowA, т. е. тип функции из библиотеки.

В начале кода выполняется уже знакомая проверка переменной f. Если она больше нуля, то окно уже показывалось, и нужно освободить память от ста­рого окна, прежде чем создавать новое.

Дальше вызывается функция LoadLibrary. Эта API-функция загружает ука­занную в качестве параметра динамическую библиотеку в память. Результатом выполнения является указатель на загруженную библиотеку. Этот указа­тель мы сохраняем в переменной DLLHandle. После этого нужно проверить, если указатель DLLHandle равен нулю, то библиотека не загрузилась.

Теперь требуется получить адрес функции ShowAbout в загруженной памяти, чтобы мы могли выполнить функцию. Для этого вызывается функция GetProcAddress. Функции нужно передать два параметра:

-  указатель на загруженную библиотеку;

-  имя искомой процедуры.

Результатом будет адрес искомой функции, и мы его сохраняем по адресу переменной @sa. Теперь sa указывает на адрес, по которому загружена процедура ShowAbout из динамической библиотеки. Единственное, что на­до проверить, — корректность адреса. Если он равен nil, то процедура не найдена (возможно, что это старая версия библиотеки или неправильно указано имя).

Если все нормально, то мы вызываем функцию через переменную f := sa(Handle), почти так же, как это делалось раньше. Результат выполне­ния функции сохраняется в переменной f.

Последняя строчка кода выгружает динамическую библиотеку из памяти - FreeLibrary. Точнее сказать, на этом этапе реальной выгрузки не происхо­дит. Функция только сообщает системе о том, что больше библиотека про­грамме не требуется. Если эту библиотеку использует другая программа (одну библиотеку могут использовать одновременно несколько программ), то она останется в памяти, пока та не сообщит о ненужности загруженного DLL-файла.