|
3957 / 1812 / 184
Регистрация: 21.11.2009
Сообщений: 2,540
|
||||||||||||||||||||||||||||||||||||||||||||||||||||
Dynamic-Link Library: Теория + Практика20.07.2010, 23:49. Показов 152848. Ответов 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' - Не найдена указанная процедура. Теория и практика вероятностей Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |
|
| Опции темы | |
|
|
Новые блоги и статьи
|
|||
|
YAFU@home — распределённые вычисления для математики. На CPU
Programma_Boinc 20.01.2026
YAFU@home — распределённые вычисления для математики. На CPU
YAFU@home — это BOINC-проект, который занимается факторизацией больших чисел и исследованием aliquot-последовательностей.
Звучит. . .
|
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
|
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма).
На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
|
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ *
Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам
Кирхгофа, решает её и находит:
токи, напряжения и их 1 и 2 производные при t = 0;. . .
|
|
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым.
Но восстановить их можно так.
Для этого понадобится консольная утилита. . .
|
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
|
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11
— это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
|
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11
Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
|