|
3956 / 1811 / 184
Регистрация: 21.11.2009
Сообщений: 2,540
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
Dynamic-Link Library: Теория + Практика20.07.2010, 23:49. Показов 152481. Ответов 7
1. Теоретическая часть. Знакомство с Dynamic-Link Library.
2. Практическая часть. Создание Dynamic-Link Library в RAD Studio.
3. Заключение. ________________________________________ _________ 1. Теоретическая часть. Знакомство с Dynamic-Link Library.
Для начала нужно разобраться, что же такое DLL. DLL — это сокращение фразы Dynamic-Link Library — динамически подключаемая библиотека. Первоначальная идея введения библиотек заключалась в более рациональном использовании ресурсов ПК, таких как ОЗУ и НЖМД. Предполагалось, что различные приложения будут использовать одну библиотеку, тем самым ликвидируя проблему сохранения одинаковых участков кода в различных местах и многократную загрузку одинаковых участков в ОЗУ. В дальнейшем, было решено увеличить эффективность разработки приложений за счёт модульности. Обновление самих DLL должно было позволить расширять и усовершенствовать систему, не затрагивая при этом всех приложений. Однако, данная идея столкнулась с проблемой одновременного требования приложениями разных, не полностью совместимых версий библиотек, что приводило к сбоям. Данная проблема была названа "DLL Hell". По сути, DLL - это относительно независимый участок кода, имеющий свою оболочку. Оболочка DLL имеет секции импорта/экспорта. Секция экспорта перечисляет те идентификаторы объектов (классы, функции, переменные), доступ к которым предоставляет данная DLL. В большинстве случаев именно эта секция вызывает особый интерес у разработчиков. Тем не менее, DLL может вовсе не содержать секцию экспорта. Кроме функций, к которым можно получить доступ извне (exported), существуют также внутренние функции (internal), которые спрятаны от "посторонних глаз" и могут использоваться лишь кодом самой DLL. Секция импорта предназначена для связи данной DLL с другими. Большинство библиотек импортируют функции из системных DLL (kernel32.dll, user32.dll и др.). Иногда в стандартный список нужно добавить другие библиотеки, например ws2_32.dll для работы с Socket'ами.
DLL не может выполняться сама по себе, поэтому требует хост-процесс (главный процесс, в котором предполагается использование DLL). Перед тем, как библиотеку можно будет использовать, её необходимо загрузить в область памяти хост-процесса. В exe-файле компилятором будет сгенерирована инструкция вызова заданной функции (call). Т.к. DLL расположена в адресном пространстве процесса, то вызов функции из библиотеки будет иметь вид:
Файл, являющийся динамически загружаемой библиотекой не всегда носит расширение *.dll. Есть также: *.cpl (библиотеки, используемые апплетом панели управления) и *.ocx. Библиотеки удобно использовать для разделения приложения на части, выполняющие разные роли. Например, приложение, обеспечивающее работу с базами данных может быть разделено на часть, отвечающую за выборку данных из базы, находящейся на сервере, и, часть, которая отвечает за визуальное управление приложением. Это явный пример той модульности, о которой я упоминал выше. Вы в праве изменять принципы обмена данными с сервером БД, не затрагивая при этом работу с визуальной частью. DLL может являться также обычным хранилищем ресурсов, о создании которого я рассказывал в теме https://www.cyberforum.ru/cpp-... 27736.html.
Настало время ответить на вопрос: Когда же нужно использовать DLL? Если вы разрабатываете небольшой проект или тестовое приложение, то внедрение DLL будет для вас пустой тратой времени и сил. Тратой времени: не только времени на создание библиотеки, но ещё и времени, необходимого для загрузки DLL в память хост-процесса. До того, как вы будете использовать объекты из DLL, вам рано или поздно прийдётся выгрузить содержимое в память. А это требует некоторого времени. Однако, если вашу DLL будет использовать более, чем одна копия приложения (или несколько различных приложений) - наступит явный выигрыш. Для эксперимента запустите Microsoft Office. Первый запуск долгий. Это обусловлено тем, что все необходимые модули загрузаются в оперативную память. Теперь полностью закройте Office и снова откройте его! Окно появится почти мгновенно. Это обусловлено тем, что модули хранились в ОЗУ (система не тронет их, пока ей не понадобится память для других целей). При создании больших проектов лучше сразу пытаться представить себе части, которые могут быть уникальными и требующими частого усовершенствования. Но не старайтесь придать вашему проекту чрезвычайной "уникальности" за счёт помещения каждой функции в отдельную библиотеку! Это можно делать, только зачем тратить время для загрузки каждого модуля? 2. Практическая часть. Создание Dynamic-Link Library в RAD Studio.
Пришло время постепенно перейти от теории к практике. Открываем IDE (для написании данной статьи я использовал RAD Studio 2010). Переходим к File -> New -> Other -> Dynamic-Link Library. Перед нами возникает диалог: Source Type - язык, на котором ведётся разработка. Use VCL - использование библиотеки визуальных компонентов. Multi Threaded - опция, указывающая на то, будет ли использоваться многопоточность в данной DLL (VCL уже подразумевает в себе многопоточность). VC++ Style DLL - опция, указывающая на то, будет ли DLL совместима с компиляторами Microsoft. Если в совместимости нет нужды и опция не выбрана, то DLL будет иметь точку входу с таким прототипом:
Перед нами появится шаблон минимальной DLL. Сохраним его. Как вы помните, сама по себе DLL работать не может, ей нужен клиент. Поэтому, для удобства сразу создадим новый проект VCL Forms Application. Для этого переходим в Project Manager, вызываем контекстное меню у нашей Project Group и переходим к Add New Project -> VCL Forms Application. Для удобста я назвал проекты TestDLL и TestVCL соответственно (и сохранил их в одном каталоге - это избавит меня от копирования DLL или указания абсолютного пути): Без изменений запускаем TestVCL, сохраняем и переключаемся к проекту TestDLL (дабл-клик на проекте в Project Manager). Переходим к Run -> Parameters и в поле Host Application указываем путь к нашему проекту TestVCL. К шаблону DLL добавляем функцию, которая будет вычислять сумму и выводить результат на экран:
При неявной загрузке DLL загружается (проецируется на адресное пространство вызывающего процесса) при его создании. Если при загрузке возникает ошибка - процесс останавливается и разрушается. Для выполнения неявной загрузки приложению требуются: - Заголовочный файл (*.h) с прототипами функций, описаниями классов и типов, которые используются в приложении. - Библиотечный файл (*.lib), в котором описывается список экспортируемых из DLL функций (переменных), и их смещения, необходимые для правильной настройки вызовов функций. В проекте TestVCL подключим наш заголовочный файл:
Далее, объявим прототип:
Чтобы убедится в том, что всё работает, прописываем в конструкторе формы:
![]()
Для того, чтобы выполнить явную загрузку программист должен попыхтеть, управляя DLL через функции WinAPI. Наиболее часто рассматриваемые WinAPI функции: DisableThreadLibraryCalls, FreeLibrary, FreeLibraryAndExitThread, GetModuleFileName, GetModuleHandle, GetProcAddress, LoadLibrary ... При этом, основными функциями являются: LoadLibrary[Ex] - позволяют загрузить DLL в адресное пространство хост-процесса. FreeLibrary - функция, используемая для явной выгрузки DLL. GetProcAddress - функция, позволяющая получить виртуальный адрес экспортируемой из DLL функции(или переменной) для ее последующего вызова. Общая методика выглядит так: 1. Загрузить DLL с помощью LoadLibrary. 2. Получить указатели на необходимые объекты с помощью GetProcAddress. 3. Выгрузить DLL после завершения всех действий. Теперь возникает вопрос, как же проверить теорию на практике? Всё, что нужно, это добавить TestDLL.lib к проекту (также, как и при неявной загрузке). А дальше, для проверки снова пишем в конструкторе формы:
![]() Остался один неосвещенный вопрос. Почему же название функции "ShowSum" мы ищем в библиотеке с нижним подчёркиванием? Виновато во всём декорирование имён.
Естественно, такое декорирование нам вообще не по душе. Избавиться от него можно объявляя все экспортируемые функции с модификатором extern "C" - тогда компилятор не будет искажать имя функции. Однако, как мы видим, нижние подчёркивание всё же добавилось. Это один из нюансов среды C++ Builder. Однако, можно отучить его добавлять нижнее подчёркивание таким образом: Project -> Options -> C++ Compiler -> Output -> Generate underscores on symbol names - перевести в состояние false.
Для чего же нужна отложенная загрузка? Представьте себе ситуацию: вы написали приложение, использующее стандартные системные библиотеки вашей новой операционной системы, скажем, для проверки орфографии. Даёте это приложение пользователю, который использует ОС более старой версии, чем у вас и в этой ОС нет функций для проверки орфографии. А пользователю это не сильно и надо. Приложение будет работать, пока не обратится к необходимой функции. То есть, фактически, DLL не нужна до обращения к определённой функции. Исключение отсутствия можно обработать и выдать пользователю предупреждение с просьбой обновить библиотеки своей ОС (и т.п.). Использование отложенной загрузки DLL в C++ Builder мало отличается от неявной загрузки. В проект добавляется заголовочный (*.h) файл с описаниями и библиотечный файл (*.lib). Далее, переходим в Project -> Options -> C++ Linker -> Advanced -> Delay Load DLLs и вписываем название нашей библиотеки (TestDLL.dll). Когда библиотека теряет свою необходимость её нужно явно выгрузить с помощью __FUnloadDelayLoadedDLL. В качестве параметра передаём имя DLL (с расширением + параметр регистрозависим). Если вы используете многопоточные приложения - убедитесь, что все потоки завершили работу с DLL. Примечание: Нельзя использовать отложенную загрузку для библиотек, имеющих секцию импорта (т.е. использующих другие библиотеки), а также Kernel32.dll и RTLDLL.dll (т.к. функции поддержки отложенной загрузки как раз и находятся в последней). 3. Заключение. Данная статья даёт вам представление о возможных вариантах использования DLL в ваших проектах. При внимательном ознакомлении с методами загрузки можно выбрать наиболее оптимальный вариант. Подведя итоги можно выявить плюсы и минусы описанных методов: Явная загрузка: + контроль и управление процессом жизни DLL. - управлением DLL занимается программист посредством WinAPI. Неявная загрузка: + все заботы берет на себя компилятор и сборщик. - ресурсы заняты всё время жизни приложения. Отложенная загрузка: + все заботы берет на себя компилятор и сборщик. + возможность использования приложения с не полностью совместимыми DLL. - необходимость усиленного контроля за многопоточными приложениями. ________________________________________ _________ С уважением, Михаил (a.k.a MikeSoft)
58
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
| 20.07.2010, 23:49 | |
|
Ответы с готовыми решениями:
7
Вопрос по теме Dynamic-Link Library: Теория + Практика Г.Шилдт. Теория и практика С++ Dynamic Link Library (.dll) |
|
|
||||||||||||
| 25.12.2012, 22:38 | ||||||||||||
|
Хочу сделать поправку по тому как в проекте самой DLL по умолчанию макрос TESTDLL_EXPORTS не определен, и
ф-ция будет "импортироваться" а не идти на экспорт, т.е будет не доступна. Если заглянуть в Архангельского ( 7 издание ) то там используется для этих целей макрос __DLL__ А значит следовало бы в место
Да и непонятно зачем в самом проекте еще раз объявлять ф-цию еще раз если она уже включена в хедер подключаемой бибиотеки ? https://www.cyberforum.ru/post3890200.html
8
|
||||||||||||
|
|
||||||
| 29.04.2014, 11:37 | ||||||
|
Явную загрузку можно ещё и так сделать (без использования typedef):
1
|
||||||
|
16 / 16 / 10
Регистрация: 20.11.2015
Сообщений: 305
|
|
| 17.12.2015, 04:29 | |
|
"ShowSum(3,2);" - нельзя ли конкретне... куда именно это записывать?
0
|
|
|
16 / 16 / 10
Регистрация: 20.11.2015
Сообщений: 305
|
|
| 19.12.2015, 01:41 | |
|
в какое из мест? (вопрос наверно не из умных, просто я новичок)
0
|
|
|
Почетный модератор
5851 / 2862 / 392
Регистрация: 01.11.2011
Сообщений: 6,906
|
|
| 22.12.2015, 11:02 | |
|
Tlya, по правилам языка C++ конструктор класса носит имя этого класса. Форма это класс. Из всего этого следует, что конструктор формы будет иметь название формы - TForm1, номер два в вашем списке.
На всякий случай: 1) Глобальная область видимости (вне функций). 2) Конструктор формы. 3) Метод формы, вызывающийся сразу после завершения работы конструктора.
0
|
|
|
16 / 16 / 10
Регистрация: 20.11.2015
Сообщений: 305
|
|
| 22.12.2015, 15:40 | |
|
Большущее спасибо!
0
|
|
| 22.12.2015, 15:40 | |
|
Помогаю со студенческими работами здесь
8
The ordinal 459 could not be located in the dynamic link library urlmon.dll
Unable to load dynamic library '/usr/lib/php/20151012/php_intl.dll __at Linux Проблемы с подключением библиотек: Unknown(): Unable to load dynamic library 'C:PHPextensionsphp_exif.dll' - Не найдена указанная процедура. Теория и практика вероятностей Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
Новые блоги и статьи
|
||||
|
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта
Симптом:
После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
|
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
|
Новый ноутбук
volvo 07.12.2025
Всем привет.
По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне:
Ryzen 5 7533HS
64 Gb DDR5
1Tb NVMe
16" Full HD Display
Win11 Pro
|
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
|
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
|
|
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов
На странице:
https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/
нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
|
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов.
. . .
|
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
|
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
|
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут.
В век Веб все очень привыкли к дизайну Single-Page-Application .
Быстренько разберем подход "на фреймах".
Мы делаем одну. . .
|