«Очень важно не прерывать вопросов. Любопытство имеет свое право на существование»
36. Разработка собственных библиотек
Структура файла библиотеки идентична структуре файла проекта, только вместо слова program используется library. Создание библиотеки (в Delphi 5) удобно выполнить с помощью темы меню File/New/New/DLL. Пример собственной библиотеки (см. проект MyDll.dpr):
Library MyDll;
uses …;
Function Min ( X, Y: Integer) : Integer;
Begin
if X < Y then Min := X else Min := Y;
End;
Function Max(X, Y: Integer) : Integer;
Begin
if X > Y then Max := X else Max := Y;
End;
exports
Min index 1,
Max index 2;
BEGIN
{секция инициализации}
END.
Если предполагается использование библиотеки из программ, написанных на другом языке, необходимо добавить директиву stdcall в объявления экспортируемыхподпрограмм, так как другой язык может не поддерживать соглашение register по вызову подпрограмм.
Библиотека может состоять из нескольких модулей. В этом случае библиотечный файл (начинающийся со слова library) часто включает только предложения uses, exports и код инициализации. Например:
library Editors;
uses EdInit, EdInOut, EdFormat, EdPrint;
exports
InitEditors index 1,
…
SetErrorHandler index 53;
begin
InitLibrary;
end.
Библиотека экспортирует только те подпрограммы, которые объявлены в объявлении exports.
Предложение exports. Подпрограмма экспортируется библиотекой (или программой), если она указана в предложении exports. Это предложение имеет такой формат:
exports
routine_1, routine_2, …, routine_n;
Каждая экспортируемая подпрограмма описывается по формату:
имя_подпрограммы (список_параметров) index номер name 'внешнее_имя'
Здесь все элементы описания, за исключением имя_подпрограммы, являются необязательными. Имя_подпрограммы – это идентификатор описанной выше (или в другом модуле) процедуры или функции, причем он может быть уточнен именем модуля. Список_параметров указывается в случае экспорта перегруженных функций, например:
exports
Divide(X, Y: Integer) name 'Divide_Ints',
Divide(X, Y: Real) name 'Divide_Reals';
Элемент описания index, сопровождаемый целочисленной константой 1..2147483647, используется только для обратной совместимости. Если он не указан, подпрограмме назначается индекс в соответствии с местоположением ее описания в предложении exports.
Слово name, сопровождаемое строковой константой, используется для экспорта подпрограммы под другим (не оригинальным) именем. Если имя опущено, то подпрограмма экспортируется под своим оригинальным именем (с учетом орфографии и регистра).
Предложение exports может встречаться в любом месте программы, где допустимо делать описания, и любое число раз. Главная программа редко содержит это предложение, так как Windows не разрешает приложениям экспортировать подпрограммы.
Код инициализации библиотеки. Операторы, указанные в секции инициализации библиотеки, выполняются один раз при ее загрузке. Обычно в этой секции выполняется инициализация переменных и регистрация оконных классов. Также в этой секции может быть установлена процедура выхода с использованием переменной ExitProc. Эта процедура выполняется при выгрузке библиотеки.
Также в секции инициализации можно присвоить переменной ExitCode ненулевое значение в том случае, если корректная работа подпрограмм библиотеки по какой-либо причине невозможна. В такой ситуации библиотека автоматически выгружается и приложение, вызвавшее ее загрузку, уведомляется об этом. Аналогичным образом, если в процессе выполнения секции инициализации возникает исключительная ситуация, библиотека не загружается и сответствующее приложение получает уведомление об этом. Пример библиотеки с секцией инициализации:
Library Test;
var
SaveExit : pointer;
Procedure LibExit;
Begin
// операторы функции
ExitProc := SaveExit; { восстановление цепочки для вызова стандартной
процедуры выхода}
End;
…
BEGIN
// код инициализации библиотеки
SaveExit := ExitProc; // запоминаем адрес стандартной процедуры
ExitProc := @LibExit; // устанавливаем свою процедуру выхода
END.
Когда библиотека выгружается, ее процедура выхода вызывается до тех пор, пока адрес, хранящийся в указателе ExitProc, не станет равным nil. Секции инициализации модулей, подключенных к библиотеке, выполняются до секции инициализации библиотеки, а секции finalization – выполняются после выполнения процедуры выхода из библиотеки.
Исключительные ситуации и DLL.
Когда в библиотеке возникает ИС, но не обрабатывается в ней, она передается вызывающему процессу. Если этот процесс написан на Object Pascal, ИС может быть обработана с помощью операторов try...except.
Менеджер разделяемой памяти(shared-memory manager).
Если библиотека экспортирует подпрограммы, параметрами которых или возвращаемыми результатами являются длинные строки, то библиотека и использующее ее приложение должны использовать модуль ShareMem. Сказанное относится и к тому случаю, когда приложение или библиотека распределяют память с помощью процедур New или GetMem, а освобождение памяти (с помощью Dispose или FreeMem) выполняется в другом модуле.
Модуль ShareMem всегда должен быть первым в списке подключаемых модулей во всех модулях библиотеки и приложения. Модуль ShareMem является интерфейсом для библиотеки BorlandMM.dll, которая предоставляет модулям возможность совместно использовать динамически распределяемую память. Вследствие этого библиотека BorlandMM.dll должна распространяться вместе со всеми такими приложениями.
«35. Динамически подключаемые библиотеки»
37. Платформы семейства Windows