Динамический импорт

Действия по загрузке и подключению библиотеки (выполняемые при статическом импорте автоматически) можно проделать самостоятельно, обратившись к стандартным функциям операционной системы. Таким образом, импорт можно произвести динамически во время работы программы (а не во время ее запуска).

Для динамического импорта необходимо:

1.загрузить библиотеку в оперативную память вызовом функции LoadLibrary;

2. затем извлечь из нее адреса подпрограмм с помощью функции GetProcAddress.

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

4. для завершения работы с библиотекой необходимо вызвать функцию FreeLibrary.

Ниже приведено краткое описание функцийLoadLibrary, FreeLibrary и GetProcAddress.

  • LoadLibrary(LibFileName: PChar): HModule — загружает в оперативную память библиотеку, которая хранится на диске в файле с именем LibFileName. При успешном выполнении функция возвращает числовой описатель библиотеки, который должен использоваться в дальнейшем для управления библиотекой. Если при загрузке библиотеки призошла какая-нибудь ошибка, то возвращается нулевое значение. Если аргумент LibFileName содержит имя файла без маршрута, то этот файл ищется в следущих каталогах: в каталоге, из которого была запущена главная программа, в текущем каталоге, в системном каталоге операционной системы Windows (его точный маршрут можно узнать вызовом функции GetSystemDirectory), в каталоге, по которому установлена операционная система (его точный маршрут можно узнать вызовом функции GetWindowsDirectory), а также в каталогах, перечисленных в переменной окружения PATH.
  • FreeLibrary(LibModule: HModule): Bool — выгружает библиотеку, заданную описателем LibModule, из оперативной памяти и освобождает занимаемые библиотекой ресурсы системы.
  • GetProcAddress(Module: HModule; ProcName: PChar): Pointer — возвращает адрес подпрограммы с именем ProcName в библиотеке с описателем Module. Если подпрограмма с именем ProcName в библиотеке не существует, то функция возвращает значение nil (пустой указатель).

В приложении № показано использование техники динамического импорта:

program TestDynamicImport; {$APPTYPE CONSOLE} uses Windows; type TBubleSortProc = procedure (var Arr: array of Integer); stdcall; TQuickSortProc = procedure (var Arr: array of Integer); stdcall; var BubleSort: TBubleSortProc; // указатель на функцию BubleSort QuickSort: TQuickSortProc; // указатель на функцию QuickSort LibHandle: HModule; // описатель библиотеки Arr: array [0..9] of Integer; I: Integer; begin LibHandle := LoadLibrary('SortLib.dll'); if LibHandle <> 0 then begin @BubleSort := GetProcAddress(LibHandle, 'BubleSortIntegers'); @QuickSort := GetProcAddress(LibHandle, 'QuickSortIntegers'); if (@BubleSort <> nil) and (@QuickSort <> nil) then begin Randomize; for I := Low(Arr) to High(Arr) do Arr[I] := Random(100); BubleSort(Arr); for I := Low(Arr) to High(Arr) do Write(Arr[I], ' '); Writeln; for I := Low(Arr) to High(Arr) do Arr[I] := Random(100); QuickSort(Arr); for I := Low(Arr) to High(Arr) do Write(Arr[I], ' '); Writeln; end else Writeln('Ошибка отсутствия процедуры в библиотеке.'); FreeLibrary(LibHandle); end else Writeln('Ошибка загрузки библиотеки.'); Writeln('Press Enter to exit...'); Readln;end.

В программе определены два процедурных типа данных, которые по списку параметров и правилу вызова (stdcall) соответствуют подпрограммам сортировки BubleSort и QuickSort в библиотеке:

type TBubleSortProc = procedure (var Arr: array of Integer); stdcall; TQuickSortProc = procedure (var Arr: array of Integer); stdcall;

Эти типы данных нужны для объявления процедурных переменных, в которых сохраняются адреса подпрограмм:

var BubleSort: TBubleSortProc; QuickSort: TQuickSortProc;

В секции var объявлена также переменная для хранения целочисленного описателя библиотеки, возвращаемого функцией LoadLibrary:

var ... LibHandle: HModule;

Программа начинает свою работу с того, что вызывает функцию LoadLibrary, в которую передает имя файла DLL-библиотеки. Функция возвращает описатель библиотеки, который сохраняется в переменной LibHandle.

LibHandle := LoadLibrary('SortLib.dll'); if LibHandle <> 0 then begin ... end

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

@BubleSort := GetProcAddress(LibHandle, 'BubleSortIntegers'); @QuickSort := GetProcAddress(LibHandle, 'QuickSortIntegers');

Обратите внимание на использование символа @ перед именем каждой переменной. Он говорит о том, что выполняется не вызов подпрограммы, а работа с ее адресом.

Если этот адрес отличен от значения nil, значит, подпрограмма с указанным именем была найдена в библиотеке и ее можно вызвать путем обращения к процедурной переменной:

if (@BubleSort <> nil) and (@QuickSort <> nil) then begin ... BubleSort(Arr); ... QuickSort(Arr); ... end

По окончании сортировки программа выгружает библиотеку вызовом функции FreeLibrary.

Как вы убедились, динамический импорт в сравнении со статическим требует значительно больше усилий на программирование, но он имеет ряд преимуществ:

  • Более эффективное использование ресурсов оперативной памяти по той причине, что библиотеку можно загружать и выгружать по мере надобности;
  • Более гибкая обработка ошибок. Динамический импорт помогает в тех случаях, когда некоторые процедуры и функции могут отсутствовать в библиотеке. При статическом импорте такие ситуации обрабатывает операционная система, которая выдает сообщение об ошибке и прекращает работу программы. Однако при динамическом импорте программа сама решает, что ей делать, поэтому она может отключить часть своих возможностей и работать дальше.

Динамический импорт отлично подходит для работы с библиотеками драйверов устройств. Он, например, используется самой средой Delphi для работы с драйверами баз данных.








Дата добавления: 2016-02-09; просмотров: 499;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.009 сек.