4

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

Delphiの道徳的同等物ですDLL_PROCESS_DETACHプロセスが終了している間、がしてはいけないことたくさんあります(例)。 DLL_PROCESS_DETACH 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ブロックを実行することです。これは可能ですか? ExitProcessDllMain(DLL_PROCESS_DETACH)

ボーナスチャッター

@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

-の呼び出しにDLLがアンロードされますExitProcess。これは、Windowsがそれを実行するためです。

4

2 に答える 2

6

ExitProcess が呼び出された後の DLL_PROCESS_DETACH 中に呼び出されているかどうかを確認するには、ライブラリの初期化コードを記述してFreeLibrary、メイン プログラムから が呼び出されたときにコードが実行されるようにします。「lpReserved」パラメータはExitProcess、すでに呼び出されている場合は「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 パラメーターは、FreeLibrary 呼び出し、読み込みの失敗、またはプロセスの終了の結果として DLL がアンロードされているかどうかを示します。

于 2012-04-27T17:27:55.143 に答える
2

私が本当に望んでいるのは、Delphi が のfinalization前にそのブロックを実行することDllMain(DLL_PROCESS_DETACH)です。これは可能ですか?

いいえ、できません。

シャットダウン中に実行できないアクションを実行する必要がある場合DllMain(DLL_PROCESS_DETACH)は、ファイナライズを実行するエクスポートされた関数を DLL に追加する必要があります。次に、DLL をアンロードする前に、DLL のクライアントにこの関数を呼び出すように要求する必要があります。CoInitializeこれは/と同じパターンCoUninitializeです。

于 2012-04-27T15:46:29.120 に答える