在调用ExitProcess之后,如何判断我是否在DLL_PROCESS_DETACH期间被调用?

Ian*_*oyd 4 delphi dll winapi process delphi-5

我在Delphi中有一个单元(可以选择)提供一个全局对象:

var
   InternalThemeParkServices: TThemeParkServices;

function ThemeParkServices: TThemeParkServices;
begin
   if InternalThemeParkServices= nil then
      InternalThemeParkServices := TThemeParkServices.Create();
   Result := InternalThemeParkServices ;
end;

...

initialization
finalization
   FreeAndNil(InternalThemeServices);
end.
Run Code Online (Sandbox Code Playgroud)

我在进程关闭期间摧毁了自己.

注意:另一个代码变体是:

var
   InternalThemeParkServices: IThemeParkServices;

function ThemeParkServices: TThemeParkServices;
begin
   if InternalThemeParkServices= nil then
      InternalThemeParkServices := TThemeParkServices.Create();
   Result := InternalThemeParkServices ;
end;
Run Code Online (Sandbox Code Playgroud)

当程序关闭期间引用计数变为零时,接口变量被隐式销毁

当我的对象不再使用时(即在其中destructor),我调用各种WinAPI函数.

问题是如果有人使用我的DLL中的类(我无法控制的东西),那么在以下期间调用的任何东西:

finalization
Run Code Online (Sandbox Code Playgroud)

是德尔福的道德等同物DLL_PROCESS_DETACH.目前各种各样的东西不应该这样做时 DLL_PROCESS_DETACH ,当进程终止(如CoCreateInstance).

我知道Embarcadero使用:

initialization 
   if not IsLibrary then
   begin
      ...
Run Code Online (Sandbox Code Playgroud)

我也许可以适应,改变我的代码:

var
   InternalThemeParkServices: IThemeParkServices;
Run Code Online (Sandbox Code Playgroud)

(使用隐式清理),以:

var
   InternalThemeParkServices: IThemeParkServices;
...
finalization
   if IsLibrary then
      Pointer(InternalThemeParkServices) := nil; //defeat reference counting and let the object leak
end;
Run Code Online (Sandbox Code Playgroud)

让它泄漏

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

真正想要的是Delphi /之前运行它的finalization块.这可能吗? ExitProcessDllMain(DLL_PROCESS_DETACH)

奖金Chatter

@pa破译了Delphi应用程序关闭方案:

关闭的层次结构如下

  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
Run Code Online (Sandbox Code Playgroud)

随着被卸载DLL文件后,将呼叫ExitProcess-因为Windows是谁做它的人.

Ser*_*yuz 6

要在调用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;
Run Code Online (Sandbox Code Playgroud)


DllMain入口点:

lpReserved参数指示由于FreeLibrary调用,加载失败或进程终止而导致DLL是否被卸载.