我有一个加载 DLL 的应用程序,该 DLL 使用 Delphi GDI+ Library 。该应用程序在卸载 DLL 时挂起(调用 FreeLibrary )。
我跟踪问题到 GdiPlus.pas 单元完成部分,该部分调用 GdiPlusShutdown ,但永远不会返回。
如何避免这种僵局?
最佳答案
GdiplusStartup
的文档函数是这样说的:
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+:
- 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
的此规则。和GdiplusShutdown
。这些函数在单元 initialization
中调用和finalization
部分,分别。对于图书馆项目,代码位于 initialization
和finalization
单元的各个部分从 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
的库的作者。确保GdiplusStartup
和GdiplusShutdown
在适当的时间被调用。
如果我是你,我会选择上面列出的三个要点选项之一。第三个选项不太实用,但前两个是不错的选择。如果是我,我会选择第一个选项并修改 initialization
和finalization
代码在你的 GdiPlus
库看起来更像 WinApi.GDIPOBJ
中的库.
关于delphi - 使用 GdiPlus 卸载 DLL 时程序挂起,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34871348/