程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 更多關於編程 >> 插件治理框架 for Delphi(二)

插件治理框架 for Delphi(二)

編輯:更多關於編程

插件治理框架 for Delphi(二)。本站提示廣大學習愛好者:(插件治理框架 for Delphi(二))文章只能為提供參考,不一定能成為您想要的結果。以下是插件治理框架 for Delphi(二)正文


unit untDllManager;

interface

uses
  Windows, Classes, SysUtils, Forms;

type

  EDllError = Class(Exception);

  TDllClass = Class of TDll;
  TDll = Class;

  TDllEvent = procedure(Sender: TObject; ADll: TDll) of Object;

  { TDllManager
    o 供給對 Dll 的治理功效; 
    o Add 時主動創立 TDll 對象,但不測驗考試裝載;
    o Delete 時主動燒毀 TDll 對象;
  }

  TDllManager = Class(TList)
  private
    FLock: TRTLCriticalSection;
    FDllClass: TDllClass;
    FOnDllLoad: TDllEvent;
    FOnDllBeforeUnLoaded: TDllEvent;
    function GetDlls(const Index: Integer): TDll;
    function GetDllsByName(const FileName: String): TDll;
  protected
    procedure Notify(Ptr: Pointer; Action: TListNotification); override;
  public
    constructor Create;
    destructor Destroy; override;
    function Add(const FileName: String): Integer; overload;
    function IndexOf(const FileName: String): Integer; overload;
    function Remove(const FileName: String): Integer; overload;
    procedure Lock;
    procedure UnLock;
    property DllClass: TDllClass read FDllClass write FDllClass;
    property Dlls[const Index: Integer]: TDll read GetDlls; default;
    property DllsByName[const FileName: String]: TDll read GetDllsByName;
    property OnDllLoaded: TDllEvent read FOnDllLoad write FOnDllLoad;
    property OnDllBeforeUnLoaded: TDllEvent read FOnDllBeforeUnLoaded write FOnDllBeforeUnLoaded;
  end;

  { TDll
    o 代表一個 Dll, Windows.HModule
    o 燒毀時主動在 Owner 中刪除本身;
    o 子類可經由過程籠罩override DoDllLoaded, 和DoDllUnLoaded停止功效擴大;
  }

  TDll = Class(TObject)
  private
    FOwner: TDllManager;
    FModule: HMODULE;
    FFileName: String;
    FPermit: Boolean;
    procedure SetFileName(const Value: String);
    function GetLoaded: Boolean;
    procedure SetLoaded(const Value: Boolean);
    procedure SetPermit(const Value: Boolean);
  protected
    procedure DoDllLoaded; virtual;
    procedure DoBeforeDllUnLoaded; virtual;
    procedure DoDllUnLoaded; virtual;
    procedure DoFileNameChange; virtual;
    procedure DoPermitChange; virtual;
  public
    constructor Create; virtual;
    destructor Destroy; override;
    function GetProcAddress(const Order: Longint): FARPROC; overload;
    function GetProcAddress(const ProcName: String): FARPROC; overload;
    property FileName: String read FFileName write SetFileName;
    property Loaded: Boolean read GetLoaded write SetLoaded;
    property Owner: TDllManager read FOwner;
    property Permit: Boolean read FPermit write SetPermit;
  end;

implementation

{ TDll }

constructor TDll.Create;
begin
  FOwner := nil;
  FFileName := ´´;
  FModule := 0;
  FPermit := True;
end;

destructor TDll.Destroy;
var
  Manager: TDllManager;
begin
  Loaded := False;
  if FOwner <> nil then
  begin
    //在具有者中刪除本身
    Manager := FOwner;
    //未避免在 TDllManager中反復刪除,是以須要將
    //FOwner設置為 nil; <-- 此段代碼和 TDllManager.Notify 須要合營
    //能力確保准確。 
    FOwner := nil;
    Manager.Remove(Self);
  end;
  inherited;
end;

function TDll.GetLoaded: Boolean;
begin
  result := FModule <> 0;
end;

function TDll.GetProcAddress(const Order: Longint): FARPROC;
begin
  if Loaded then
    result := Windows.GetProcAddress(FModule, Pointer(Order))
  else
    raise EDllError.CreateFmt(´Do Load before GetProcAddress of "%u"´, [DWORD(Order)]);
end;

function TDll.GetProcAddress(const ProcName: String): FARPROC;
begin
  if Loaded then
    result := Windows.GetProcAddress(FModule, PChar(ProcName))
  else
    raise EDllError.CreateFmt(´Do Load before GetProcAddress of "%s"´, [ProcName]);
end;

