使用GdiPlus卸载DLL时程序挂起 [英] Program hangs when unloading a DLL making use of GdiPlus

查看:155
本文介绍了使用GdiPlus卸载DLL时程序挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have an application which load a DLL that makes use of Delphi GDI+ Library. This application hangs when it unload the DLL (Calling FreeLibrary).

我将问题追溯到GdiPlus.pas单元最终确定部分,该部分调用了永不返回的GdiPlusShutdown。

I tracked the issue down to GdiPlus.pas unit finalization section which calls GdiPlusShutdown which never returns.

如何避免这种僵局?

推荐答案

GdiplusStartup 函数表示:

The documentation for the GdiplusStartup function says this:


请勿在其中调用 GdiplusStartup GdiplusShutdown DllMain 或在 DllMain 调用的任何
函数中。如果要创建
使用GDI +的DLL,则应使用以下技术之一来
初始化GDI +:

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+:


  • 要求您的客户端在调用DLL中的函数之前先调用 GdiplusStartup ,并在有权限时调用 GdiplusShutdown
    使用完DLL。

  • 导出自己的调用 GdiplusStartup 的启动函数和自己的调用<$的关机函数c $ c> GdiplusShutdown 。要求您的客户
    调用启动函数,然后再调用
    DLL中的其他函数,并在他们使用完
    您的DLL后调用关机函数。

  • 在每个进行GDI +调用的函数中,分别调用
  • 调用 GdiplusStartup GdiplusShutdown

  • 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 。这些函数分别在单元初始化 finalization 部分中调用。对于图书馆项目,单元的初始化完成部分中的代码从执行DllMain

By compiling this Delphi GdiPlus library into a DLL you are breaking this rule for both GdiplusStartup and GdiplusShutdown. These functions are called in unit initialization and finalization sections, respectively. And for library projects, code in the initialization and finalization sections of a unit is executed from DllMain.

似乎您使用的GdiPlus库从未打算从库中使用。但是作为一般规则,编写库代码时,应注意 DllMain 的限制,并确保放置在初始化中的代码最终化部分对此表示尊重。我认为该GdiPlus库在这方面失败了。

It seems that the GdiPlus library that you use was never intended to be used from a library. But as a general rule, when writing library code, you should be aware of the restrictions around DllMain and make sure that code that you place in initialization and finalization sections respects that. I think that this GdiPlus library fails in that regard.

通过对比,请看一下Delphi RTL的 WinApi.GDIPOBJ中的代码。 单位:

By way of contrast, have a look at the code in the Delphi RTL's WinApi.GDIPOBJ unit:

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 确保 GdiplusStartup GdiplusShutdown 在适当的时间被调用。

This code respects the rules by making sure that it does not call GdiplusStartup and GdiplusShutdown from DllMain. Instead it leaves the onus on the author of any library that uses WinApi.GDIPOBJ to make sure that GdiplusStartup and GdiplusShutdown are called at appropriate times.

如果我是我,我会选择上面列出的三个项目之一。这些选项中的第三个选项不是很实用,但是前两个选项是不错的选择。是我吗,我会选择第一个选项,并在您的<$ c $中修改初始化完成化代码c> GdiPlus 库看起来更像在 WinApi.GDIPOBJ 中找到的库。

If I were you I would pick one of the three bullet point options listed above. The third of these options is not very practical, but the first two are good choices. Were it me, I would opt for the first option and modify the initialization and finalization code in your GdiPlus library to look more like that found in WinApi.GDIPOBJ.

这篇关于使用GdiPlus卸载DLL时程序挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