DLL библиотеки


Зміст

 

Вступ

Різні програми багатовіконного середовища часто виконують однакові дії, наприклад, хрестик в правому верхньому куті вікна, який закриває його, малюється більшістю програм однаково. Марнотратно було б, щоб кожна із цих програм мала відповідну функцію — це роздувало б їхні розміри. Тому, розумно, щоб такі функції поступали в спільне користування. Для цього служать бібліотеки з динамічним зв'язуванням. Відповідні функції завантажуються в пам'ять комп'ютера не з файлу програми, а із спеціального файлу, вже при виконанні. Насправді, операційна система не завантажує їх повторно. Якщо програма при запуску вимагає завантаження динамічної бібліотеки, то операційна система перевіряє, чи така бібліотека вже є в пам'яті. Якщо вона є, то операційна система збільшує лічильник клієнтів для динамічної бібліотеки на одиницю. При завершенні роботи, програма повідомляє операційну систему про необхідність вивантажити динамічну бібліотеку. При цьому операційна система зменшує лічильник клієнтів на одиницю. Якщо після такого зменшення кількість клієнтів стає рівною нулю, то тоді динамічна бібліотека справді вивантажується із пам'яті комп'ютера.

У Windows, динамічні бібліотеки зберігаються в файлах із розширенням *.DLL. Крім підпрограм там можуть також зберігатися інші ресурси, наприклад, іконки чи BMP файли. В коді програми, що використовує функції з динамічної бібліотеки, завантаження та вивантаження бібліотеки повинні бути прописані безпосередньо. Компілятору не потрібен код функцій, що містяться в динамічних бібліотеках. При запуску програми, вона, все одно, шукатиме відповідну DLL. Якщо така DLL не знайдена на комп'ютері, то програма здебільшого виконуватися не буде, а видасть повідомлення про відсутність динамічної бібліотеки.

Взагалі кажучи, DLL – це набори функцій, зібрані в бібліотеки. 
Однак, на відміну від своїх статичних родичів файлів Lib, бібліотеки 
DLL не приєднані безпосередньо до виконуваних файлів за допомогою редактора зв'язків. У виконуваний файл занесена тільки інформація про їхнє місцезнаходження. У момент виконання програми завантажується вся бібліотека цілком. Завдяки цьому різні процеси можуть користуватися спільно одними і тими ж бібліотеками, знаходяться в пам'яті. Такий підхід дозволяє скоротити обсяг пам'яті, необхідний для декількох додатків, що використовують багато спільних бібліотек, а також контролювати розміри ЕХЕ-файлів.

Однак, якщо бібліотека використовується тільки одним додатком, краще зробити її звичайною, статичною. Звичайно, якщо входять до її складу функції, що будуть використовуватися тільки в одній програмі, то можна вставити в неї відповідний файл з вихідним текстом.

Найчастіше проект підключається  до DLL статично, або неявно, на етапі компонування. Завантаженням DLL при виконанні програми управляє операційна система. Однак, DLL можна завантажити і явно, або динамічно, в ході роботи додатку.

Мета дипломної роботи розробити самостійно декілька власних DLL бібліотек у середовищі Delphi7, та показати приклади роботи з ними.

 

1.Огляд відомих рішень

Бібліотека динамічного  компонування (DLL) є виконуваним файлом, який виконує функції загальної  бібліотеки. Динамічне компонування представляє спосіб виклику функції, що не є частиною виконуваного коду. Виконуваний код функції розташований в бібліотеці DLL, яка містить кілька компільованих, пов'язаних і окремо збережених функцій у використовуваних процесах. Бібліотеки DLL часто спрощують процес загального доступу до даних і джерел. Численні програми можуть мати одночасний доступ до декількох змістів однієї копії DLL в пам'яті.

Динамічна компоновка відрізняється  від статичного компонування тим, що дозволяє виконуваним модулям (таким як файл. Dll або. Exe) включати тільки необхідну інформацію в середовище виконання і розміщувати виконуваний код у функції DLL. У статичному компонуванні компонувальник отримує всі зазначені функції з бібліотеки і розміщує код в виконуваному середовищі. [1]

Динамічна компоновка має  деякі переваги над статичною. Бібліотеки DLL зберігаються в пам'яті, зменшують  кількість обмінів, займають невеликий об'єм місця на диску, спрощують процес оновлення, надають вторинну підтримку, а також забезпечують механізмом для розширення класів бібліотеки MFC, підтримують багатомовні програми і спрощують створення міжнародних версій.

Незважаючи на те, що бібліотеки DLL і програми є виконуваними програмними модулями, між ними існує ряд відмінностей. Для кінцевого користувача найбільш очевидною відмінністю є те, що бібліотеки DLL не є програмами і не можуть виконуватися безпосередньо. З точки зору системи існує два фундаментальних відмінності між програмами та бібліотеками DLL:

  • В системі може виконуватися кілька екземплярів програми одночасно, в той час як бібліотека DLL може виконуватися тільки в одному екземплярі.
  • У програмі може бути стек, глобальна пам'ять, дескриптори файлів і черга повідомлень - всього цього не може бути в бібліотеці DLL.

Динамічна компоновка має такі переваги:

  • Економія пам'яті і зменшення обсягу вивантаження. Багато процесів використовують одночасно одну бібліотеку DLL - при цьому в пам'яті зберігається тільки один її примірник для всіх процесів. Для кожної програми, побудованого за допомогою статично компонованої бібліотеки, Windows, навпаки, повинна завантажити копію коду бібліотеки в пам'ять.
  • Економія місця на диску. Багато додатків спільно використовують одну копію бібліотеки DLL на диску. У кожній програмі, побудованому на основі статично компонованої бібліотеки, код бібліотеки, навпаки, компонується у виконуваний образ у вигляді окремої копії.
  • Оновлення бібліотек DLL простіше і зручніше. При зміні функцій в бібліотеці DLL не потрібно перекомпіляція або перекомпонування додатків, що використовують ці бібліотеки, якщо аргументи функцій і повертаються значення залишилися колишніми. Навпаки, при використанні статичної компоновки об'єктного коду потрібно перекомпонування додатка у разі зміни функцій.
  • Забезпечується після продажна підтримка. Наприклад, в бібліотеку DLL для драйвера монітора можна внести зміни для підтримки монітора іншого типу, якого ще не існувало на момент поставки програми.
  • Підтримка багатомовних програм. Програми, написані на різних мовах програмування, можуть викликати ту ж саму функцію бібліотеки DLL, якщо в цих програмах дотримуються єдині угоди за викликами функцій. Між програмою і функцією бібліотеки DLL повинна бути забезпечена сумісність за наступними напрямками: визначити послідовність передачі аргументів функції в стек, а також визначити, яка частина відповідає за очищення стека - функція або додаток, а також які аргументи передаються в регістри.
  • Механізм розширення класів бібліотеки MFC. На основі існуючих класів MFC можна створювати похідні класи і розміщати їх в бібліотеку DLL розширення MFC для використання в додатках MFC.
  • Полегшення створення міжнародних версій додатків. Створення міжнародних версій додатків набагато спрощується, якщо рядкові ресурси помістити в бібліотеку DLL. Можна розмістити рядкові ресурси кожної мовної версії вашого застосування в окрему бібліотеку ресурсів, щоб різні мовні версії завантажували відповідні ресурси.

Потенційний недолік  використання бібліотек DLL полягає  в тому, що програма не є самодостатньою: її виконання визначається наявністю того чи іншого бібліотечного модуля DLL.

Відмінна від MFC бібліотека DLL - це бібліотека DLL, яка внутрішньо не використовує MFC, а експортовані функції в бібліотеці DLL можуть бути викликані виконуваними файлами  як MFC, так і не MFC.