procedure TDll.SetLoaded(const Value: Boolean);
begin
  if Loaded <> Value then
  begin
    if not Value then
    begin
      Assert(FModule <> 0);
      DoBeforeDllUnLoaded;
      try
        FreeLibrary(FModule);
        FModule := 0;
      except
        Application.HandleException(Self);
      end;
      DoDllUnLoaded;
    end
    else
    begin
      FModule := LoadLibrary(PChar(FFileName));
      try
        Win32Check(FModule <> 0);
        DoDllLoaded;
      except
        On E: Exception do
        begin
          if FModule <> 0 then
          begin
            FreeLibrary(FModule);
            FModule := 0;
          end;
          raise EDllError.CreateFmt(´LoadLibrary Error: %s´, [E.Message]);
        end;
      end;
    end;
  end;
end;

procedure TDll.SetFileName(const Value: String);
begin
  if Loaded then
    raise EDllError.CreateFmt(´Do Unload before load another Module named: "%s"´,
      [Value]);
  if FFileName <> Value then
  begin
    FFileName := Value;
    DoFileNameChange;
  end;
end;

procedure TDll.DoFileNameChange;
begin
  // do nonthing.
end;

procedure TDll.DoDllLoaded;
begin
  if Assigned(FOwner) and Assigned(FOwner.OnDllLoaded) then
    FOwner.OnDllLoaded(FOwner, Self);
end;

procedure TDll.DoDllUnLoaded;
begin
  //do nonthing.
end;

procedure TDll.DoPermitChange;
begin
  //do nonthing.
end;

procedure TDll.SetPermit(const Value: Boolean);
begin
  if FPermit <> Value then
  begin
    FPermit := Value;
    DoPermitChange;
  end;
end;

procedure TDll.DoBeforeDllUnLoaded;
begin
  if Assigned(FOwner) and Assigned(FOwner.OnDllBeforeUnLoaded) then
    FOwner.OnDllBeforeUnLoaded(FOwner, Self);
end;

{ TDllManager }

function TDllManager.Add(const FileName: String): Integer;
var
  Dll: TDll;
begin
  result := -1;
  Lock;
  try
    if DllsByName[FileName] = nil then
    begin
      Dll := FDllClass.Create;
      Dll.FileName := FileName;
      result := Add(Dll);
    end
    else
      result := -1;
  finally
    UnLock;
  end;
end;

constructor TDllManager.Create;
begin
  FDllClass := TDll;
  InitializeCriticalSection(FLock);
end;

destructor TDllManager.Destroy;
begin
  DeleteCriticalSection(FLock);
  inherited;
end;

function TDllManager.GetDlls(const Index: Integer): TDll;
begin
  Lock;
  try
    if (Index >=0) and (Index <= Count - 1) then
      result := Items[Index]
    else
      raise EDllError.CreateFmt(´Error Index of GetDlls, Value: %d, Total Count: %d´, [Index, Count]);
  finally
    UnLock;
  end;
end;

function TDllManager.GetDllsByName(const FileName: String): TDll;
var
  I: Integer;
begin
  Lock;
  try
    I := IndexOf(FileName);
    if I >= 0 then
      result := Dlls[I]
    else
      result := nil;
  finally
    UnLock;
  end;
end;

function TDllManager.IndexOf(const FileName: String): Integer;
var
  I: Integer;
begin
  result := -1;
  Lock;
  try
    for I := 0 to Count - 1 do
      if CompareText(FileName, Dlls[I].FileName) = 0 then
      begin
        result := I;
        break;
      end;
  finally
    UnLock;
  end;
end;

procedure TDllManager.Lock;
begin
  OutputDebugString(Pchar(´TRLock DM´ + IntToStr(GetCurrentThreadId) + ´:´ + IntToStr(DWORD(Self))));
  EnterCriticalSection(FLock);
  OutputDebugString(Pchar(´Locked DM´ + IntToStr(GetCurrentThreadId) + ´:´ + IntToStr(DWORD(Self))));
end;

procedure TDllManager.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if Action = lnDeleted then
  begin
    //若TDll(Ptr).Owner和Self分歧,則
    //注解由 TDll.Destroy 觸發;
    if TDll(Ptr).Owner = Self then
    begin
      //避免FOwner設置為nil以後相干事宜不克不及觸發
      TDll(Ptr).DoBeforeDllUnLoaded;
      TDll(Ptr).FOwner := nil;
      TDll(Ptr).Free;
    end;
  end
  else
  if Action = lnAdded then
    TDll(Ptr).FOwner := Self;
  inherited;
end;

function TDllManager.Remove(const FileName: String): Integer;
var
  I: Integer;
begin
  result := -1;
  Lock;
  try
    I := IndexOf(FileName);
    if I >= 0 then
      result := Remove(Dlls[I])
    else
      result := -1;
  finally
    UnLock;
  end;
end;

procedure TDllManager.UnLock;
begin
  LeaveCriticalSection(FLock);
  OutputDebugString(Pchar(´UnLock DM´ + IntToStr(GetCurrentThreadId) + ´:´ + IntToStr(DWORD(Self))));
end;

end.
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved