Запуск библиотеки dll как приложения

Обновлено: 06.07.2024

Динамическая библиотека служит базой для создания небольших программ в среде Windows. Это внешние источники данных, которые нужны для полноценной работы ПО. Второй вариант расширения — динамические веб-страницы, которые создаются сервером, при обращении пользователей к ним.

Рисунок 1. Внешний вид ярлыка файлов с расширением .dll

Рассмотрим, как работать с обоими типами в различных ОС.

Чем открыть файл dll для редактирования

Вне зависимости от того, является понятие частью прикладной программы или входит в состав систем МС, распространённый вопрос — чем открыть файл dll для редактирования.

Стоит знать, что он реализует ряд программных функций. От соединения с внешними устройствами и работы с жестким диском до применения в кросс платформенных приложениях.

Примечание: Поэтому какие-либо изменения в его структуре могут привести к ошибкам операционной системы.

Но, если вы хотите познакомиться с исходным кодом, вам потребуется специальный редактор для системных ресурсов Resource Hacker (ResHacker). Он позволяет извлекать и изменять код на ваше усмотрение (Рисунок 2).

Открываем и редактируем .dll файлы при помощи приложения reshacker

Рисунок 2. Интерфейс приложения Resource Hacker для открытия файлов формата .dll

Пошаговая инструкция

Итак, как открыть dll файл для изменения?

Для чтения в исходном формате выберите в верхней панели File>Open.

Слева будут показаны директивы с содержащимися в них открываемыми объектами.

В центре утилиты содержатся коды, подлежащие изменениям и сохранению.

Для компиляции воспользуйтесь кнопкой Compile Script.

Для сохранения используйте команду File>Save.

Открыть dll файл онлайн

Если вы имеете дело с веб-страницей, то вам понадобится открыть этот dll файл онлайн. Он содержит в себе скрипты сервера, отвечающие за генерирование HTML. К примеру, VB или Perl.

Как открыть dll файл windows 10

Если это элементы библиотеки, которые расположены в системной папке, то они предназначены для запуска приложений, созданных при помощи Visual C++.

Поэтому, чтобы их открыть на том же windows10 понадобится соответствующее ПО от МС — Visual Studio или VisualFoxPro (Рисунок 3).

Открываем .dll файлы при помощи visual studio для windows 10

Рисунок 3. Визуальный пример открытого файла формата .dll в приложении Visual Studio на Windows 10

Также «длл» должен открываться программой, использующей его библиотеку.

Как открыть файл dll на windows 8

Windows 8 уже является специализированным программным обеспечением для этого формата, поэтому задача с его открытием имеет очень простое решение. Если трудности и возникают — необходимо изменить ассоциацию файлов, установив и назначив одну из указанных ниже программ приложением по умолчанию.

Microsoft Windows 8;

Microsoft Windows NT 4.0;

Как открыть файл dll в windows 7

Вы можете встретить распространённый тип документа mfc42u.dll, который относится к Microsoft Foundation Class (MFC).

Примечание: Он отвечает за запуск рабочих дополнений на вашем ПК.

Открыть этот файл dll и подобные ему в windows 7 можно теми же утилитами, что используются для 8 версии, или воспользоваться небольшим редактором исполняемых элементов — Resource Tuner (Рисунок 4).

Открываем .dll файлы на windows 7 при помощи resource tuner

Рисунок 4. Интерфейс приложения Resource Tuner с открытым файлом формата .dll

Он позволяет изменять различные детали пользовательского интерфейса — строки меню и диалоговых окон, внешний вид курсора, иконок и так далее. В нём ресурсы библиотеки отделены от кода, который остаётся неизменным. Для его редактирования есть используемые в программировании профессиональные редакторы PE Explorer и FlexHex, (в зависимости от вносимых правок).

Resource Tuner предусматривает несколько способов открытия объекта.

Для просмотра и изменения кликните Open File на панели инструментов.

Для выполнения действия в меню — введите команду File>Open.

Или используйте комбинацию клавиш CTRL+O.

