Наша взаимовыгодная связь https://banwar.org/
Типова задача - розробляється якась завдання і при цьому
- Деякі її компоненти можуть не інсталюватися баз шкоди для працездатності
- Деякі компоненти передбачається виготовляти згодом і розсилати користувачам
- Деякі компоненти можуть розроблятися іншими програмістами і поширюватися незалежно від програми
- .....
Класичні приклади - фільтри для сумісності з форматами файлів з іншими програмами, деякі розширення і додаткові можливості. Приклади і моєї практики - приведу парочку
- Програма управління програматором ПЗУ. Заздалегідь невідомо, з яким залізом вона буде працювати і як їм управляти. Необхідно було дати возможнось розробнику заліза написати для нього підтримку
- Програма друку звітів. Вона повинна друкувати в будь-якому кодуванні на будь-який принтері, в т.ч. і екзотичному типу АЦДП. Заздалегідь невідомо, які принтери будуп застосовуватися спільно з нею і як ними управляти (відомо тільки одне - драйверів під них немає і не буде) - переробляти програму під кожен принтер - нецікаво ...
Отже, все це можна реалізувати в DLL, однак звичайне її підключення призведе до того, що при запуску програма буде шукати всі підключення до неї DLL і в разі відсутності хоча-б однієї відмовиться запускатися. Це не прийнятно, але на щастя є можливість і вельми удоюний набір сервісних функцій для динамічного завантаження, використання і вивантаження DLL.
Приклад (додаток має одне вікно, на ньому кнопка):
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class (TForm) Button1: TButton; procedure Button1Click (Sender: TObject); procedure FormCreate (Sender: TObject); private public end; // Тип "процедура". Природно, можна визначить типи // "функція" або "функція з параметрами" ... TDllProc = procedure; var Form1: TForm1; DllProcPtr: TDllProc; LibInstance: HMODULE; // Логічний номер модуля DLL implementation {$ R * .DFM} procedure TForm1.Button1Click (Sender: TObject); begin // Перевіримо, завантажена DLL if LibInstance = 0 then Begin // Чи не завантажена, спробуємо завантажити LibInstance: = LoadLibrary ( 'plug_in.dll'); // Перевіримо, чи успішна завантаження (LibInstance = 0 - неуспішно) If LibInstance = 0 then Begin ShowMessage ( 'Помилка завантаження бібліотеки plug_in.dll'); exit; end; // Шукаємо функцію по її імені (ім'я має точно збігатися) DllProcPtr: = TDllProc (GetProcAddress (LibInstance, 'MyProc')); // Перевіримо, чи знайшли (якщо знайшли, то Assigned поверне true) if not Assigned (DllProcPtr) then Begin // Чи не знайшли - вивантажуємо DLL з пам'яті FreeLibrary (LibInstance); LibInstance: = 0; ShowMessage ( 'Помилка: функція MyProc не знайдено'); exit; end; // Безпосередньо виклик функції DllProcPtr; // Вивантаження бібліотеки FreeLibrary (LibInstance); LibInstance: = 0; end; end; procedure TForm1.FormCreate (Sender: TObject); begin DllProcPtr: = nil; LibInstance: = 0; end; end.
Природно, в реальній задачі має сенс створити свій клас, який при ініціалізації буде завантажувати бібліотеку, а при знищенні - вивантажувати. Крім того, він повинен мати функцію типу "Перезавантажити бібліотеку", яка буде вивантажувати поточну і завантажувати нову. DLL - звичайна, природно може мати необмежену кількість процедур і функцій.
особливості:
- Поки бібліотека завантажена, її файл можна ні видалити, ні перейменувати. Тому при виникненні помилок слід вивантажувати бібліотеку, інакше користувач не зможе її замінить (без перезавантаження ПК).
- Зазвичай має сенс створити ряд функції типу GetInfo, GetAutor, GetCopyRight ..., щоб зухвала програма могла отримати інформацію про призначення даної DLL
- Розширення DLL не є обов'язковим, тому можна застосовувати свої розширення (наприклад DRV)
© Зайцев Олег, "Програмування на Delphi - обмін досвідом" 1999-2004. При використанні будь-яких матеріалів даного сайту необхідно вказувати джерело інформації. Дата поновлення: 22.11.2004. Сайт розміщено на хостингу AGAVA - Хостинг від AGAVA.ru