Delphi 我如何判断我是否';调用ExitProcess后,在DLL\u进程\u分离期间调用m?

Delphi 我如何判断我是否';调用ExitProcess后,在DLL\u进程\u分离期间调用m?,delphi,winapi,dll,process,delphi-5,Delphi,Winapi,Dll,Process,Delphi 5,我在Delphi中有一个单元(可以选择)提供单个全局对象: var InternalThemeParkServices: TThemeParkServices; function ThemeParkServices: TThemeParkServices; begin if InternalThemeParkServices= nil then InternalThemeParkServices := TThemeParkServices.Create(); Re

我在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;
接口变量在被调用时被隐式销毁 程序关闭期间,引用计数变为零

当我的对象不再使用时(即在其
析构函数期间),我调用各种WinAPI函数

问题是,如果有人使用DLL中的我的类(我无法控制的内容),则在以下过程中调用任何内容:

finalization
德尔福在道德上等同于。我是
DLL\u进程\u分离
(例如
CoCreateInstance

我知道Embarcadero使用:

initialization 
   if not IsLibrary then
   begin
      ...
我可能会对其进行调整,更改代码:

var
   InternalThemeParkServices: IThemeParkServices;
(使用隐式清理),以:

让它泄露出去

但这是最好的解决方案吗?我假设这意味着,如果运行我的代码的dll被卸载(但不是在进程关闭期间),我将泄漏内存。如果dll被附加和分离,我每次都会泄漏

我真正想要的是Delphi在退出进程之前运行它的
finalization
/
DllMain(DLL\u PROCESS\u DETACH)
。这可能吗

花言巧语 破译:

关机的层次结构如下所示

  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完成的

我真正想要的是Delphi在
DllMain(DLL\u进程\u分离)
之前运行它的
finalization
块。这可能吗

不,这是不可能的


如果需要执行在
DllMain(DLL\u PROCESS\u DETACH)
期间无法执行的关闭操作,则需要将导出的函数添加到DLL中,以形成最终结果。然后,您应该要求DLL的客户端在卸载DLL之前调用此函数。这与
CoInitialize
/
CoUninitialize

的模式相同。要知道在调用ExitProcess后,是否在DLL\u进程分离期间调用了您,您可以为库编写初始化代码,以便在从主程序调用
FreeLibrary
时执行代码。如果已调用
ExitProcess
,则“lpReserved”参数将为“1”,否则:

..
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;

发件人:

lpReserved参数指示是否正在卸载DLL 由于FreeLibrary调用、加载或处理失败 终止


一个使用一个单元的人,使用一个单元,使用一个单元,需要泄露该实现细节的实现细节的实现细节,这真是糟糕透了。特别是当可能没有人会从dll调用代码时。问题是my不在库中,而是在一个单元中。其他人可能会在他们的单元中使用我的代码。其他人可能会在他们的单元中使用该代码。然后有人可能会在DLL中使用该单元。严格地说,
TBase64
类不在dll中,它是代码文件中的帮助器类,同样地,
TStringList
也不在dll中。但是现在
TBase64
TStringList
t必须防止被dll调用。@Ian-如果在库中,可以在单元初始化中进行测试,如果在库中,则保存原始DllProcEx,然后将其分配给函数。在“DllMain”函数中,如果保存的DllProcEx不是nil,则调用它。这样可以保留初始化代码链。否则我看不出有任何问题。请更新您的代码示例以执行此操作,您将窃取您自己一个可接受的答案。
..
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;