Всплывающее окно возле кнопки тулбара предоставит вам список последних открывавшихся элементов. Его можно получить командой File>Recent Files из меню программы, которая пользуется динамически подключаемой библиотекой. Настройка количества данных в списке осуществляется в окне диалога Customize.

Открыть dll файл на MacOS

На MacOs тоже встречаются данные этого формата. Их можно просмотреть в окне любого веб-браузера, если они представлены в виде интернет страницы.

На системные файлы dll в большинстве случаев ссылаются кросс платформенные приложения и по факту, открывать и редактировать их в среде Macintosh нет никакой необходимости.

Открытие dll файл на linux

Чтобы получить доступ к ним на Linux, понадобится эмулятор Windows – Wine. Он подражает поведению различных версий этой операционной системы.

Утилита поддерживает её исполняемые данные, поэтому проблем с открытием имеющихся файлов ни в одном из дистрибутивов быть не должно. Она эмулирует библиотеки Windows, создавая их альтернативные варианты, которые не требуют лицензии Microsoft, обеспечивая тем самым независимость вашего ПО.

Настроить работу Wine можно при помощи вкладки Default Settings — установок по умолчанию. Так он будет автоматически запускать приложения в выбранной вами ОС.

Программа для открытия dll файлов

Для отображения в родной среде можно использовать обычный блокнот. Но в таком случае возникнет трудность с не читаемыми символами. Чтобы её не было, необходима специальная программа для открытия dll файлов. К примеру, бесплатный декомпилятор dotPeek.

Найдите нужный элемент для декомпиляции.

Вы можете его просто просмотреть, не нарушая целостности системы.

Для профессионального применения есть отдельное ПО. Самый известный его вариант — Resource Hacker, описание которого было приведено выше.

Его можно бесплатно скачать с официального сайта разработчика. Инсталлятор быстро загружается и открывается на ПК, а установка не отнимает много времени.

Часто библиотеки DLL помещаются в файлы с различными расширениями, такими как .EXE, .DRV или .DLL.

Преимущества DLL

Ниже приведены несколько преимуществ наличия файлов DLL.

Использует меньше ресурсов

DLL файлы не загружаются в оперативную память вместе с основной программой; они не занимают места, если не требуется. Когда требуется файл DLL, он загружается и запускается. Например, пока пользователь Microsoft Word редактирует документ, файл DLL принтера не требуется в оперативной памяти. Если пользователь решает распечатать документ, то приложение Word вызывает загрузку и запуск DLL-файла принтера.

Способствует модульной архитектуре

DLL помогает продвигать разработку модульных программ. Это помогает вам разрабатывать большие программы, которые требуют многоязычных версий, или программу, которая требует модульной архитектуры. Примером модульной программы является бухгалтерская программа, имеющая много модулей, которые могут динамически загружаться во время выполнения.

Помогите легко развернуть и установить

Когда функция в DLL нуждается в обновлении или исправлении, развертывание и установка DLL не требует повторного связывания программы с DLL. Кроме того, если несколько программ используют одну и ту же DLL, все они получают выгоду от обновления или исправления. Эта проблема может возникать чаще, когда вы используете сторонние библиотеки DLL, которые регулярно обновляются или исправляются.

Приложения и библиотеки DLL могут автоматически ссылаться на другие библиотеки DLL, если связь с DLL указана в разделе ИМПОРТ файла определения модуля как часть компиляции. Иначе, вы можете явно загрузить их, используя функцию Windows LoadLibrary.

Важные DLL-файлы

Сначала мы обсудим проблемы и требования, которые вы должны учитывать при разработке своих собственных библиотек DLL.

Типы DLL

Когда вы загружаете DLL в приложение, два метода связывания позволяют вам вызывать экспортированные функции DLL. Два метода связывания:

  • динамическое связывание во время загрузки и
  • динамическое связывание во время выполнения.

Динамическое связывание во время загрузки