Звичайна бібліотека DLL, статично компонована з MFC, - це бібліотека DLL, усередині якої використовується MFC, а експортовані функції цієї бібліотеки можуть викликатися виконуваними модулями, які можуть використовувати або не використовувати MFC. Як випливає з назви, цей тип бібліотек DLL будується за допомогою статично компонованої версії бібліотеки MFC.

Звичайна бібліотека DLL, статично компонована з MFC, має  такі можливості:

  • Клієнтський виконуваний модуль може бути створений будь-якою мовою, що підтримує використання бібліотек DLL (C, C + +, Pascal, Delphi і т. д.), і він не зобов'язаний бути додатком MFC.
  • Бібліотека DLL може компонуватися з тими ж статичними бібліотеками MFC, що і додатки. Більше не існує окремої версії статично компонованих бібліотек, призначених спеціально для бібліотек DLL.

Вся виділена бібліотекою DLL пам'ять повинна використовуватися  тільки усередині цієї DLL. Бібліотека DLL не повинна передавати або отримувати з викликуваного виконуваного модуля наступні об'єкти:

  • вказівники на об'єкти MFC;
  • вказівники на пам'ять, виділену MFC.

Якщо необхідно зробити  що-небудь з перерахованого вище або  передавати об'єкти класів, похідних від класів MFC, між викликаючим виконуваним модулем і бібліотекою DLL, то слід побудувати бібліотеку розширення.

Передавати вказівники пам'яті, виділеної бібліотеками часу виконання мови Delphi, між додатком і бібліотекою DLL безпечно тільки в тому випадку, якщо виконується копіювання даних. Не можна видаляти або змінювати розміри цих вказівників, або ж використовувати їх без копіювання пам'яті.

Бібліотеку DLL, статично скомпоновану з MFC, не можна динамічно  пов'язувати з загальними бібліотеками DLL MFC. Статично пов'язана з MFC бібліотека є, як і будь-які інші DLL, динамічно  пов'язаної з додатком; додаток зв'язується з нею так само, як і з будь-якої іншої DLL.

Звичайна бібліотека DLL, динамічно зв’язуюча з MFC - це бібліотека DLL, внутрішньо використовуюча MFC. Експортовані функції цієї бібліотеки можуть викликатися виконуваними програми MFC та іншими додатками. Як зрозуміло з назви, цей вид бібліотек DLL побудований з використанням версії бібліотеки динамічної компоновки MFC (також званої загальної версією MFC).

Звичайна бібліотека DLL, динамічно зв'язуюча з MFC, володіє  наступними можливостями:

  • Клієнтський виконуваний модуль може бути створений будь-якою мовою, що підтримує використання бібліотек DLL (C, C + +, Pascal, Delphi і т. д.), і він не зобов'язаний бути додатком MFC.
  • На відміну від статично зв'язуваних звичайних DLL, цей вид бібліотек DLL динамічно зв'язується з DLL-бібліотекою MFC
  • З цим типом бібліотеки DLL пов'язана та ж бібліотека імпорту MFC, яка використовується для DLL-бібліотек розширення або додатків, що використовують DLL-бібліотеки MFC.

Побудова бібліотек DLL розширення виконується за допомогою  бібліотеки динамічної компоновки версії. Тільки виконувані файли MFC, які створюються із загальною версією MFC, можуть використовувати бібліотеку DLL розширення. За допомогою бібліотеки DLL розширення можна створити нові користувальницькі класи на основі MFC і потім застосовувати цю розширену версію MFC в додатках, які викликають бібліотеку DLL.

Бібліотеки DLL розширення можуть також використовуватися  для передачі об'єктів, похідних від MFC, між додатком і бібліотекою DLL. Функції-члени, асоційовані з переданим об'єктом, знаходяться в модулі, в якому об'єкт був створений. Оскільки ці функції відповідним чином експортуються при використанні загальнодоступної версії бібліотеки DLL MFC, можлива вільна передача вказівників на об'єкти MFC або вказівників на об'єкти, похідні від MFC, між додатком і бібліотеками програм, які його завантажують.

