Динамическое связывание периода выполнения
Когда прикладная программа вызывает функцию LoadLibrary или LoadLibraryEx, система пытается определить местонахождение DLL (подробности, смотрите в описаниях этих функций). Если поиск завершается успешно, система отображает модуль DLL в виртуальное адресное пространство процесса и увеличивает итоговое число ссылок. Если вызов LoadLibrary или LoadLibraryEx устанавливает DLL, код которой уже отображен в виртуальном адресном пространстве вызывающего процесса, функция просто возвращает дескриптор DLL и увеличивает итоговое число ссылок на DLL.
Обратите внимание! на то, что те две DLL, которые имеют одно и то же базовое имя и расширение файла, но находятся в различных каталогах, не рассматриваются, как одна и та же DLL. |
Система вызывает функцию точки входа в контексте потока, который вызвал LoadLibrary или LoadLibraryEx. Функция точки входа не вызывается, если DLL ранее была загружена процессом при помощи вызова LoadLibrary или LoadLibraryEx без соответствующего вызова функции FreeLibrary.
Если система не может найти DLL, или если функция точки входа возвращает значение ЛОЖЬ (FALSE), LoadLibrary или LoadLibraryEx возвращает значение ПУСТО (NULL). Если LoadLibrary или LoadLibraryEx завершаются успешно, то возвращает дескриптор модуля DLL. Процесс может использовать этот дескриптор, чтобы идентифицировать DLL при вызове функции GetProcAddress, FreeLibrary или FreeLibraryAndExitThread.
Функция GetModuleHandle возвращает дескриптор использованный в GetProcAddress, FreeLibrary или FreeLibraryAndExitThread. Функция GetModuleHandle завершается успешно, только в том случае, если модуль DLL уже отображен в адресное пространство процесса выполняемым при загрузке связыванием или предыдущим вызовом LoadLibrary или LoadLibraryEx. В отличие от LoadLibrary или LoadLibraryEx, GetModuleHandle не увеличивает итоговое число ссылок на модули. Функция GetModuleFileName извлекает полный путь к модулю, связанном с дескриптором, возвращенным GetModuleHandle, LoadLibrary или LoadLibraryEx.
Процесс может использовать функцию GetProcAddress, чтобы получить адрес экспортируемой функции в DLL, используя дескриптор модуля DLL, возвращенного LoadLibrary или LoadLibraryEx, GetModuleHandle.
Когда модуль DLL - больше не нужен, процесс может вызвать FreeLibrary или FreeLibraryAndExitThread. Эти функции уменьшают итоговое число ссылок на модуль и отменяют отображение кода DLL в виртуальное адресное пространство процесса, если итоговое число ссылок на неё равняется нулю.
Динамическое связывание периода выполнения дает возможность процессу продолжить управление и тогда даже, когда DLL не доступна. Процесс может тогда использовать альтернативный метод, чтобы выполнить свою цель. Например, если процесс не в состоянии определить местонахождение какой-то DLL, он может сделать попытку использовать другую библиотеку или может уведомить пользователя об ошибке. Если пользователь может предоставить полный путь к отсутствующей DLL, процесс может использовать эту информацию, чтобы загрузить DLL даже при том, что он этого не делает при обычном определении пути поиска. Эта ситуация противоположна ситуации с выполняемым при загрузке связыванием, в котором система просто заканчивает работу, процесса, если не может найти DLL.
Динамическое связывание периода выполнения может породить проблемы, если DLL использует функцию DllMain, чтобы осуществить инициализацию каждого потока процесса, потому что точка входа не вызывается для потоков, которые существовали до вызова LoadLibrary или LoadLibraryEx. Пример, показывающий, как иметь дело с этой проблемой, см. в статье Использование локальной памяти потока (TLS) в динамически подключаемой библиотеке (DLL).