При динамическом связывании во время загрузки приложение выполняет явные вызовы экспортируемых функций DLL, таких как локальные функции. Чтобы использовать динамическое связывание во время загрузки, предоставьте файл заголовка (.h) и файл библиотеки импорта (.lib) при компиляции и компоновке приложения. Когда вы сделаете это, компоновщик предоставит системе информацию, необходимую для загрузки DLL, и разрешит расположение экспортированных функций DLL во время загрузки.

Динамическое связывание во время выполнения

При динамическом связывании во время выполнения приложение вызывает либо функцию LoadLibrary, либо функцию LoadLibraryEx, чтобы загрузить DLL во время выполнения. После успешной загрузки DLL вы используете функцию GetProcAddress, чтобы получить адрес экспортированной функции DLL, которую вы хотите вызвать. Когда вы используете динамическое связывание во время выполнения, вам не нужен файл библиотеки импорта.

В следующем списке описаны критерии приложения для выбора между динамическим связыванием во время загрузки и динамическим связыванием во время выполнения:

Производительность при запуске: если важна начальная производительность при запуске приложения, следует использовать динамическое связывание во время выполнения.

Простота использования : при динамическом связывании во время загрузки экспортированные функции DLL похожи на локальные функции. Это помогает вам легко вызывать эти функции.

Логика приложения . При динамическом связывании во время выполнения приложение может выполнять ветвление для загрузки различных модулей по мере необходимости. Это важно при разработке многоязычных версий.

Производительность при запуске: если важна начальная производительность при запуске приложения, следует использовать динамическое связывание во время выполнения.

Простота использования : при динамическом связывании во время загрузки экспортированные функции DLL похожи на локальные функции. Это помогает вам легко вызывать эти функции.

Логика приложения . При динамическом связывании во время выполнения приложение может выполнять ветвление для загрузки различных модулей по мере необходимости. Это важно при разработке многоязычных версий.

Точка входа в DLL

Когда вы создаете DLL, вы можете дополнительно указать функцию точки входа. Функция точки входа вызывается, когда процессы или потоки присоединяются к DLL или отсоединяются от DLL. Вы можете использовать функцию точки входа для инициализации или уничтожения структур данных в соответствии с требованиями DLL.

Кроме того, если приложение является многопоточным, вы можете использовать локальное хранилище потоков (TLS) для выделения памяти, которая является частной для каждого потока в функции точки входа. Следующий код является примером функции точки входа DLL.

Когда функция точки входа возвращает значение FALSE, приложение не запускается, если вы используете динамическое связывание во время загрузки. Если вы используете динамическое связывание во время выполнения, не будет загружаться только отдельная DLL.

Функция точки входа должна выполнять только простые задачи инициализации и не должна вызывать какие-либо другие функции загрузки или завершения DLL. Например, в функции точки входа не следует прямо или косвенно вызывать функцию LoadLibrary или функцию LoadLibraryEx . Кроме того, вы не должны вызывать функцию FreeLibrary, когда процесс завершается.

ВНИМАНИЕ : В многопоточных приложениях убедитесь, что доступ к глобальным данным DLL синхронизирован (потокобезопасен), чтобы избежать возможного повреждения данных. Для этого используйте TLS, чтобы предоставить уникальные данные для каждого потока.

Экспорт функций DLL

Чтобы экспортировать функции DLL, вы можете добавить ключевое слово функции в экспортированные функции DLL или создать файл определения модуля (.def), в котором перечислены экспортированные функции DLL.

Чтобы использовать ключевое слово функции, вы должны объявить каждую функцию, которую вы хотите экспортировать, со следующим ключевым словом:

Чтобы использовать экспортированные функции DLL в приложении, вы должны объявить каждую функцию, которую вы хотите импортировать, с помощью следующего ключевого слова:

Как правило, вы использовали бы один заголовочный файл, имеющий оператор определения и оператор ifdef, чтобы разделить оператор экспорта и оператор импорта.

// SampleDLL.def // LIBRARY "sampleDLL" EXPORTS HelloWorld

Написать пример DLL

В Microsoft Visual C ++ 6.0 вы можете создать DLL, выбрав либо тип проекта Win32 Dynamic-Link Library, либо тип проекта MFC AppWizard (dll) .

Следующий код представляет собой пример библиотеки DLL, созданной в Visual C ++ с использованием типа проекта Win32 Dynamic-Link Library.

Вызов примера библиотеки DLL

Следующий код является примером проекта приложения Win32, который вызывает экспортированную функцию DLL в библиотеке SampleDLL.

ПРИМЕЧАНИЕ . При динамическом связывании во время загрузки необходимо связать библиотеку импорта SampleDLL.lib, которая создается при сборке проекта SampleDLL.

При динамическом связывании во время выполнения вы используете код, подобный следующему коду, для вызова экспортированной функции DLL SampleDLL.dll.

Когда вы компилируете и связываете приложение SampleDLL, операционная система Windows ищет библиотеку SampleDLL в следующих местах в следующем порядке:

Системная папка Windows (функция GetSystemDirectory возвращает путь к системной папке Windows).

Папка Windows (функция GetWindowsDirectory возвращает путь к папке Windows).

Системная папка Windows (функция GetSystemDirectory возвращает путь к системной папке Windows).

Папка Windows (функция GetWindowsDirectory возвращает путь к папке Windows).

Это может быть использовано для включения и выключения службы.

Доступно несколько инструментов, которые помогут вам решить проблемы с DLL. Некоторые из них обсуждаются ниже.

Зависимость Уокер

Средство Dependency Walker ( disabled.exe ) может рекурсивно сканировать все зависимые библиотеки DLL, которые используются программой. Когда вы открываете программу в Dependency Walker, Dependency Walker выполняет следующие проверки:

  • Проверяет наличие недостающих DLL.
  • Проверяет недопустимые программные файлы или библиотеки DLL.
  • Проверяет, совпадают ли функции импорта и функции экспорта.
  • Проверяет круговые ошибки зависимости.
  • Проверяет недопустимые модули, поскольку модули предназначены для другой операционной системы.

DLL Универсальный Решатель Проблем

Инструмент универсального решения проблем DLL (DUPS) используется для аудита, сравнения, документирования и отображения информации DLL. В следующем списке описаны утилиты, которые составляют инструмент DUPS:

Помните следующие советы при написании DLL:

Используйте правильное соглашение о вызовах (C или stdcall).

Помните о правильном порядке аргументов, передаваемых в функцию.

НИКОГДА не изменяйте размеры массивов и не объединяйте строки, используя аргументы, передаваемые непосредственно в функцию. Помните, что передаваемые вами параметры являются данными LabVIEW. Изменение размеров массива или строки может привести к сбою при перезаписи других данных, хранящихся в памяти LabVIEW. Вы МОЖЕТЕ изменить размер массивов или объединить строки, если вы передадите дескриптор массива LabVIEW или дескриптор строки LabVIEW и используете компилятор Visual C ++ или Symantec для компиляции вашей DLL.

При передаче строк в функцию выберите правильный тип строки для передачи. C или Паскаль или LabVIEW Строка Ручка.

Длина строк Паскаля ограничена 255 символами.

Если вы работаете с массивами или строками данных, ВСЕГДА передавайте буфер или массив, достаточно большой, чтобы хранить любые результаты, помещенные в буфер функцией, если вы не передаете их как дескрипторы LabVIEW, и в этом случае вы можете изменить их размер с помощью CIN. работает под компилятором Visual C ++ или Symantec.

Перечислите функции DLL в разделе EXPORTS файла определения модуля, если вы используете _stdcall.

Перечислите функции DLL, которые другие приложения вызывают в разделе EXPORTS файла определения модуля, или включите ключевое слово _declspec (dllexport) в объявление функции.

Если вы используете компилятор C ++, экспортируйте функции с помощью оператора extern .C. <> В заголовочном файле, чтобы предотвратить искажение имени.

Если вы пишете свою собственную DLL, вы не должны перекомпилировать DLL, пока DLL загружается в память другим приложением. Перед перекомпиляцией DLL убедитесь, что все приложения, использующие эту конкретную DLL, выгружены из памяти. Это гарантирует, что сама DLL не загружается в память. Возможно, вам не удастся восстановить правильно, если вы забудете об этом и ваш компилятор не предупредит вас.