Отже, за допомогою  динамічно завантажуваних бібліотек  можна оптимізувати ресурси, необхідні  для виконання додатків; використовувати  в проектах модулі, написані на різних мовах програмування; створювати проекти, які можуть мати необов'язкові функції і пункти меню. Виклик методів з DLL не представляє труднощів, за винятком того, що слід звертати особливу увагу на виняткові ситуації: не допускати попадання примірника - нащадка Exception в головний модуль, обов'язково викликати команду FreeLibrary при наявності виключень.

 

2. Вибір метода рішення

2.1 Постановка  задачі

Розробити власні DLL бібліотеки в середовищі Delphi7 для покращення якості коду та відповідно збільшення продуктивності програмного продукту

Для розробки були обрані наступні напрями:

  • Підрахунок хеш суми MD5;
  • Пошук функцій в DLL бібліотеках;
  • Підтримка процесором різних технологій ;
  • Числа прописом;
  • Скріншот екрана;
  • Шифрування й дешифрування текстів за принципом S-Coder з прихованим ключем;

2.2 Обраний метод

Створення простої DLL

library Project1;

 

uses

  SysUtils,

  Classes;

 

{$R *.res}

 

begin

end.




До складу Delphi входить  експерт для створення DLL, який викликається при виборі команди File/New і піктограми DLL на сторінці New репозитарія об'єктів. При цьому виникає заготовка для реалізації DLL:

 

У наведеному вище коді відсутній  текстовий коментар, який генерується експертом. Заготовка відрізняється від заготовки для створення коду *.exe-файлу тим, що використовується службове слово Library замість Program. Крім того, відсутні звернення до методів об'єкта TApplication (хоча примірник цього об'єкта в дійсності створюється в DLL!), А також модуль реалізації головної форми. Створимо в даній заготовці метод, який буде симулювати виконання будь-яких обчислень:

function AddOne(N:integer):integer; stdcall; export; 

begin 

  Result:=N+1; 

end; 




Як видно, код реалізації методу AddOne включає два оператори, які зазвичай не використовуються в реалізації методів при створенні програми, - stdcall і export. Директива stdcall пов'язана з угодами виклику методів. Розглянемо їх тут докладніше.

Коли в додатку здійснюється виклик методу, його параметри (як і  локальні змінні) поміщаються в стек. Стек, який представляє собою зарезервоване місце в ОЗУ комп'ютера, має показник поточної позиції, який при старті програми встановлюється на початок стека. При виклику методу в стек поміщаються всі локальні змінні і параметри методу, при цьому показник поточної позиції стека зміщується вправо відповідно до розміру вносимих в нього даних. Якщо метод, в свою чергу, викликає інший метод, то локальні змінні другого методу додаються в стек, так само як і список параметрів. Після закінчення роботи другого методу відбувається звільнення області пам'яті в стеку - для цього показник поточної позиції стека зміщується вліво. І нарешті, після закінчення роботи першого методу показник поточної позиції стека зміщується в початкове положення.

