使用GdiPlus卸载DLL时程序挂起

fpi*_*tte 5 delphi dll gdi+

我有一个应用程序,它加载了一个使用Delphi GDI + Library的DLL .该应用程序在卸载DLL(Calling FreeLibrary)时挂起.

我将问题跟踪到GdiPlus.pas单元终结部分,该部分调用GdiPlusShutdown,它永远不会返回.

如何避免这种僵局?

fpi*_*tte 3

GdiPlusShutdown(和 GdiPlusStartup 顺便说一句)不能从 DllMain 调用,但当调用 FreeLibrary 时,DllMain 由 Windows 和 Delphi 运行时调用:Delphi 调用 DLL 使用的所有单元的终结部分,并且 GdiPlus 终结部分调用 GdiPlusShutdown (这在使用时完全可以)来自可执行文件)。与初始化部分类似的行为。

我通过在初始化和终结部分添加 IsLibrary 测试来解决此问题,以避免调用有问题的函数,还添加了两个公共过程 InitializeForDll 和 FinalizeForDll。通过这些微小的更改,DLL 能够导出调用 InitializeForDll 和 FinalizeForDll 的函数。这些导出的函数必须在加载 DLL 之后和卸载 DLL 之前由托管应用程序调用。

以下是我对 GdiPlus.pas 所做的更改:

在界面部分:

var
  procedure InitializeForDll;
  procedure FinalizeForDll;
Run Code Online (Sandbox Code Playgroud)

在实施部分:

procedure InitializeForDll;
begin
  Initialize;
end;

procedure FinalizeForDll;
begin
  Finalize;
end;
Run Code Online (Sandbox Code Playgroud)

还更新了初始化和终结部分,如下所示:

Initialization
  if not IsLibrary then
    Initialize;

Finalization
  if not IsLibrary then
    Finalize;
Run Code Online (Sandbox Code Playgroud)

在 DLL 中,我导出了这些函数:

procedure Initialize; stdcall;
begin
  GdiPlus.InitializeForDll;
end;

procedure Finalize; stdcall;
begin
  GdiPlus.FinalizeForDll;
end;
Run Code Online (Sandbox Code Playgroud)

Initialize 和 Finalize 由托管应用程序在调用 LoadLibrary 之后和调用 FreeLibrary (或任何将加载/卸载 DLL 的内容)之前调用。

我希望这会帮助其他人。顺便说一句:感谢Eric Bilsen提供Delphi GdiPlus 库

  • 这实际上只是故事的一部分。即使您进行了此更改,您仍然通过从初始化部分调用“GdiplusStartup”来违反规则。可能需要更深入地阅读文档。我试着把它写在我的答案中。 (2认同)