我在Delphi中有一个单元(可以选择(提供单个全局对象:
var
InternalThemeParkServices: TThemeParkServices;
function ThemeParkServices: TThemeParkServices;
begin
if InternalThemeParkServices= nil then
InternalThemeParkServices := TThemeParkServices.Create();
Result := InternalThemeParkServices ;
end;
...
initialization
finalization
FreeAndNil(InternalThemeServices);
end.
我在进程关闭期间摧毁了自己。
注意:另一个代码变体是:
var InternalThemeParkServices: IThemeParkServices; function ThemeParkServices: TThemeParkServices; begin if InternalThemeParkServices= nil then InternalThemeParkServices := TThemeParkServices.Create(); Result := InternalThemeParkServices ; end;
接口变量在 程序关闭期间引用计数为零
当我的对象不再使用时(即在其destructor
期间(,我调用调用各种 WinAPI 函数。
问题是,如果有人从 DLL(我无法控制的东西(中使用我的类,那么在以下期间调用的任何内容:
finalization
是德尔菲道德等价物DLL_PROCESS_DETACH
.在进程终止DLL_PROCESS_DETACH
期间,我不应该做各种各样的事情(例如 CoCreateInstance
(。
我知道内河码头使用:
initialization
if not IsLibrary then
begin
...
我也许可以适应,将我的代码从:
var
InternalThemeParkServices: IThemeParkServices;
(使用隐式清理(,以:
var
InternalThemeParkServices: IThemeParkServices;
...
finalization
if IsLibrary then
Pointer(InternalThemeParkServices) := nil; //defeat reference counting and let the object leak
end;
并让它泄漏。
但这是最好的解决方案吗? 我认为这意味着如果运行我的代码的 DLL 被卸载(但不是在进程关闭期间(,我将泄漏内存。如果dll是连接和分离的,我每次都会泄漏。
我真正想要的是德尔福在ExitProcess
/DllMain(DLL_PROCESS_DETACH)
之前运行其finalization
块。这可能吗?
奖金喋喋不休
@pa破译了德尔福应用程序关闭方案:
关机的层次结构如下
Application.Terminate() performs some unidentified housekeeping of application calls Halt() Halt() calls ExitProc if set alerts the user in case of runtime error get rid of PackageLoad call contexts that might be pending finalize all units clear all exception handlers call ExitprocessProc if set and finally, call ExitProcess() from 'kernel32.dll' ExitProcess() unloads all DLLs uses TerminateProcess() to kill the process
在调用ExitProcess
后卸载DLL - 因为Windows是执行此操作的人。
要判断在调用 ExitProcess 后DLL_PROCESS_DETACH期间是否调用了您,您可以为库编写初始化代码,以便在从主程序调用FreeLibrary
时执行代码。如果已经调用ExitProcess
则"lpReserved"参数将为"1",否则为"0":
..
var
SaveDllProcEx: TDllProcEx;
procedure DllMainEx(Reason: Integer; Reserved: Integer);
begin
if (Reason = DLL_PROCESS_DETACH) and (Reserved = 0) then
// Main app is still running, cleanup.
if Assigned(SaveDllProcEx) then
SaveDllProcEx(Reason, Reserved);
end;
initialization
if IsLibrary then begin
SaveDllProcEx := DllProcEx;
DllProcEx := @DllMainEx;
end;
从 DllMain 入口点:
lpReserved 参数指示是否正在卸载 DLL 由于 FreeLibrary 调用、加载或处理失败 终止。
我真正想要的是德尔福在
DllMain(DLL_PROCESS_DETACH)
之前运行其finalization
块。这可能吗?
不,这是不可能的。
如果需要执行在DllMain(DLL_PROCESS_DETACH)
期间无法执行的关闭操作,则需要向 DLL 添加一个导出的函数,以执行定稿。然后,应要求 DLL 的客户端在卸载 DLL 之前调用此函数。这与 CoInitialize
/CoUninitialize
的模式相同。