Ясно, що якщо додаток  працює нормально, то після закінчення виконання ланцюжка методів показник поточної позиції стека повинен повернутися в первісний стан, тобто створений стек повинен бути очищений. Якщо ж вказівник не повертається, то відбувається крах стека - цей термін не слід плутати з очищенням стека. У цьому випадку додаток припиняє свою роботу (ніякі пастки винятків не допомагають) і, якщо воно виконується під Windows 95 або Windows 98, найчастіше потрібне перезавантаження операційної системи. Зрозуміло, що повернення показника стека в первинний стан повинен відбуватися після закінчення роботи методу. Але при цьому існують дві можливості - повернення вказівника на місце може робити як викликуваний метод по закінченні роботи, так і викликаючий метод після завершення роботи викликуваного методу. В принципі, в різних мовах програмування реалізуються обидві зазначені можливості - очищати стек можуть і викликаний, і викликаючий методи. Оскільки модуль пишеться на одній мові програмування, то ці проблеми приховані від програміста: очищення стека проводиться по специфічному для даної мови протоколу. Але якщо використовуються різні модулі, код для яких реалізований на різних мовах програмування, то виникають проблеми. Наприклад, в C + + стек очищається в методі, який викликав другий метод, після закінчення його роботи. В Delphi стек очищається в тому ж самому методі, де він використовується, перед закінченням його роботи. Якщо *.exe-модуль, створений на мові C + +, викликає метод з DLL, створений на Delphi, то перед закінченням роботи методу в DLL стек буде очищено. Після цього управління передається модулю, реалізованому на C + +, який також спробує очистити стек, - така дія призведе до краху стека.

Крім цих можливостей, існує й інший спосіб, а саме: послідовність занесення в стек параметрів методу. Припустимо, є метод, який використовує для роботи два параметри:

procedure DoSomething(N:integer; D:TDateTime);


Зазначений спосіб полягає  в тому, що спочатку в стек може бути поміщена константа N, а потім D (зліва направо) або спочатку поміщається константа D, а потім N (справа наліво). Крім того, деякі мови програмування (зокрема, Delphi) частину параметрів методу взагалі не поміщають в стек, а передають їх через регістри процесора. До того ж у різних мовах програмування параметри можуть міститися в стек як зліва направо, так і справа наліво. Якщо вони були поміщені зліва направо, а викликуваний метод буде читати справа наліво, то вийде плутанина: як значення константи N викликуваний метод буде вважати значення правої половини константи D, а константу D він буде формувати з константи N і лівої половини D.

З цієї причини в будь-якій мові програмування передбачена можливість оголосити, який з методів - викликуваний або викликаючий,  буде очищати стек і в якій послідовності параметри методу поміщаються в стек. Таке оголошення називається угодою виклику (calling conversion); є ряд зарезервованих слів, які поміщаються після заголовка методів, як показано в таблиці.

Директива

Порядок слідування параметрів

Очистка стека

Використанна регістрів 

register

Зліва направо

викликуваний метод

+

pascal

Зліва направо

викликуваний метод

-

cdecl

Зліва направо

викликуваний метод

-

stdcall

Зліва направо

викликуваний метод

-

safecall

Зліва направо

викликуваний метод

-


 

