Вопрос, поднятый в данной статье, касается проблемы "Loader Lock" (блокировки загрузчика), которая возникает при динамической загрузке DLL в основном приложении, использующем Windows.LoadLibrary. Проблема заключается в том, что приложение может зависнуть в процессе загрузки одной из таких DLL, и это может быть связано с общим кодовой базой, используемой в DLL. В процессе исследования было установлено, что проблема может быть вызвана некорректным использованием функций GetModuleHandle и GetProcAddress в начале работы DLL, что может привести к взаимоблокировке.
Описание проблемы
При динамической загрузке DLL через Windows.LoadLibrary в основном приложении на Delphi возникает проблема, известная как "Loader Lock". Это происходит, когда в процессе инициализации DLL выполняются операции, которые могут вызвать взаимоблокировку с другими DLL или системными функциями. В частности, использование функций GetModuleHandle и GetProcAddress в разделе begin...end в файле проекта DLL (project.dpr) может привести к таким проблемам, так как этот раздел фактически соответствует функции DllMain DLL.
Подтвержденный ответ
Для решения проблемы необходимо избегать вызова функций, которые могут привести к взаимоблокировке, в функции DllMain. В соответствии с рекомендациями Microsoft, в DllMain следует выполнять только простые задачи инициализации или завершения. Вызовы функций LoadLibrary или FreeLibrary в DllMain могут привести к созданию циклов зависимостей в порядке загрузки DLL, что и является причиной "Loader Lock".
Альтернативные шаги по устранению проблемы
Перемещение инициализации: Код, который выполняется функции GetModuleHandle и GetProcAddress, должен быть перемещен и выполнен после завершения загрузки DLL.
Использование централизованного реестра: Разработать механизм, который позволит регистрировать процедуры инициализации и завершения в центральном реестре, и вызывать их в нужные моменты времени.
Экспортирование функций для инициализации и завершения: В DLL должны быть экспортированы функции, которые потребители DLL смогут вызывать для инициализации и завершения работы DLL.
Изменение третьих сторонних библиотек: В случае, если третьи стороныние библиотеки не совместимы с использованием в DLL, следует рассмотреть возможность их изменения или переупаковки в пакеты.
Пример кода
program MyDLL;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
procedure Initialize;
begin
// Инициализация DLL
end;
procedure Finalize;
begin
// Завершение работы DLL
end;
exports
Initialize,
Finalize;
end.
Важные замечания
Важно понимать, что не все функции безопасно использовать в DllMain. Например, Microsoft предоставляет рекомендации, но не полный список безопасных функций.
Конвертация DLL в runtime пакеты или пакеты может помочь избежать некоторых проблем, связанных с дублированием кода и одновременным доступом к одиночным объектам.
В случае смешанного использования DLL от Delphi и не от Delphi, возможно, стоит рассмотреть статическую компоновку необходимых библиотек в основной исполняемый файл.
Заключение
Понимание механизма работы "Loader Lock" и правильное управление инициализацией и завершением работы DLL в Delphi может помочь избежать проблем с зависанием приложения. Следуя рекомендациям и альтернативным подходам, описанным в этой статье, разработчики могут устранить данную проблему и обеспечить стабильную работу своих приложений.
Проблема 'Loader Lock' в Delphi DLL связана с взаимоблокировкой при динамической загрузке из-за некорректного использования функций `GetModuleHandle` и `GetProcAddress` в процессе инициализации DLL.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.