Program MainDemo;

{$APPTYPE CONSOLE}

uses
  System,
  Borland.Delphi.Classes,
  Borland.Delphi.SysUtils,
  Borland.VCL.Graphics,
  System.Runtime.InteropServices,
  Borland.Win32.Windows, Borland.Win32.WinUtils;

type
  TFinalizeHWNDNotify = procedure of object;

  TDemoClass = class
  private
    FNotifies: TList;
  strict protected
    procedure Finalize; override;
    procedure CallNotifies;
  public
    procedure RegisterFinalizeNotify(Proc: TFinalizeHWNDNotify);
    procedure UnregisterFinalizeNotify(Proc: TFinalizeHWNDNotify);
  end;

  TDllWrapper = class
  private
    FDllName : String;
    FDll : HMODULE;
  public
    Constructor Create(const sDllName : String);
    procedure DoDllWorks;
    procedure DoCleanUp;
  end;

  TFooClass = class
  public
    procedure CallFoo;
  end;

{ TDemoClass }

var
  myClassObj : TDemoClass;
{ TDemoClass }

procedure TDemoClass.CallNotifies;
var
  I: Integer;
begin
  if Assigned(FNotifies) then
  begin
    for I := 0 to FNotifies.Count - 1 do
      TFinalizeHWNDNotify(FNotifies[I]);
    FreeAndNil(FNotifies);
  end;
end;

procedure TDemoClass.Finalize;
begin
  CallNotifies;
  inherited;
end;

procedure TDemoClass.RegisterFinalizeNotify(Proc: TFinalizeHWNDNotify);
begin
  if FNotifies = nil then
    FNotifies := TList.Create;
  FNotifies.Add(@Proc);
end;

procedure TDemoClass.UnregisterFinalizeNotify(Proc: TFinalizeHWNDNotify);
begin
  if Assigned(FNotifies) then
    FNotifies.Remove(@Proc);
end;

{ TFooClass }

procedure TFooClass.CallFoo;
begin
  Console.WriteLine('TFooClass is called at : ' + DateTimeToStr(Now));
end;

{ TDllWrapper }

constructor TDllWrapper.Create(const sDllName: String);
begin
  inherited Create;
  FDllName := sDllName;
  FDll := SafeLoadLibrary(sDllName);
end;

[DllImport('ntDll.dll', CharSet=CharSet.Ansi)]
procedure DoFinalize; external;

procedure TDllWrapper.DoCleanUp;
begin
  DoFinalize;
  FreeLibrary(FDll);
end;

[DllImport('ntDll.dll', CharSet=CharSet.Ansi)]
procedure DoInit; external;

procedure TDllWrapper.DoDllWorks;
begin
  DoInit;
end;

var
  iCount : Integer;
  mnHolder : TDemoClass;
  dll1 : TDllWrapper;
  fooObj : TFooClass;
begin
  mnHolder := TDemoClass.Create;

  dll1 := TDllWrapper.Create('ntdll.dll');

  mnHolder.RegisterFinalizeNotify(dll1.DoCleanUp);
  try
    dll1.DoDllWorks;
    Sleep(10000);
  finally
    FreeAndNil(mnHolder);
  end;

  for iCount := 1 to 5000  do    // Iterate
  begin
    fooObj := TFooClass.Create;
    fooObj.CallFoo;
  end;    // for
end.