Для методів, що експонуються в DLL, рекомендується (але не обов'язково) використовувати угоду виклику, що і в Windows API. Для 32-розрядних додатків Windows API методи реалізовані таким чином, що параметри поміщаються в стек справа наліво і стек очищає викликуваний метод; при цьому не використовуються регістри процесора для передачі даних. Цим умовам задовольняє директива stdcall, яка в описаному вище прикладі поміщається після заголовка методу AddOne. Якщо після заголовка методу відсутня угода про виклик, то за замовчуванням Delphi використовує угоду register.

Однак написаного вище коду ще недостатньо для виклику методу AddOne з іншого модуля. Одна DLL може надавати декілька методів зовнішньому модулю. Для того щоб зовнішній модуль міг вибрати конкретний метод, в DLL повинна бути присутня спеціальна секція, яка має заголовок exports. У нашому прикладі цю секцію можна оголосити таким чином:

exports

  AddOne index 1 name ’CalculateSum’;


 

Для експонування методу в секції exports наводиться його назва (AddOne), після якого слідує або службове слово index з цілочисловим ідентифікатором після нього (ідентифікатор повинен бути більше нуля), або службове слово name з текстовим ідентифікатором, або обидва разом - як в даному випадку . Зовнішній модуль може звертатися до конкретного методу як за індексом, так і по імені.

Статичне  і динамічне завантаження DLL

Модуль може викликати методи іншого модуля, а той, у свою чергу, - наступного і т.д. Наприклад, додаток викликає DLL, а ця DLL викликає методи інший DLL: так можна формувати довгі ланцюжки викликів. Для виклику методу з іншого модуля необхідно спочатку завантажити його в пам'ять, а потім визначити адресу методу. Існує два способи завантаження і визначення адреси методу - статичний і динамічний.

Function Add1(K:integer):integer; stdcall; external 'Project1.DLL' name 'CalculateSum';




 При статичному  завантаженні для виклику іншого модуля слід в якійсь із секцій описати метод з DLL наступним чином:

або

function Add1(K:integer):integer; stdcall; external 'Project1.DLL' index 1; 




Для тестування необхідно  описати в додатку зовнішній  метод одним з вищезазначених способів і зробити, наприклад, обробник події OnClick кнопки, поставленої на форму разом з компонентом TEdit:

procedure TForm1.Button1Click(Sender: TObject);

var 

  N:integer; 

begin 

  N:=StrToInt(Edit1.Text); 

  N:=Add1(N); 

  Edit1.Text:=IntToStr(N); 

end; 


При натисканні кнопки буде викликатися метод з DLL. Зверніть увагу на зміну імен методу: з  обробника події OnClick викликається метод з ім'ям Add1. Цей метод  експонується в DLL під ім'ям CalculateSum. У реалізації DLL він має назву AddOne.

При такому визначенні методу DLL буде завантажена негайно після старту програми та вивантажено разом з його завершенням. У наведеному вище прикладі слід звернути увагу на те, що після імені динамічної бібліотеки зазначено її розширення (Project1.dll). Така конструкція необхідна для завантаження бібліотеки в Windows NT, оскільки без розширення *. Dll файл не буде знайдено.

При пошуку DLL для завантаження спочатку визначається, чи була дана DLL вже завантажена в пам'ять іншим модулем. Якщо була - то витягується адреса методу і передається з додатком. Якщо ж ні - то операційна система починає її пошук на диску. При цьому, якщо шлях при імені DLL не вказаний в явному вигляді, система шукає бібліотеку в каталозі модуля, який намагається завантажити DLL. Якщо не знаходить, то продовжує пошуки в директоріях WINDOWS і WINDOWS \ SYSTEM (або WINNT, WINNT \ SYSTEM, WINNT \ SYSTEM32). Після цього відбувається пошук в каталогах, визначених у змінній середовища Path. Якщо бібліотека з заданим ім'ям буде знайдена, то вона завантажиться і додаток стартує. Якщо ж ні - відбувається виключення і додаток припинить свою роботу. Додаток припиняє роботу також і в тому випадку, якщо не буде знайдений метод з даними ім'ям (або індексом, якщо він імпортується за індексом).

Динамічне завантаження DLL дозволяє завантажувати бібліотеку тільки в той момент, коли вона потрібна. Крім того, якщо не буде знайдена бібліотека або метод, то це можна проаналізувати і запустити додаток і в цьому випадку. Звичайно, в такій ситуації слід інформувати користувача про неможливість викликати метод з DLL - наприклад, зробивши невидимим пункту меню, який звертається до даного методу. Приклад динамічного завантаження DLL виглядає наступним чином:

type

  TAddFunction=function(K:integer):integer; stdcall; 

  

procedure TForm1.Button2Click(Sender: TObject); 

var 

  Add1:TAddFunction; 

  HLib:THandle; 

  N:integer; 

begin 

  HLib:=0; 

  try 

    HLib:=LoadLibrary('Project1.dll'); 

    if HLib>HINSTANCE_ERROR then begin 

      Add1:=GetProcAddress(HLib,'CalculateSum'); 

      if Assigned(Add1) then begin 

        N:=StrToInt(Edit1.Text); 

        N:=Add1(N); 

        Edit1.Text:=IntToStr(N); 

      end else ShowMessage('Метод з ім’ям CalculateSum не знайдений'); 

    end else ShowMessage('Не знайдена бібліотека Project1.dll'); 

  finally 

    if HLib>HINSTANCE_ERROR then FreeLibrary(HLib); 

  end; 

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, якщо відбувається виключення.

Метод GetProcAddress для завантаження DLL може також використовувати індекси. Для прикладу, представленого вище, в якому метод AddOne експонується з індексом 1, використання індексів в GetProcAddress виглядає наступним чином:

Add1:=GetProcAddress(HLib,pchar(1));


При завантаженні DLL здійснюється резервування пам'яті, необхідної для  збереження коду методів. Крім того, резервується місце для всіх глобальних змінних і виконуються секції ініціалізації в модулях DLL. Якщо інший процес також намагається завантажити DLL, то знову відбувається резервування пам'яті для зберігання глобальних змінних. Проте копіювання методів DLL не здійснюється; також не виконується і секція ініціалізації. Іншими словами, одна копія методу в ОЗУ обслуговує кілька додатків. Глобальні змінні є унікальними для кожного додатку, і якщо один додаток змінить їх значення за допомогою виклику якогось методу, то інший додаток цього не помітить. Оскільки секція ініціалізації виконується тільки при першому завантаженні DLL, її не можна використовувати для установки початкових значень глобальних змінних.

Розглянемо переваги використання DLL:

  1. Методи, описані в DLL, можуть одночасно обслуговувати кілька додатків. При цьому самі методи зберігаються у вигляді однієї копії в ОЗУ. Якщо викликається код досить великий і є кілька додатків, які викликають даний код, то внаслідок цього можна досягти суттєвої економії системних ресурсів.
  2. Можливість зберігання загальних ресурсів. Якщо кілька додатків працюють з одними і тими ж ресурсами (наприклад, великі растрові картинки - *.Bmp), то при збереженні їх у DLL можна мати ці ресурси в одному екземплярі.
  3. Підтримка нових версій додатків. Якщо програміст зробив будь-які зміни в реалізаціях методів, визначених у DLL, то кінцевому споживачеві достатньо передати нову версію DLL, і *. Exe-файл можна зберегти незмінним. Це особливо актуально зараз, коли програми можна оновлювати за допомогою Internet. У цьому випадку важливо знизити кількість інформації, що посилається по мережі. Природно, що якщо частина коду реалізована в DLL, то при завантаженні з сервера тільки цієї DLL трафік, пов'язаний з оновленням версії програми, буде зменшений.
  4. Можливо використовувати різні мови програмування для створення *.Exe і *.DLL. Наприклад, *. Exe-файл може компілюватися з коду, написаного на Delphi, а *.DLL, яка їм використовується, компілюється з коду, написаного на Microsoft Visual C + +. Якщо програма використовує кілька DLL, то вони можуть бути створені на різних мовах програмування. Це значно спрощує перенесення коду в інші додатки.
  5. DLL можна завантажувати в пам'ять тільки тоді, коли вони потрібні для виконання програм, реалізуючи тим самим динамічне завантаження. При цьому знову ж досягається економія системних ресурсів. Так, наприклад, в DLL можна реалізувати діалог, за допомогою якого змінюються які небудь параметри програми. Користувач може місяцями не звертатися до даного діалогу, і при цьому DLL, в якій він реалізований, не завантажується в пам'ять і не споживає системних ресурсів. Тільки в момент, коли користувач звертається до цього діалогу, відбувається завантаження DLL в пам'ять, але після виконання діалогу ця пам'ять звільняється. Використовуючи динамічне завантаження, можна оформити динамічний призначений для користувача інтерфейс: відповідні опції меню програми з'являються в тому випадку, якщо знайдена дана DLL, і зникають при її відсутності. Такий інтерфейс зручний при поставці додатків, в яких користувач може замовити додаткові можливості за окрему плату.[1]

 

3. Реалізація

DLL библиотеки