При разработке приложений на Delphi, использование сторонних библиотек может привести к непредвиденным проблемам, в том числе и в контексте работы с компонентами GDI+ после выгрузки DLL. Рассмотрим проблему, которая заключается в зависании программы при выгрузке DLL, использующей библиотеку GDI+ для Delphi.
Описание проблемы
Программа, использующая библиотеку GDI+ для Delphi, замирает при попытке выгрузить DLL, которая использует эту библиотеку. Проблема связана с финализацией модуля GdiPlus.pas, в частности, с функцией GdiPlusShutdown, которая не возвращает управление.
Контекст и решение проблемы
В контексте использования GDI+ в DLL, важно понимать, что функции GdiplusStartup и GdiplusShutdown не предназначены для вызова из DllMain или функций, вызываемых DllMain. Это требование документации GDI+ необходимо учитывать при разработке библиотеки.
Автор вопроса обнаружил, что при выгрузке DLL, финализация модуля GdiPlus.pas приводит к вызову GdiPlusShutdown, который никогда не завершается, что и вызывает зависание программы.
Подтвержденный ответ
Для решения проблемы был предложен следующий подход:
В модуле GdiPlus.pas были добавлены два новых публичных процедуры: InitializeForDll и FinalizeForDll.
В разделах инициализации и финализации модуля добавлены проверки на то, не является ли текущий модуль библиотекой (IsLibrary).
Функции Initialize и Finalize были изменены таким образом, чтобы в случае, если модуль является библиотекой, вызывались новые процедуры InitializeForDll и FinalizeForDll.
В DLL были экспортированы процедуры InitializeForDll и FinalizeForDll, которые должны быть вызваны хост-приложением после загрузки DLL и перед её выгрузкой.
Пример кода
// В интерфейсе модуля GdiPlus.pas
var
procedure InitializeForDll;
procedure FinalizeForDll;
// В реализации модуля GdiPlus.pas
procedure InitializeForDll;
begin
Initialize;
end;
procedure FinalizeForDll;
begin
Finalize;
end;
// В разделе инициализации и финализации модуля
Initialization
if not IsLibrary then
InitializeForDll;
Finalization
if not IsLibrary then
FinalizeForDll;
// В DLL, экспорт процедур
procedure InitializeForDll; stdcall; external;
procedure FinalizeForDll; stdcall; external;
Альтернативный ответ
Дополнительно было отмечено, что документация GDI+ ясно указывает на необходимость избегать вызова функций GdiplusStartup и GdiplusShutdown из DllMain. В качестве альтернативного решения предлагается выбрать один из предложенных в документации вариантов инициализации и финализации GDI+ в DLL.
Заключение
При использовании GDI+ в библиотеках, важно соблюдать правила, установленные документацией GDI+, особенно касающиеся вызова функций инициализации и финализации. Приведенные выше изменения позволяют корректно работать с GDI+ в среде DLL, предотвращая зависание программы при выгрузке библиотеки.
Этот подход можно использовать как шаблон для решения подобных проблем в будущем, учитывая специфику работы с компонентами GDI+ в среде Delphi.
Проблема связана с неправильной финализацией модуля GDI+ при выгрузке DLL в приложении на Delphi, что приводит к зависанию программы.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS