Delphi world - спільні бібліотеки

Спільні бібліотеки

Спільні бібліотеки (далі DLL - Dynamic Link Library) представляють собою універсальний механізм інтегрування в вашу програму процедур і функцій, написаних іншими програмістами і, в загальному випадку, на інших, ніж Object Pascal, мовами програмування.







DLL реалізуються у вигляді виконуваних модулів, що містять готові до роботи процедури, функції і / або ресурси. З точки зору програміста, є багато спільного між DLL і звичайними для Object Pascal модулями, т. К. В кінцевому рахунку і бібліотеки, і модулі поставляють підпрограми, які позбавляють програміста від написання власного коду. Але є і принципові відмінності. Головним з них є те, що DLL не в змозі поставляти в програму змінні, константи і типи, адже творці DLL можуть використовувати не типізовані мови програмування, наприклад, мова асемблера. В результаті DLL не можуть експортувати в програму такі необхідні сьогодні програмістові класи - для цього використовуються пакети.

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

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

Крім імені підпрограми в заголовок DLL поміщається також її порядковий номер, точніше, присвоєний їй цілочисельний індекс. Це дозволяє викликає програмі посилатися не так на ім'я, а на індекс підпрограми і тим самим зменшити витрати часу на встановлення з нею зв'язку. Індекс присвоюється підпрограмі по порядку її появи в списках Exports: перша підпрограма в першому списку отримує індекс 0, наступна - 1 і т. Д. Програміст може змінити замовчувану індексацію і явно вказати індекс підпрограми, додавши за її ім'ям в списку Exports слово index і ціле число без знака в діапазоні від 0 до 32767:

Програміст може визначити зовнішнє ім'я експортованої підпрограми відмінним від її справжнього імені. Для цього в списку Exports додається слово name і зовнішнє ім'я в апострофа:

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







Зауважу, що на відміну від модулів Delphi НЕ компілює DLL автоматично в режимах make або build, т. К. Справедливо розглядає її як іншу програму, ніяк не пов'язану в момент компіляції з основною програмою.

Зверніть увагу: всі функції нашої DLL використовують угоду stdcall, яке забезпечує сумісність нових функцій з функціями API Windows 32. Ми могли б не вказувати цю угоду; в цьому випадку компілятор використовував би ефективну угоду register, але звернення до нашої DLL з програм, написаних на інших мовах програмування, в загальному випадку стало б неможливим.

Якщо ви створили DLL для "зовнішнього" ісользованія (внеDelphi), оголошуйте підпрограми з директивою stdcall або safecall!

Для використання підпрограм з DLL необхідно описати їх як зовнішні, додавши за словом External ім'я бібліотеки в апострофа:

Як вже говорилося, підпрограма викликається по імені або за індексом. У нашому прикладі з бібліотеки MyDLL викликається підпрограма із зовнішнім ім'ям 'мургос'. Якщо потрібно послатися на індекс підпрограми, за ім'ям бібліотеки вказується слово index і індекс:

У цьому випадку ім'я, під яким підпрограма буде відома програмі, може не збігатися з її зовнішнім DLL-ім'ям. Втім, програміст може і явно перевизначити ім'я підпрограми, навіть якщо він посилається на її зовнішнє ім'я:

У цьому варіанті передбачається, що експортується процедура із зовнішнім ім'ям 'ExtName'.

13.4.1. статична завантаження

У наступній програмі використовується бібліотека Сmpix, описана на попередній сторінці.

Зверніть увагу: бібліотечна функція cmpixAdd має зовнішнє ім'я addc. Саме так (великими літерами) описана ця функція в наведеному вище прикладі. Якби ми використовували

компоновщик не зміг би її ідентифікувати.

13.4.2. динамічне завантаження

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

Стандартних функцій. LoadLibrary, GetProcAddress І FreeLibrary.

Наступний приклад ілюструє техніку такого завантаження DLL Cmplx:

13.4.3. інтерфейсний модуль

Такий інтерфейсний модуль істотно спрощує розробку основної програми: в нашому прикладі він забезпечує такий же інтерфейс до бібліотеки cmpix, як описаний вище модуль cmpix до своїх об'єктів.

При зверненні до підпрограм DLL, написаним на інших мовах програмування, може виявитися, що зовнішнє ім'я підпрограми містить символи, які не можуть міститися в правильному ідентифікаторі Delphi. Наприклад, мова C ++ дозволяє використовувати в ідентифікаторах символ '@'. У цьому випадку (а також якщо ви хочете перейменувати що експортується з DLL підпрограму) називайте підпрограму будь-яким правильним з точки зору Delphi ідентифікатором і вкажіть справжнє ім'я підпрограми після слова name. наприклад:

13.5. ВКЛЮЧЕННЯ В БІБЛІОТЕКУ ФОРМ

У наступному прикладі ілюструється техніка включення в DLL форми і використання її в зухвалій програмі.

Текст форми в DLL

Текст викликає програми

Модуль форми DLLForm, вміщеній в DLL, посилається на стандартний модуль Forms і таким чином отримує свій глобальний об'єкт Application, який нічого 'не знає' про глобальне об'єкті викликає програми (див. Гл. 21). У режимі модального виклику це не має особливого значення, т. К. Модальне вікно блокує роботу зухвалої програми. У режимі немодального виклику слід синхронізувати дії об'єктів, в іншому випадку мінімізація головного вікна, наприклад, не призведе до мінімізації вікна DLL. Синхронізація досягається тим, що дескриптор об'єкта Application DLL замінюється на відповідний дескриптор зухвалої програми.