Разработка программы для автоматизации работы кардиоцентра
Курсовой проект - Компьютеры, программирование
Другие курсовые по предмету Компьютеры, программирование
ториях WINDOWS и WINDOWS\SYSTEM (или WINNT, WINNT\SYSTEM, WINNT\SYSTEM32). После этого происходит поиск в каталогах, определенных в переменной среды Path. Если библиотека с заданным именем будет найдена, то она загрузится и приложение стартует. Если же нет - происходит исключение и приложение прекратит свою работу. Приложение прекращает работу также и в том случае, если не будет найден метод с данным именем (или индексом, если он импортируется по индексу).
Динамическая загрузка DLL позволяет загружать библиотеку только в тот момент, когда она требуется. Кроме того, если не будет найдена библиотека или метод, то это можно проанализировать и запустить приложение и в этом случае. Конечно, в такой ситуации следует информировать пользователя о невозможности вызвать метод из DLL - например, сделав невидимым элемент меню, который обращается к данному методу. Пример динамической загрузки DLL выглядит следующим образом:
=function(K:integer):integer; stdcall;
HINSTANCE_ERRORthenbegin:=GetProcAddress(HLib,CalculateSum);Assigned(Add1)thenbegin:=StrToInt(Edit1.Text);:=Add1(N);.Text:=IntToStr(N);elseShowMessage(MethodwithnameCalculateSumwasnotfound);elseShowMessage(CannotloadlibraryFirstLib.dll);HLib>HINSTANCE_ERRORthenFreeLibrary(HLib);">procedure TForm1.Button2Click(Sender: TObject); :TAddFunction; :THandle; :integer; :=0; :=LoadLibrary(FirstLib.dll); HLib>HINSTANCE_ERROR then begin :=GetProcAddress(HLib,CalculateSum); Assigned(Add1) then begin :=StrToInt(Edit1.Text); :=Add1(N); .Text:=IntToStr(N); else ShowMessage(Method with name CalculateSum was not found); else ShowMessage(Can not load library FirstLib.dll); HLib>HINSTANCE_ERROR then FreeLibrary(HLib);
end; ;
Первоначально определяется новый процедурный тип, например TAddFunction, который имеет такой же список параметров и такие же договоренности вызова, что и метод в DLL. Delphi в процессе компиляции приложения никак не может проверить соответствие процедурного типа методу, вызываемом из DLL. Проверка может быть осуществлена только во время выполнения, а при несоответствии формальных параметров или неврно указанной договоренности вызова происходит крах стека, что программист обнаружит очень быстро.
Далее в коде приложения вызывается метод LoadLibrary, который в качестве параметра использует имя библиотеки. После успешной отработки данного метода и загрузки библиотеки в память указатель на загруженную библиотеку помещается в переменную HLib. Если библиотеку не удается найти (или загрузить), то в эту же переменную помещается код ошибки. Чтобы определить, была ли загружена библиотека, переменную HLib следует сравнить с константой HINSTANCE_ERROR, которая определена в модуле Windows. Если библиотека была успешно загружена, то осуществляется попытка найти адрес метода в памяти компьютера при помощи вызова метода GetProcAddress. Указанный метод возвращает адрес того метода, имя которого указано во втором параметре GetProcAddress. Если же метод не был найден, то возвращается nil-адрес.
Соответственно вызов метода Add1 осуществляется только в случае, если он был успешно найден. Затем, поскольку при загрузке библиотеки были заняты системные ресурсы, их необходимо вновь вернуть операционной системе, выгрузив библиотеку из памяти. Для этого вызывается метод FreeLibrary. При загрузке DLL производится подсчет ссылок, а именно: при каждом успешном обращении к методу LoadLibrary в DLL счетчик ссылок увеличивается на единицу, а при каждом вызове метода FreeLibrary счетчик ссылок уменьшается на единицу. Как только счетчик ссылок станет равным нулю, библиотека выгружается из памяти компьютера. Следовательно, каждому успешному вызову LoadLibrary должно соответствовать обращение к FreeLibrary - иначе DLL не выгрузится из памяти компьютера даже после окончания работы приложения. Поэтому данные методы были помещены в защищенный блок try…finally..end; - это гарантирует вызов метода FreeLibrary, если происходит исключение.
Теперь следует рассмотреть, каким образом загружаемая DLL размещается в ОЗУ компьютера. При загрузке DLL осуществляется резервирование памяти, необходимое для хранения кода методов. Кроме того, резервируется место для всех глобальных переменных и выполняются секции инициализации в модулях DLL. Если другой процесс также пытается загрузить DLL, то вновь происходит резервирование памяти для хранения глобальных переменных. Однако копирование методов DLL не осуществляется; также не выполняется и секция инициализации. Другими словами, одна копия метода в ОЗУ обслуживает несколько приложений. Глобальные переменные являются уникальными для каждого приложения, и если одно приложение изменит их значение при помощи вызова какого-нибудь метода, то другое приложение этого не заметит. Поскольку секция инициализации выполняется только при первой загрузке DLL, ее нельзя использовать для установки начальных значений глобальных переменных. Вышесказанное необходимо учитывать при разработке DLL.
Обмен данными с DLL
DLL имеет общее адресное пространство с приложением, из которого вызываются его методы. Из этого следует, что указатель на какой-либо объект в памяти DLL является легальным внутри приложения, и наоборот. Это позволяет передать, например, адрес метода или адрес данных, чего нельзя сделать без использования маршрутизации при взаимодействии двух приложений. Имеется, однако, существенное отличие от передачи данных между двумя методами одного модуля: в различных модулях разными являются и диспетчеры памяти (memory manager). Это означает, что если в каком-то модуле (например, в DLL) был вызван метод GetMem, то освободить системные ресурсы вызовом метода FreeMem можно только в том же самом модуле. Если попытаться вызвать метод FreeMem в приложении (для примера выше), то происходит исключение. Поскольку при создании экземпляров класса также прои?/p>