Протестируйте свои DLL с другой программой, чтобы убедиться, что функция (и DLL) работают правильно. Тестирование с помощью отладчика вашего компилятора или простой C-программы, в которой вы можете вызывать функцию в DLL, поможет вам определить, являются ли возможные трудности присущими DLL или LabVIEW.

Используйте правильное соглашение о вызовах (C или stdcall).

Помните о правильном порядке аргументов, передаваемых в функцию.

НИКОГДА не изменяйте размеры массивов и не объединяйте строки, используя аргументы, передаваемые непосредственно в функцию. Помните, что передаваемые вами параметры являются данными LabVIEW. Изменение размеров массива или строки может привести к сбою при перезаписи других данных, хранящихся в памяти LabVIEW. Вы МОЖЕТЕ изменить размер массивов или объединить строки, если вы передадите дескриптор массива LabVIEW или дескриптор строки LabVIEW и используете компилятор Visual C ++ или Symantec для компиляции вашей DLL.

При передаче строк в функцию выберите правильный тип строки для передачи. C или Паскаль или LabVIEW Строка Ручка.

Длина строк Паскаля ограничена 255 символами.

Если вы работаете с массивами или строками данных, ВСЕГДА передавайте буфер или массив, достаточно большой, чтобы хранить любые результаты, помещенные в буфер функцией, если вы не передаете их как дескрипторы LabVIEW, и в этом случае вы можете изменить их размер с помощью CIN. работает под компилятором Visual C ++ или Symantec.

Перечислите функции DLL в разделе EXPORTS файла определения модуля, если вы используете _stdcall.

Перечислите функции DLL, которые другие приложения вызывают в разделе EXPORTS файла определения модуля, или включите ключевое слово _declspec (dllexport) в объявление функции.

Если вы используете компилятор C ++, экспортируйте функции с помощью оператора extern .C. <> В заголовочном файле, чтобы предотвратить искажение имени.

Если вы пишете свою собственную DLL, вы не должны перекомпилировать DLL, пока DLL загружается в память другим приложением. Перед перекомпиляцией DLL убедитесь, что все приложения, использующие эту конкретную DLL, выгружены из памяти. Это гарантирует, что сама DLL не загружается в память. Возможно, вам не удастся восстановить правильно, если вы забудете об этом и ваш компилятор не предупредит вас.

Протестируйте свои DLL с другой программой, чтобы убедиться, что функция (и DLL) работают правильно. Тестирование с помощью отладчика вашего компилятора или простой C-программы, в которой вы можете вызывать функцию в DLL, поможет вам определить, являются ли возможные трудности присущими DLL или LabVIEW.

Мы видели, как написать DLL и как создать программу «Hello World». Этот пример, должно быть, дал вам представление об основной концепции создания DLL.

Здесь мы дадим описание создания DLL с использованием Delphi, Borland C ++ и снова VC ++.

Использование DLL в программе на Visual C++

Многие знают, что существует два основных способа подключить DLL к программе - явный и неявный.

При неявном подключении (implicit linking) линкеру передается библиотека импорта (обычно имеет расширение lib), содержащая список переменных и функций DLL, которые могут использовать приложения. Обнаружив, что программа обращается хотя бы к одной из них, линкер добавляет в целевой exe-файл таблицу импорта . Таблица импорта содержит список всех DLL, которые использует программа, с указанием конкретных переменных и функций, к которым она обращается. Позже, когда exe-файл будет запущен, загрузчик проецирует все DLL, перечисленные в таблице импорта, на адресное пространство процесса; в случае неудачи весь процесс немедленно завершается.

При явном подключении (explicit linking) приложение вызывает функцию LoadLibrary, чтобы загрузить DLL, затем использует функцию GetProcAddress, чтобы получить указатели на требуемые функции (или переменные), а по окончании работы с ними вызывает FreeLibrary, чтобы выгрузить библиотеку и освободить занимаемые ею ресурсы.

Каждый из способов имеет свои достоинства и недостатки. В случае неявного подключения все библиотеки, используемые приложением, загружаются в момент его запуска и остаются в памяти до его завершения (даже если другие запущенные приложения их не используют). Это может привести к нерациональному расходу памяти, а также заметно увеличить время загрузки приложения, если оно использует очень много различных библиотек. Кроме того, если хотя бы одна из неявно подключаемых библиотек отсутствует, работа приложения будет немедленно завершена. Явный метод лишен этих недостатков, но делает программирование более неудобным, поскольку требуется следить за своевременными вызовами LoadLibrary и соответствующими им вызовами FreeLibrary, а также получать адрес каждой функции через вызов GetProcAddress.

Теперь рассмотрим, как каждый из перечисленных методов используется на практике. Для этого будем считать, что у нас есть библиотека MyDll.dll, которая экспортирует переменную Var, функцию Function и класс Class. Их объявления содержатся в заголовочном файле MyDll.h, который выглядит следующим образом:

Кроме того, будем считать, что библиотека импорта содержится в файле MyDll.lib.

Неявное подключение

Это наиболее простой метод подключения DLL к нашей программе. Все, что нам нужно - это передать линкеру имя библиотеки импорта, чтобы он использовал ее в процессе сборки. Сделать это можно различными способами.

Теперь можно использовать в программе любые переменные, функции и классы, содержащиеся в DLL, как если бы они находились в статической библиотеке. Например:

Явное подключение

Загрузка DLL

Как уже говорилось ранее, при явном подключении DLL программист должен сам позаботиться о загрузке библиотеки перед ее использованием. Для этого используется функция LoadLibrary, которая получает имя библиотеки и возвращает ее дескриптор. Дескриптор необходимо сохранить в переменной, так как он будет использоваться всеми остальными функциями, предназначенными для работы с DLL.

В нашем примере загрузка DLL выглядит так.

Вызов функций

После того как библиотека загружена, адрес любой из содержащихся в ней функций можно получить с помощью GetProcAddress, которой необходимо передать дескриптор библиотеки и имя функции. Затем функцию из DLL можно вызывать, как обычно. Например:

Обратите внимание на приведение указателя к ссылке на тип FARPROC. FARPROC - это указатель на функцию, которая не принимает параметров и возвращает int. Именно такой указатель возвращает функция GetProcAddress. Приведение типа необходимо, чтобы умиротворить компилятор, который строго следит за соответствием типов параметров оператора присваивания. Альтернативный подход заключается в использовании оператора typedef с последующим приведением значения, возвращаемого GetProcAddress, к указателю на функцию с нужным прототипом.

Доступ к переменным

Хотя это не всегда очевидно из документации, получить указатель на переменную из DLL можно, используя все ту же функцию GetProcAddress. В нашем примере это выглядит так.

Использование классов

Сразу замечу, что в общем случае не рекомендуется размещать классы в библиотеках, подключаемых явно. Приемлемым можно считать только подход, который исповедует COM, при котором объекты класса создаются и разрушаются внутри DLL (для этого используются экспортируемые глобальные функции), а сам класс содержит исключительно виртуальные методы.

Однако предположим, что у нас нет доступа к исходным кодам библиотеки, содержащей класс, а использование других типов подключения DLL по каким-то причинам невозможно. Классом удастся воспользоваться и в этом случае, но для достижения цели придется проделать дополнительную работу.

Сначала задумаемся, почему объекты класса из явно подключаемой библиотеки нельзя использовать, как обычно. Дело в том, что при создании объекта класса компилятор генерирует вызов его конструктора. Но линкер не может разрешить этот вызов, поскольку адрес конструктора будет известен только в процессе выполнения программы. В результате сборка программы закончится неудачно. Такая же проблема возникает при вызове невиртуальных методов класса. С другой стороны, вызов виртуальных методов возможен, так как он осуществляется через таблицу виртуальных функций (vtable). Так, следующий фрагмент откомпилируется и слинкуется нормально (хотя, конечно, вызовет ошибку в процессе выполнения):

