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

时间:2012-04-27 15:26:07

标签: delphi winapi dll 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.

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

  

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

var
   InternalThemeParkServices: IThemeParkServices;

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

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

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

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

finalization

是德尔福道德等同于DLL_PROCESS_DETACHThere all kinds of things我是should not be doing during DLL_PROCESS_DETACH when the process is terminating(例如CoCreateInstance)。

我知道Embarcadero使用:

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被连接和分离,我每次都会泄漏。

我真正想要的是Delphi在 finalization / ExitProcess之前运行DllMain(DLL_PROCESS_DETACH)。这可能吗?

Bonus Chatter

@pa已解密the Delphi application shutdown scheme

  

关闭的层次结构如下

  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是执行此操作的人。

2 个答案:

答案 0 :(得分:6)

要知道在调用ExitProcess之后是否在DLL_PROCESS_DETACH期间调用,您可以为库编写初始化代码,以便在从主程序调用{​​{1}}时执行代码。如果已经调用FreeLibrary,则'lpReserved'参数将为'1',否则为'0':

ExitProcess


来自DllMain entry point

  

lpReserved参数指示是否正在卸载DLL   作为FreeLibrary调用的结果,无法加载或处理   终止。

答案 1 :(得分:2)

  

真正想要的是Delphi在finalization之前运行DllMain(DLL_PROCESS_DETACH)块。这可能吗?

不,这是不可能的。

如果您需要执行在DllMain(DLL_PROCESS_DETACH)期间无法执行的关闭操作,则需要向DLL中添加导出的函数以完成最终化。然后,您应该要求DLL的客户端在卸载DLL之前调用此函数。这与CoInitialize / CoUninitialize相同。