插件管理框架 for Delphi(二)
unit untDllManager;<br><br>interface
<br><br>uses
<br> Windows, Classes, SysUtils, Forms;
<br><br>type
<br><br> EDllError = Class(Exception);
<br><br> TDllClass = Class of TDll;
<br> TDll = Class;
<br><br> TDllEvent = procedure(Sender: TObject; ADll: TDll) of Object;
<br><br> { TDllManager
<br> o 提供对 Dll 的管理功能;
<br> o Add 时自动创建 TDll 对象,但不尝试装载;
<br> o Delete 时自动销毁 TDll 对象;
<br> }
<br><br> TDllManager = Class(TList)
<br> private
<br> FLock: TRTLCriticalSection;
<br> FDllClass: TDllClass;
<br> FOnDllLoad: TDllEvent;
<br> FOnDllBeforeUnLoaded: TDllEvent;
<br> function GetDlls(const Index: Integer): TDll;
<br> function GetDllsByName(const FileName: String): TDll;
<br> protected
<br> procedure Notify(Ptr: Pointer; Action: TListNotification); override;
<br> public
<br> constructor Create;
<br> destructor Destroy; override;
<br> function Add(const FileName: String): Integer; overload;
<br> function IndexOf(const FileName: String): Integer; overload;
<br> function Remove(const FileName: String): Integer; overload;
<br> procedure Lock;
<br> procedure UnLock;
<br> property DllClass: TDllClass read FDllClass write FDllClass;
<br> property Dlls: TDll read GetDlls; default;
<br> property DllsByName: TDll read GetDllsByName;
<br> property OnDllLoaded: TDllEvent read FOnDllLoad write FOnDllLoad;
<br> property OnDllBeforeUnLoaded: TDllEvent read FOnDllBeforeUnLoaded write FOnDllBeforeUnLoaded;
<br> end;
<br><br> { TDll
<br> o 代表一个 Dll, Windows.HModule
<br> o 销毁时自动在 Owner 中删除自身;
<br> o 子类可通过覆盖override DoDllLoaded, 以及DoDllUnLoaded进行功能扩展;
<br> }
<br><br> TDll = Class(TObject)
<br> private
<br> FOwner: TDllManager;
<br> FModule: HMODULE;
<br> FFileName: String;
<br> FPermit: Boolean;
<br> procedure SetFileName(const Value: String);
<br> function GetLoaded: Boolean;
<br> procedure SetLoaded(const Value: Boolean);
<br> procedure SetPermit(const Value: Boolean);
<br> protected
<br> procedure DoDllLoaded; virtual;
<br> procedure DoBeforeDllUnLoaded; virtual;
<br> procedure DoDllUnLoaded; virtual;
<br> procedure DoFileNameChange; virtual;
<br> procedure DoPermitChange; virtual;
<br> public
<br> constructor Create; virtual;
<br> destructor Destroy; override;
<br> function GetProcAddress(const Order: Longint): FARPROC; overload;
<br> function GetProcAddress(const ProcName: String): FARPROC; overload;
<br> property FileName: String read FFileName write SetFileName;
<br> property Loaded: Boolean read GetLoaded write SetLoaded;
<br> property Owner: TDllManager read FOwner;
<br> property Permit: Boolean read FPermit write SetPermit;
<br> end;
<br><br>implementation
<br><br>{ TDll }
<br><br>constructor TDll.Create;
<br>begin
<br> FOwner := nil;
<br> FFileName := ´´;
<br> FModule := 0;
<br> FPermit := True;
<br>end;
<br><br>destructor TDll.Destroy;
<br>var
<br> Manager: TDllManager;
<br>begin
<br> Loaded := False;
<br> if FOwner <> nil then
<br> begin
<br> //在拥有者中删除自身
<br> Manager := FOwner;
<br> //未防止在 TDllManager中重复删除,因此需要将
<br> //FOwner设置为 nil; <-- 此段代码和 TDllManager.Notify 需要配合
<br> //才能确保正确。
<br> FOwner := nil;
<br> Manager.Remove(Self);
<br> end;
<br> inherited;
<br>end;
<br><br>function TDll.GetLoaded: Boolean;
<br>begin
<br> result := FModule <> 0;
<br>end;
<br><br>function TDll.GetProcAddress(const Order: Longint): FARPROC;
<br>begin
<br> if Loaded then
<br> result := Windows.GetProcAddress(FModule, Pointer(Order))
<br> else
<br> raise EDllError.CreateFmt(´Do Load before GetProcAddress of "%u"´, );
<br>end;
<br><br>function TDll.GetProcAddress(const ProcName: String): FARPROC;
<br>begin
<br> if Loaded then
<br> result := Windows.GetProcAddress(FModule, PChar(ProcName))
<br> else
<br> raise EDllError.CreateFmt(´Do Load before GetProcAddress of "%s"´, );
<br>end;
<br><br>procedure TDll.SetLoaded(const Value: Boolean);
<br>begin
<br> if Loaded <> Value then
<br> begin
<br> if not Value then
<br> begin
<br> Assert(FModule <> 0);
<br> DoBeforeDllUnLoaded;
<br> try
<br> FreeLibrary(FModule);
<br> FModule := 0;
<br> except
<br> Application.HandleException(Self);
<br> end;
<br> DoDllUnLoaded;
<br> end
<br> else
<br> begin
<br> FModule := LoadLibrary(PChar(FFileName));
<br> try
<br> Win32Check(FModule <> 0);
<br> DoDllLoaded;
<br> except
<br> On E: Exception do
<br> begin
<br> if FModule <> 0 then
<br> begin
<br> FreeLibrary(FModule);
<br> FModule := 0;
<br> end;
<br> raise EDllError.CreateFmt(´LoadLibrary Error: %s´, );
<br> end;
<br> end;
<br> end;
<br> end;
<br>end;
<br><br>procedure TDll.SetFileName(const Value: String);
<br>begin
<br> if Loaded then
<br> raise EDllError.CreateFmt(´Do Unload before load another Module named: "%s"´,
<br> );
<br> if FFileName <> Value then
<br> begin
<br> FFileName := Value;
<br> DoFileNameChange;
<br> end;
<br>end;
<br><br>procedure TDll.DoFileNameChange;
<br>begin
<br> // do nonthing.
<br>end;
<br><br>procedure TDll.DoDllLoaded;
<br>begin
<br> if Assigned(FOwner) and Assigned(FOwner.OnDllLoaded) then
<br> FOwner.OnDllLoaded(FOwner, Self);
<br>end;
<br><br>procedure TDll.DoDllUnLoaded;
<br>begin
<br> //do nonthing.
<br>end;
<br><br>procedure TDll.DoPermitChange;
<br>begin
<br> //do nonthing.
<br>end;
<br><br>procedure TDll.SetPermit(const Value: Boolean);
<br>begin
<br> if FPermit <> Value then
<br> begin
<br> FPermit := Value;
<br> DoPermitChange;
<br> end;
<br>end;
<br><br>procedure TDll.DoBeforeDllUnLoaded;
<br>begin
<br> if Assigned(FOwner) and Assigned(FOwner.OnDllBeforeUnLoaded) then
<br> FOwner.OnDllBeforeUnLoaded(FOwner, Self);
<br>end;
<br><br>{ TDllManager }
<br><br>function TDllManager.Add(const FileName: String): Integer;
<br>var
<br> Dll: TDll;
<br>begin
<br> result := -1;
<br> Lock;
<br> try
<br> if DllsByName = nil then
<br> begin
<br> Dll := FDllClass.Create;
<br> Dll.FileName := FileName;
<br> result := Add(Dll);
<br> end
<br> else
<br> result := -1;
<br> finally
<br> UnLock;
<br> end;
<br>end;
<br><br>constructor TDllManager.Create;
<br>begin
<br> FDllClass := TDll;
<br> InitializeCriticalSection(FLock);
<br>end;
<br><br>destructor TDllManager.Destroy;
<br>begin
<br> DeleteCriticalSection(FLock);
<br> inherited;
<br>end;
<br><br>function TDllManager.GetDlls(const Index: Integer): TDll;
<br>begin
<br> Lock;
<br> try
<br> if (Index >=0) and (Index <= Count - 1) then
<br> result := Items
<br> else
<br> raise EDllError.CreateFmt(´Error Index of GetDlls, Value: %d, Total Count: %d´, );
<br> finally
<br> UnLock;
<br> end;
<br>end;
<br><br>function TDllManager.GetDllsByName(const FileName: String): TDll;
<br>var
<br> I: Integer;
<br>begin
<br> Lock;
<br> try
<br> I := IndexOf(FileName);
<br> if I >= 0 then
<br> result := Dlls
<br> else
<br> result := nil;
<br> finally
<br> UnLock;
<br> end;
<br>end;
<br><br>function TDllManager.IndexOf(const FileName: String): Integer;
<br>var
<br> I: Integer;
<br>begin
<br> result := -1;
<br> Lock;
<br> try
<br> for I := 0 to Count - 1 do
<br> if CompareText(FileName, Dlls.FileName) = 0 then
<br> begin
<br> result := I;
<br> break;
<br> end;
<br> finally
<br> UnLock;
<br> end;
<br>end;
<br><br>procedure TDllManager.Lock;
<br>begin
<br> OutputDebugString(Pchar(´TRLock DM´ + IntToStr(GetCurrentThreadId) + ´:´ + IntToStr(DWORD(Self))));
<br> EnterCriticalSection(FLock);
<br> OutputDebugString(Pchar(´Locked DM´ + IntToStr(GetCurrentThreadId) + ´:´ + IntToStr(DWORD(Self))));
<br>end;
<br><br>procedure TDllManager.Notify(Ptr: Pointer; Action: TListNotification);
<br>begin
<br> if Action = lnDeleted then
<br> begin
<br> //若TDll(Ptr).Owner和Self不同,则
<br> //表明由 TDll.Destroy 触发;
<br> if TDll(Ptr).Owner = Self then
<br> begin
<br> //防止FOwner设置为nil之后相关事件不能触发
<br> TDll(Ptr).DoBeforeDllUnLoaded;
<br> TDll(Ptr).FOwner := nil;
<br> TDll(Ptr).Free;
<br> end;
<br> end
<br> else
<br> if Action = lnAdded then
<br> TDll(Ptr).FOwner := Self;
<br> inherited;
<br>end;
<br><br>function TDllManager.Remove(const FileName: String): Integer;
<br>var
<br> I: Integer;
<br>begin
<br> result := -1;
<br> Lock;
<br> try
<br> I := IndexOf(FileName);
<br> if I >= 0 then
<br> result := Remove(Dlls)
<br> else
<br> result := -1;
<br> finally
<br> UnLock;
<br> end;
<br>end;
<br><br>procedure TDllManager.UnLock;
<br>begin
<br> LeaveCriticalSection(FLock);
<br> OutputDebugString(Pchar(´UnLock DM´ + IntToStr(GetCurrentThreadId) + ´:´ + IntToStr(DWORD(Self))));
<br>end;
<br><br>end.
<div class="art_xg">
</div>
</div>
<!--endmain-->
頁:
[1]