delphi - 使用 GdiPlus 卸载 DLL 时程序挂起

标签 delphi dll gdi+

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

我跟踪问题到 GdiPlus.pas 单元完成部分,该部分调用 GdiPlusShutdown ,但永远不会返回。

如何避免这种僵局?

最佳答案

GdiplusStartup 的文档函数是这样说的:

Do not call GdiplusStartup or GdiplusShutdown in DllMain or in any function that is called by DllMain. If you want to create a DLL that uses GDI+, you should use one of the following techniques to initialize GDI+:

  • Require your clients to call GdiplusStartup before they call the functions in your DLL and to call GdiplusShutdown when they have finished using your DLL.
  • Export your own startup function that calls GdiplusStartup and your own shutdown function that calls GdiplusShutdown. Require your clients to call your startup function before they call other functions in your DLL and to call your shutdown function when they have finished using your DLL.
  • Call GdiplusStartup and GdiplusShutdown in each of your functions that make GDI+ calls.

通过将此 Delphi GdiPlus 库编译成 DLL,您就违反了 GdiplusStartup 的此规则。和GdiplusShutdown 。这些函数在单元 initialization 中调用和finalization部分,分别。对于图书馆项目,代码位于 initializationfinalization单元的各个部分从 DllMain 开始执行.

看来您使用的 GdiPlus 库从未打算从库中使用。但作为一般规则,在编写库代码时,您应该注意 DllMain 周围的限制。并确保您将代码放置在 initialization 中和finalization部分尊重这一点。我认为这个 GdiPlus 库在这方面失败了。

作为对比,看看 Delphi RTL 的 WinApi.GDIPOBJ 中的代码单位:

initialization
  if not IsLibrary then
  begin
    // Initialize StartupInput structure
    StartupInput.DebugEventCallback := nil;
    StartupInput.SuppressBackgroundThread := False;
    StartupInput.SuppressExternalCodecs   := False;
    StartupInput.GdiplusVersion := 1;

    GdiplusStartup(gdiplusToken, @StartupInput, nil);
  end;

finalization
  if not IsLibrary then
  begin
    if Assigned(GenericSansSerifFontFamily) then
      GenericSansSerifFontFamily.Free;
    if Assigned(GenericSerifFontFamily) then
      GenericSerifFontFamily.Free;
    if Assigned(GenericMonospaceFontFamily) then
      GenericMonospaceFontFamily.Free;
    if Assigned(GenericTypographicStringFormatBuffer) then
      GenericTypographicStringFormatBuffer.free;
    if Assigned(GenericDefaultStringFormatBuffer) then
      GenericDefaultStringFormatBuffer.Free;

    GdiplusShutdown(gdiplusToken);
  end;

此代码通过确保它不会调用 GdiplusStartup 来遵守规则。和GdiplusShutdown来自DllMain 。相反,它将责任留给任何使用 WinApi.GDIPOBJ 的库的作者。确保GdiplusStartupGdiplusShutdown在适当的时间被调用。

如果我是你,我会选择上面列出的三个要点选项之一。第三个选项不太实用,但前两个是不错的选择。如果是我,我会选择第一个选项并修改 initializationfinalization代码在你的 GdiPlus库看起来更像 WinApi.GDIPOBJ 中的库.

关于delphi - 使用 GdiPlus 卸载 DLL 时程序挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34871348/

相关文章:

java - 使用JNA将 native C函数映射到Java接口(interface)时出现指针问题

.net - FillRectangle 和 DrawRectangle 的像素行为

c# - TextureBrush 内存不足异常

delphi - 在当前用户 session 中从服务执行应用程序

performance - 字符串文字的 ResourceString VS Const

dll - 如何决定何时实现DLL?

c# - 绘制图像时 : System. Runtime.InteropServices.ExternalException: GDI 中发生一般性错误

forms - 当表单没有焦点时,如何防止表单处理热键?

delphi - delphi如何转换ModalResult属性?

delphi - 从 Delphi 代码调用 Visual C++ DLL 的函数