Приведенные выше рассуждения подсказывают решение проблемы. Коль скоро неявный вызов конструктра невозможен, мы можем вызвать его вручную, предварительно получив его адрес и выделив память под объект. Затем можно вызывать невиртуальные методы, получая их адреса с помощью GetProcAddress. Виртуальные методы можно вызывать, как обычно. Кроме того, необходимо не забыть вручную вызвать деструктор объекта, прежде чем выделенная для него память будет освобождена.

Продемонстрирую все сказанное на примере. Сначала мы выделяем память для объекта и вызываем для него конструктор. Память можно выделить как на стеке, так и в куче (с помощью оператора new). Рассмотрим оба варианта.

Обратите внимание на использование операторов .* и ->* для вызова функции-члена класса по указателю на нее. Этими операторами мы будем пользоваться и дальше.

ПРИМЕЧАНИЕ

Как правило, имена функций, экспортируемых из DLL, искажаются линкером. Поэтому вместо понятного имени, такого как "Constructor", получается совершенно нечитабельное имя вида "??0Class@@QAE@XZ". В рассматриваемом примере я назначил переменным и функциям нормальные имена при помощи def-файла следующего содержания:

Невиртуальные методы класса вызываются так же, как и конструктор, например:

Виртуальные методы вызываются непосредственно (как это делается для обычных классов). Хотя DLL и экспортирует их, явно получать их адреса с помощью GetProcAddress не требуется. Отсюда следует вывод: если все методы класса являются виртуальными, использование объектов класса из явно подключаемой библиотеки практически ничем не отличается от использования объектов любого другого класса. Разница только в том, что конструктор и деструктор для таких объектов придется вызывать вручную.

В нашем примере виртуальная функция вызывается так.

После того, как работа с объектом завершена, его нужно уничтожить, вызвав для него деструктор. Если объект был создан на стеке, деструктор необходимо вызвать до его выхода из области видимости, иначе возможны неприятные последствия (например, утечки памяти). Если объект был распределен при помощи new, его необходимо уничтожить перед вызовом delete. В нашем примере это выглядит так.

До сих пор я ничего не говорил о статических переменных и функциях класса. Дело в том, что они практически ни чем не отличаются от обычных функций и переменных. Поэтому к ним можно обращаться, используя уже известные нам методы. Например:

Выгрузка библиотеки

После того, как работа с библиотекой закончена, ее можно выгрузить, чтобы она не занимала системные ресурсы. Для этого используется функция FreeLibrary, которой следует передать дескриптор освобождаемой библиотеки. В нашем примере это выглядит так.

Отложенная загрузка

Использование отложенной загрузки

Вот и все. Теперь можно использовать функции и классы DLL прозрачно, как и в случае с неявным подключением. Единственная проблема возникает с переменными: их невозможно использовать напрямую. Дело в том, что при обращении к одной из функций в DLL мы на самом деле вызываем функцию __delayLoadHelper, которая и выполняет загрузку DLL (если она еще не загружена), затем получает адрес функции с помощью GetProcAddress и перенаправляет все последующие вызовы функции по этому адресу. Но при обращении к переменной вызова функции не происходит, а значит использовать __delayLoadHelper не удается.

Проблема решается путем явного использования GetProcAddress при работе с переменными. Если DLL еще не загружена, ее придется загрузить явно с помощью LoadLibrary. Но если мы уже обращались к ее функциям и точно знаем, что она находится в памяти, мы можем получить ее дескриптор с помощью функции GetModuleHandle, которой необходимо передать имя DLL. В нашем примере это выглядит так.

Выгрузка библиотеки

Итак, мы установили, что при использовании отложенной загрузки DLL грузится в память, когда происходит обращение к одной из ее функций. Но в последствии нам может потребоваться выгрузить ее, чтобы не занимать зря системные ресурсы. Специально для этого предназначена функция __FUnloadDelayLoadedDLL, объявленная в файле Delayimp.h. Если вы планируете использовать ее, вам нужно задать еще один ключ линкера - /DELAY:UNLOAD. Например:

