Как сделать файл dll по умолчанию
Для начала нужно разобраться, что же такое 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 расположена в адресном пространстве процесса, то вызов функции из библиотеки будет иметь вид:
При выполнении команды call, процессор передает управление на код с адреса 010199, и выполняет его до команды ret, а затем возвращает управление команде следующей за call. Код который вызывается командой call называется процедурой.
Файл, являющийся динамически загружаемой библиотекой не всегда носит расширение *.dll.
Есть также: *.cpl (библиотеки, используемые апплетом панели управления) и *.ocx.
Библиотеки удобно использовать для разделения приложения на части, выполняющие разные роли.
Например, приложение, обеспечивающее работу с базами данных может быть разделено на часть, отвечающую за выборку данных из базы, находящейся на сервере, и, часть, которая отвечает за визуальное управление приложением. Это явный пример той модульности, о которой я упоминал выше. Вы в праве изменять принципы обмена данными с сервером БД, не затрагивая при этом работу с визуальной частью.
- 1.3. Необходимость внедрения DLL. Нужно ли это?
Настало время ответить на вопрос: Когда же нужно использовать DLL?
Если вы разрабатываете небольшой проект или тестовое приложение, то внедрение DLL будет для вас пустой тратой времени и сил. Тратой времени: не только времени на создание библиотеки, но ещё и времени, необходимого для загрузки DLL в память хост-процесса. До того, как вы будете использовать объекты из DLL, вам рано или поздно прийдётся выгрузить содержимое в память. А это требует некоторого времени.
Однако, если вашу DLL будет использовать более, чем одна копия приложения (или несколько различных приложений) - наступит явный выигрыш.
Для эксперимента запустите Microsoft Office. Первый запуск долгий. Это обусловлено тем, что все необходимые модули загрузаются в оперативную память. Теперь полностью закройте Office и снова откройте его! Окно появится почти мгновенно. Это обусловлено тем, что модули хранились в ОЗУ (система не тронет их, пока ей не понадобится память для других целей).
При создании больших проектов лучше сразу пытаться представить себе части, которые могут быть уникальными и требующими частого усовершенствования.
Но не старайтесь придать вашему проекту чрезвычайной "уникальности" за счёт помещения каждой функции в отдельную библиотеку! Это можно делать, только зачем тратить время для загрузки каждого модуля?
- 2.1. Создаём первую DLL своими руками.
Пришло время постепенно перейти от теории к практике.
Открываем 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 мы подготовили. Теперь необходимо узнать, как же подключить DLL к проекту. Сделать это можно тремя способами. Рассмотрим их подробнее.
При неявной загрузке DLL загружается (проецируется на адресное пространство вызывающего процесса) при его создании. Если при загрузке возникает ошибка - процесс останавливается и разрушается.
Для выполнения неявной загрузки приложению требуются:
- Заголовочный файл (*.h) с прототипами функций, описаниями классов и типов, которые используются в приложении.
- Библиотечный файл (*.lib), в котором описывается список экспортируемых из DLL функций (переменных), и их смещения, необходимые для правильной настройки вызовов функций.
В проекте TestVCL подключим наш заголовочный файл:
Далее, объявим прототип:
Теперь осталось только вызвать функцию там, где это необходимо.
Чтобы убедится в том, что всё работает, прописываем в конструкторе формы:
Запускаем и смотрим на результат. Думаю, "3 + 2 = 5" всех устраивает.
Для того, чтобы выполнить явную загрузку программист должен попыхтеть, управляя 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 к проекту (также, как и при неявной загрузке).
А дальше, для проверки снова пишем в конструкторе формы:
И на экране снова красуется победная надпись "3 + 2 = 5"
Остался один неосвещенный вопрос. Почему же название функции "ShowSum" мы ищем в библиотеке с нижним подчёркиванием?
Виновато во всём декорирование имён.
Прототип функции Test(int); мог быть преобразован компилятором, например в ?Test@@YAKH@Z.
Естественно, такое декорирование нам вообще не по душе. Избавиться от него можно объявляя все экспортируемые функции с модификатором 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.
- необходимость усиленного контроля за многопоточными приложениями.
Файл DLL – компонент динамически подключаемой библиотеки, чьи элементы используют практически все программы. Библиотека DLL файлов расположена в корневой папке системы. Компоненты должны быть все в наличии, иметь цифровую подпись, правильно работать и быть актуальными по версии. Если одно из требований не соблюдено, при запуске программы пользователь получит информационное уведомление: ошибка DLL. Неисправность свидетельствует о том, что отсутствует DLL файл, поврежден или устарел.
Как установить DLL файл
Чтобы программы, приложения и игры снова начали работать, необходимо установить вручную недостающие компоненты библиотеки. Просто поместить файл в папку недостаточно ─ нужно знать как их зарегистрировать.
Помещение и регистрация файлов библиотеки
Перед тем как установить DLL файл на Windows 7,8,10, их нужно скачать, причем точно под разрядность системы.
Давайте определим, какая разрядность у Вашей системы (если вы точно знаете, может пропустить этот шаг)
Шаг 1. Кликаем правой кнопкой мыши по "Мой компьютер" и выбираем "Свойства"
Шаг 2. В открывшемся окне, мы может прочитать свойства компьютера, версию операционной системы и её разрядность 32 (х86) или 64 бит. В нашем случаи стоит 64-разрядная операционная система Windows 10.
·
Шаг 3. После скачивания файлов их нужно поместить в корневую папку, зарегистрировать
для х32 (х86) систем компонент необходимо заменить или поместить в папку C:\Windows\System32;
для х64 необходимо выполнить замену или переместить в папку C:\Windows\ SysWOW64;
Шаг 4. Файл нужно зарегистрировать в системе.
Сделать это можно, открыв командную строку комбинацией «Win» + «R», или нажать «Пуск» и «Выполнить»;
в открывшемся окне ввести через пробел следующее: regsvr32 имя файла.dll – где, «regsvr32» ─ команда для регистрации, а «имя файла.dll» – полное имя вставленного компонента;
или же можно прописать расположение файла вручную - regsvr32.exe + путь к файлу
Шаг 5. Нажмите "ОК", и перезагрузите компьютер, и новые параметры вступят в силу.
Сразу хочется отметить, что при регистрации возможны появления ошибок. Например: "Не удалось загрузить модуль". Обычно они возникают по 3 причинам
Второй способ регистрации
Шаг 1. Зарегистрировать файл можно с помощью командой строки, которую нужно запустить от имени администратора.
Шаг 2. Пишем команду regsvr32.exe + путь к файлу и жмём "Enter"
Очень часто в своей работе, Вы будете сталкиваться с такой ситуацией.
Перед вами стоит задача, нужно написать программу " Супер Блокнот" которая должна сохранить все функции стандартного блокнота, но при этом иметь ряд каких-то дополнительных функций, благодаря которым, при выборе программы для работы с текстом, пользователь будет отдавать предпочтение именно вашей программе. Для этого было решено добавить несколько новых функций, одна из них, будет отвечать за подсчет и вывод количества слов в тексте.
Через пару недель программа была написана, затем она попала в Интернет, пользователи оценили новый продукт и стали им пользоваться. Цель достигнута.
Проходит время и перед вами ставят новую задачу, написать программу "Супер парсер". Одной из функции данной программы, будет подсчет слов в тексте. Вы понимаете, что снова придется разрабатывать метод, который будет вести подсчёт слов. Но, при этом вспоминаете, что совсем не давно уже разрабатывали программу, в которой применялась данная функция. Чтобы не изобретать велосипед, Вы открываете исходник программы "Супер блокнот"; и копируете весь метод в исходник новой программы "Супер парсер". Отлично, теперь Вам не придется тратить время на написание этого метода заново, и Вы можете посветить больше времени остальным элементам программы. Задача решена.
Но, что если метод по подсчету слов, писали не Вы, а допустим, какой-нибудь коллега по работе и по каким-то причинам, Вы не можете получить доступ к исходному коду программы "Супер блокнот". То есть первый вариант, копирование метода из исходника, не прокатит и данный метод придется писать самому ммм, печалька.
Но, тут вам звонит ваш коллега по работе и говорит: Ты знаешь, я тут вспомнил, когда я разрабатывал данный метод, я подумал, что возможно мне придется его использовать ещё где-то, и по этому я решил вынести его в отдельную сборку, в виде файла динамической библиотеки (dll).Ты просто скопируй этот файл dll в свой проект, и подключи его, как внешнюю сборку, после чего ты получишь доступ к моему методу и сможешь им пользоваться.
Отлично! Вы проделываете все описанные действия, в программе “Супер парсер” появляется нужный метод, задача решена и вам вновь не пришлось повторно писать код руками.
На этом присказка закончена и теперь переходим к более подробному изучению.
Что такое DLL
DLL (dynamic-link library) - это динамически подключаемая библиотека, или сокращено динамическая библиотека.
Как уже писал ранее, динамические библиотеки, позволяют повторно использовать ранее написанный код, а так же они обеспечивают лучшую переносимость кода. Достаточно, скинуть файл на флешку, или скачать dll файл из Интернета, после чего добавить его в текущий проект и тут же получить набор разных дополнительных функций для вашего приложения. Так же стоит знать, что в одном dll файле может храниться любое количество типов, членов и пространств имён.
Создание файла dll
Для начала выберем тип нового создаваемого приложения, а точнее проекта.
Выбираем Class Library, то есть создаем файл динамической библиотеки (dll)
Так же Вы можете указать, под какую версию Фреймворка будет создаваться данный проект.
После того, как Visual Studio создаст каркас проекта, Вы увидите следующее:
Так будет выглядеть окно Solution Explorer
А так будет выглядеть рабочая область, где Вы обычно пишите код программы
И так дано пространство имён: Car и класс: Class1. Class1 не удачное название, давайте немного изменим наш код, заменив Class1 на BMW, и добавим метод, который будет выводить имя нашего класса.
И так код написан, и теперь необходимо выполнить компиляцию, чтобы получить сборку.
Если сейчас попытаться нажать F5 или Ctrl+F5, то вы увидите данное окно
Данная ошибка, говорит лишь о том, что был создан файл динамической библиотеки (dll), а не исполняемый файл (exe), который не может быть запущен.
Для того, чтобы скомпилировать проект, нажмите клавишу F6, после чего в директории bin\Debug появиться файл Car.dll.
Чтобы проверить был ли создан файл библиотеки, воспользуйтесь кнопкой Show All Files на вкладке Solution Explorer
Сборка, в виде файла динамической библиотеки успешно создана.
Теперь перейдем в папку bin\Debug, для того, чтобы быстро переместиться в текущую директорию проекта, в том же Solution Explorer воспользуйтесь пунктом Open Folder in Windows Explorer
Скопируйте полученный файл сборки (в нашем случае - это файл Car.dll) в какую-нибудь временную папку. На самом деле, это делать необязательно, Вы можете оставить данный файл в этой папке, но для удобства, создадим новую папку, и поместим туда созданный файл библиотеки.
Создаем новый проект.
Новый проект создан. Теперь подключим в текущий проект, нашу библиотеку (Car.dll)
Подключение dll
Для этого на папке References, в окне Solution Explorer нужно нажать правую кнопку мыши и выбрать пункт Add Reference, откроется вот такое окно:
- Выберите вкладку Browse
- Укажите папку, в которой лежит файл созданной библиотеки (в нашем примере - Car.dll)
- Выделите файл нужной библиотеки и нажмите кнопку ОК;
На ней видно, что в наш текущий проект была успешна, добавлена ссылка на нашу сборку Car.dll, в которой храниться наш код на языке IL. Надеюсь, Вы помните, что после компиляции весь написанный вами код преобразуется в промежуточный код на языке IL (CIL, MSIL - это одно и тоже). А так же видно, что в папку bin\Debug была помещёна копия нашей библиотеки.
Если вдруг Вы забыли, какое пространство имен, типы, или члены содержит ваша созданная библиотека. Вы всегда можете воспользоваться таким инструментом Visual Studio, как Object Browser. Для этого перейдите на вкладку Solution Explorer, откройте папку References, и просто щёлкните правой кнопкой мыши по добавленной ранее библиотеке, в нашем случае напоминаю - это файл (Car.dll) и выберите пункт View in Object Browser, появиться вот такое окно.
В окне Object Browser можно посмотреть содержимое нашей сборки.
Сборка подключена и теперь Вы можете работать с её содержимым. Далее выполним необязательный пункт.
Добавим, с помощью ключевого слова using пространство имен Car из созданной нами библиотеки Car.dll, после чего создадим объект класса BMW и выполним метод Вывести_Имя_Класса().
- Создаем файл динамической библиотеки (dll)
- Подключаем созданную библиотеку в наш проект, путем добавления в папку References ссылки на наш файл dll.
- (Необязательный пункт) Подключаем пространство имен из подключенной сборки, с помощью ключевого слова using, либо используем полное наименование, то есть Пространство имён.Тип (Car.BMW).
- Profit
И в конце не много информации о типах сборок:
Сборки бывают следующих основных видов: общие и частные.
Частная сборка (private assembly)
Это файлы библиотек, как наш ранее созданный файл Car.dll, которые содержаться на протяжении всего времени в каталоге текущего приложения или любом из его подкаталогов.
Вернёмся к началу статьи.
После того, как было создано приложение “Супер парсер”, мы получили сборку в виде файла (exe). Затем мы решили протестировать нашу программу и отдаём её нашему другу, при этом Вы так же упоминаете, что если он хочет иметь дополнительные функции в программе, то ему нужно просто рядом с его exe файлом поместить файл библиотеки Car.dll. После чего он получит возможность подсчёта слов в тексте. То есть библиотека будет храниться в той же директории, что и исполняемый файл.
Общие сборки (shared assembly)
Это сборки, предназначенные для множественного использования разными приложениями, установленными на одном компьютере.
Среди частых вопросов пользователей, особенно после того, как они сталкиваются с тем, что какая-то из библиотек DLL отсутствует в Windows 10, Windows 11 или других версиях системы — как зарегистрировать DLL в соответствующей версии ОС.
В этой инструкции подробно о способах регистрации библиотек DLL в Windows x64 и x86 (32-бит) с помощью regsvr32.exe (и кратко о regasm.exe), о возможных нюансах и проблемах, которые могут возникнуть в процессе.
Дальнейшие шаги описаны в предположении, что DLL, которую нужно зарегистрировать, уже находится в нужном расположении: папке C:\Windows\System32, C:\Windows\SysWOW64 или, в некоторых случаях — отдельных папках программ, к которой относится соответствующая библиотека, например, для 1С — C:\Program Files\1cv8\номер_версии\bin (или Program Files x86 в случае 32-битной версии).
Прежде чем приступить к регистрации библиотеки, учитывайте следующие моменты:
- В x64 версиях Windows 64-битные DLL хранятся в System32, а 32-битные — в SysWOW64 (у некоторых начинающих пользователей бывает обратное предположение исходя из имён папок).
- Файлы DLL x64 и x86 (32-бит) — это разные файлы. И если прямого указания на разрядность в месте загрузки файла нет, то чаще это 32-битный файл (что не мешает ему работать в x64 системе), но это не всегда так.
- Для регистрации библиотеки DLL используется системный инструмент regsvr32.exe, который также доступен в двух версиях, которые лежат в папках System32 и SysWOW64 (в случае 64-битных систем). По умолчанию при описываемых далее действиях запускается x64 версия.
- 32-битным программам и играм (по умолчанию устанавливаются в Program Files x86 в 32-битных системах) для работы нужны 32-битные DLL, не зависимо от разрядности Windows.
Сам процесс регистрации в общем случае состоит из следующих шагов:
Почему не удается зарегистрировать DLL
Ошибка при регистрации с помощью regsvr32 вида «Точка входа DllRegisterServer не найдена» говорит о том, что эта библиотека DLL не поддерживает регистрацию описанным методом. Можно попробовать использовать вариант команды:
но с большой вероятностью и это не поможет.
У большинства домашних пользователей такая проблема возникает при регистрации файлов DLL для игр и программ, часто не вполне лицензионных, которые сообщили, что нужный файл DLL не обнаружен или отсутствует. Причем сами библиотеки DLL обычно скачаны со сторонних сайтов (и чаще всего имеют имена начинающиеся с «vc», «msvc» или «d3d»). А решение, как правило, простое — выяснить, частью какого набора компонентов является эта DLL и установить эти компоненты с помощью их собственного установщика. Более подробно проблема и подходы к решению описаны в инструкции Точка входа DllRegisterServer не найдена — причины и возможные решения.
Видео
Надеюсь, цель достигнута, а количество вопросов, связанных с регистрацией DLL в Windows, уменьшилось.
Читайте также: