使用GdiPlus卸载DLL时程序挂起 [英] Program hangs when unloading a DLL making use of GdiPlus
问题描述
我有一个应用程序,该应用程序加载了一个使用 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
orGdiplusShutdown
inDllMain
or in any function that is called byDllMain
. 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后调用关机函数。 - 调用
GdiplusStartup
和GdiplusShutdown
。
在每个进行GDI +调用的函数中,分别调用
- Require your clients to call
GdiplusStartup
before they call the functions in your DLL and to callGdiplusShutdown
when they have finished using your DLL. - Export your own startup function that calls
GdiplusStartup
and your own shutdown function that callsGdiplusShutdown
. 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
andGdiplusShutdown
in each of your functions that make GDI+ calls.
通过将此Delphi GdiPlus库编译为DLL,您将同时破坏 GdiplusStartup $的规则c $ c>和
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屋!