Имя, которое вы передаете функции __FUnloadDelayLoadedDLL, должно в точности соответствовать имени, заданному в ключе /DELAYLOAD. Если, к примеру, передать ей "MYLIB.DLL" или "mylib.dll", библиотека останется в памяти.

ПРЕДУПРЕЖДЕНИЕ

Не используйте FreeLibrary, чтобы выгрузить DLL с отложенной загрузкой.

Обработка исключений

Как я уже говорил, в случае ошибки функция __delayLoadHelper возбуждает исключение. Если нужная DLL не обнаружена, возбуждается исключение с кодом VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND). Если в DLL не обнаружена требуемая функция, исключение будет иметь код VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND).

ПРИМЕЧАНИЕ

VcppException - это макрос, который используется для формирования кода ошибки в подсистеме Visual C++. Первый параметр задает "степень серьезности" ошибки, а второй - код исключения.

И то, и другое исключение можно обработать, используя механизм структурной обработки исключений. Для этого нужно написать фильтр , реагирующий на приведенные коды исключения, а также обработчик исключения. В простейшем случае они могут выглядеть так.

Написанный вами фильтр исключений может также получить дополнительную информацию с помощью функции GetExceptionInformation. Эта функция возвращает указатель на структуру EXCEPTION_POINTERS. В ней содержится поле ExceptionRecord - указатель на структуру EXCEPTION_RECORD. А структура EXCEPTION_RECORD в свою очередь содержит поле ExceptionInformation[0], в которое __delayLoadHelper помещает указатель на структуру DelayLoadInfo, содержащую дополнительную информацию. Эта структура объявлена следующим образом (файл Delayimp.h).

В частности, вы можете извлечь из нее имя DLL (поле szDll), а также имя или порядковый номер функции, вызов которой привел к исключению (поле dlp).

Функции-ловушки

Функции-ловушки должны иметь следующий прототип:

Первый параметр функции содержит код уведомления или ошибки, второй - указатель на уже знакомую нам структуру DelayLoadInfo. Все возможные коды уведомления описаны в файле Delayimp.h при помощи следующего перечисления:

В качестве примера приведу текст функции-ловушки, которая подменяет вызов функции SomeFunc на вызов функции YetAnotherFunc.

Что такое dll файл?

dll файл

Какие dll файлы задействуются программами прямо сейчас, можно узнать, запустив, к примеру, утилиты Autoruns for Windows , пробежавшись по вкладкам программы:

dll файл для программы

Как работает dll файл?

Любая устанавливаемая в Windows программа всегда использует либо свои немногочисленные или имеющиеся в системе dll-ки. Программа обычно загружает свою dll-ку во время автозагрузки через специальную библиотеку Win32 API LoadLibrary или по сигналу с другого dll-файла. Обычно это выглядит так:

К СВЕДЕНИЮ

Куда они исчезают, или почему в системе отсутствует dll файл ?

перерегистрация файлов dll

попытка снять с регистрации файл для последующей правильной его установки в реестре провалилась

Почему нельзя просто его скачать?

решения не обнаружилось: всё равно ошибка и ничего не работает. Почему? Ответ для внимательных очевиден: вы никогда не задумывались, что Windows обновляет прежде всего ? Да-да, скачанный вами файл просто морально устарел , и вам в любом случае придётся искать уже обновлённую его версию. Вобщем, действуйте в этом варианте на свой страх и риск.

Прокатывает не всегда, ибо это инструмент общего действия. Однако попробовать стоит. Внутри побитого файла она ничего изменить не сможет, но системные файлы могут быть подменены. Однако, если задет файл конкретной программы, утилита отрапортует, что всё хорошо и захлопнется. Оставив вас ни с чем.

на компьютере отсутствует .

Советов здесь немного, и главный из них должен решаться ещё на этапе установки машины. Старайтесь не смешивать типы файловых систем самой машины и носителей для них и не разносите по разным томам папку с программой и носителями для неё.

Читайте также: