Определение подходящего метода связывания
Существует два типа связывания: явное и неявное.
Неявное связывание
Неявное связывание выполняется, когда код приложения вызывает экспортированную функцию DLL.Когда создается или компилируется исходный код для вызова исполняемого файла, вызов функции DLL производит внешнюю ссылку на функцию в коде объекта.Чтобы разрешить эту внешнюю ссылку, приложение должно быть связано с библиотекой импорта (LIB-файл), предоставленной создателем библиотеки DLL.
Библиотека импорта содержит код только для загрузки библиотеки DLL и реализации вызовов функций в библиотеке DLL.При нахождении внешней функции в библиотеке импорта компоновщик уведомляется о том, что код для данной функции находится в библиотеке DLL.Чтобы разрешить внешние ссылки на библиотеки DLL, компоновщик просто добавляет информацию в исполняемый файл, который сообщает системе, где найти код DLL при запуске процесса.
Когда система запускает программу, содержащую динамически связанные ссылки, она использует информацию исполняемого файла программы для определения расположения необходимых библиотек DLL.Если системе не удается найти библиотеку DLL, происходит завершение процесса и отображается диалоговое окно об ошибке.В противном случае система вносит модули библиотеки DLL в адресное пространство процесса.
Если какая-либо библиотека DLL имеет функцию точки входа (для кода инициализации и завершения), операционная система вызывает функцию.Один из параметров, переданных в функцию точки входа, указывает код, который указывает, что библиотека DLL присоединяется к процессу.Если функция точки входа не возвращает значение TRUE, система завершает процесс и выводит сообщение об ошибке.
Наконец, система изменяет исполняемый код процесса, чтобы предоставить начальные адреса для функций DLL.
Подобно другим кодам программы, код библиотеки DLL вносится в адресное пространство процесса при его запуске и загружается в память только в случае необходимости.В результате, атрибуты кода PRELOAD и LOADONCALL, используемые DEF-файлами для контроля загрузки в предыдущих версиях Windows, больше не требуются.
Явное связывание
Большинство приложений используют неявное связывание, так как этот способ является наиболее простым.Однако бывают случаи, когда просто необходимо применить явное связывание.Причины использования явного связывания следующие.
Приложение не имеет информации об имени библиотеки DLL, которую необходимо будет загрузить, до начала выполнения.Например, приложению могут потребоваться имя библиотеки DLL и экспортированные функции из файла конфигурации.
Операционная система завершает процесс, использующий неявное связывание, если при запуске процесса не удалось найти библиотеку DLL.Процесс, использующий явное связывание, не завершается в данной ситуации и может попытаться продолжить выполнение после ошибки.Например, процесс может уведомить пользователя об ошибке и запросить у него другой путь к библиотеке DLL.
Процесс, использующий неявное связывание, также завершается, если в одной из библиотек DLL, с которой он связан, произошел сбой в функции DllMain.Процесс, использующий явное связывание, в таком случае не завершается.
Приложение, которое неявным образом связано со многими библиотеками DLL, может запускаться с промедлением, поскольку при загрузке приложения Windows загружает все библиотеки DLL.Чтобы улучшить выполнение запуска, приложение может неявным образом связываться с библиотеками DLL, которые требуются в первую очередь после загрузки, и отложить явное связывание с другими библиотеками до момента, когда в них будет необходимость.
Явное связывание исключает необходимость связывания приложения с библиотекой импорта.Если изменения в библиотеке DLL приводят к изменению порядковых номеров экспорта, тогда приложениям, использующим явное связывание, не приходится выполнять повторное связывание (предполагается, что они вызывают GetProcAddress с именем функции, а не порядковым номером), в то время как приложения, использующие неявное связывание, должны выполнить повторное связывание с новой библиотекой импорта.
При использовании явного связывания необходимо учитывать следующие моменты.
Если библиотека DLL имеет функцию точки входа DllMain, операционная система вызывает функцию в контексте потока, вызвавшего LoadLibrary.Функция точки входа не вызывается, если библиотека DLL уже присоединена к процессу в результате предыдущего вызова функции LoadLibrary, за которым не последовал вызов функции FreeLibrary.Явное связывание может привести к неполадкам, если библиотека DLL использует функцию DllMain для инициализации каждого потока процесса, поскольку потоки, существующие при вызове LoadLibrary (или AfxLoadLibrary), не смогут инициализироваться.
Если в качестве статических данных библиотека DLL объявляет __declspec(thread), это может привести к сбою защиты при использовании явного связывания.После загрузки библиотеки DLL с помощью LoadLibrary, происходит сбой защиты независимо от того, когда код ссылается на эти данные(статические данные включают в себя глобальные и локальные статические элементы). Поэтому при создании библиотеки DLL необходимо или избегать использования локальной памяти потока, или уведомить пользователей библиотеки о потенциальных ошибках (в случае если они попытаются произвести динамическую загрузку).