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.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;