TURBO PASCAL |
Новости
|
9.5.1. Создание DLLДля создания DLL в ВР введено зарезервированное слово Library, которым должен начинаться текст библиотеки. За словом Library следует правильный идентификатор, но в отличие от объявления модуля он не обязан совпадать с именем файла: имя DLL определяется именем DLL-файла, а не идентификатором, следующим за Library. Структура текста DLL повторяет структуру обычной программы с тем исключением, что раздел исполняемых операторов в DLL играет ту же роль, что и установочная часть модуля: операторы этой части исполняются только один раз в момент загрузки библиотеки в память. Каждое очередное обращение с требованием загрузить библиотеку наращивает на единицу ее счетчик ссылок, но не приводит к выполнению операторов исполняемой части. Сразу за заголовком экспортируемой подпрограммы должно следовать зарезервированное слово Export, которое заставит компилятор выработать специальный код пролога/эпилога. DLL имеют сегменты кода и данных, но у них нет сегмента стека. Специальный пролог/эпилог позволяет DLL— подпрограмме использовать сегмент стека вызвавшей ее программы. В разделе описаний DLL могут объявляться типы (в том числе и объекты), константы и переменные, но они остаются скрытыми от вызывающей программы и могут использоваться только внутри DLL. В разделе описаний помимо стандартных для обычной программы объявлений используется специальный раздел объявления экспортируемых подпрограмм. Этот раздел начинается зарезервированным словом Exports, за которым через запятую перечисляются имена экспортируемых подпрограмм, например: Library MyLibrary; Function MyFunc(...):...; Export; begin end; Procedure MyProc; Export; begin end; Exports MyFunc, MyProc; begin end. Раздел Exports помогает компилятору и компоновщику создать специальный заголовок DLL— модуля, в котором перечисляются имена подпрограмм и адреса их точек входа. В DLL может быть несколько списков Exports, но перечисляемые в них подпрограммы должны быть описаны где — то выше по тексту библиотеки. Помимо имени подпрограммы в заголовок DLL помещается также ее порядковый номер, точнее присвоенный ей целочисленный индекс. Это позволяет вызывающей программе ссылаться не на имя, а на индекс подпрограммы и тем самым уменьшить затраты времени на установление с ней связи. Индекс присваивается подпрограмме по порядку ее появления в списках Exports', первая подпрограмма в первом списке получает индекс 1, следующая — 2 и т.д. Программист может изменить умалчиваемую индексацию и явно указать индекс подпрограммы, добавив за ее именем в списке Exports слово index та. целое число без знака в диапазоне от 1 до 32767: Expots MyFunc index 1, MyProc index 2; Во избежание возможной путаницы с индексацией советую явно задавать индексы всем экспортируемым подпрограммам1. Программист может определить внешнее имя экспортируемой подпрограммы отличным от ее настоящего имени. Для этого в списке Exports добавляется слово name и внешнее имя в апострофах: Exports MyFunc index 1 name 'NEWFUNC'; Обратите внимание: указываемое в апострофах внешнее имя должно состоять из заглавных букв. Если в приведенном выше примере задать ' NewFunc', вызывающая программа не сможет найти функцию MyFunc ни по имени, ни по индексу! По умолчанию ВР создает внешнее имя совпадающим с настоящим, но преобразует его буквы к заглавным. Вызывающая программа может ссылаться или на имя экспортируемой подпрограммы, или на ее индекс. При вызове по имени программа про— 1 Мною замечено, что ВР начинает умалчиваемую индексацию не с 1, а с 2, что может существенно повлиять на использование DLL. Более того, даже если первой подпрограмме явно присвоить индекс 1, следующая за ней подпрограмма получит умалчивоемый индекс 3, d не 2. сматривает имена в таблице имен в поисках нужного. Так как имена могут состоять из длинных наборов символов и самих имен в таблице может быть много, процесс поиска имени существенно медленнее, чем процесс поиска индекса. Поэтому опытные программисты предпочитают ссылаться не на имя, а на индекс подпрограммы. Тем не менее, нельзя исключить возможность того, что программа будет вызывать DLL—подпрограмму по имени^ В этом случае затраты времени на поиск можно заметно сократить, если указать в списке Exports слово resident: Exports MyFunc index 1 name 'NEWFUNC' resident; Информация о подпрограмме, экспортируемой с признаком resident, сохраняется в памяти во все время использования библиотеки. Замечу, что в отличие от модулей ВР не компилирует DLL автоматически в режимах MAKE или BUILD, т.к. справедливо рассматривает ее как другую программу, никак не связанную в момент компиляции с основной программой. В заключение рассмотрим реальный пример создания DLL, в котором иллюстрируются различные приемы объявления экспортируемых подпрограмм. Для примера я выбрал модуль Cmplx, описанный в п.9.7. В его состав входят 4 процедуры, реализующие действия с комплексными числами. Вариант соответствующей DLL показан ниже. {$N+,E+} {Используем сопроцессор для типа Single} Library Complex; type TComplex = record Re, Im: Single end; Procedure CmplxAdd(x, y: TComplex; var z: TComplex); Export; begin z.Irn := x.Im + y.Im; z . Re : = x. Re + у. Re end; Procedure CmplxSub(x, y: TComplex; var z: TComplex); Export; begin z.Im := x.Im - y.Im; z. Re : = x. Re - у. Re end; Procedure CmplxMul(x, y: TComplex; var z: TComplex); Export; begin z.Re := x.Re * y.Re + x.Im * y.Im; z.Im := x.Re * y.Im - x.Im * y.Re end; Программирование для защищенного режима 235 Procedure CmplxDiv(x, у: TComplex; var z: TComplex); Export; var zz: Single; begin zz := sqr(y.Re) + sqr(y.Im); z.Re := (x.Re * y.Re + x.Im * y.Im)/zz; z.Im := (x.Re * y.Im - x.Im * y.Re)/zz end; Exports CmplxAdd index 1 name 'ADD' resident, CmplxSub index 2, CmplxMul index 3, CmplxDiv index 4; begin end. |
(с)Все права защищены По всем интересующим вопросам прошу писать на электронный адрес |