unituntDllManager;
interface
uses
Windows,Classes,SysUtils,Forms;
type
EDllError=Class(Exception);
TDllClass=ClassofTDll;
TDll=Class;
TDllEvent=procedure(Sender:TObject;ADll:TDll)ofObject;
{TDllManager
o提供对Dll的管理功能;
oAdd时自动创建TDll对象,但不尝试装载;
oDelete时自动销毁TDll对象;
}
TDllManager=Class(TList)
private
FLock:TRTLCriticalSection;
FDllClass:TDllClass;
FOnDllLoad:TDllEvent;
FOnDllBeforeUnLoaded:TDllEvent;
functionGetDlls(constIndex:Integer):TDll;
functionGetDllsByName(constFileName:String):TDll;
protected
procedureNotify(Ptr:Pointer;Action:TListNotification);override;
public
constructorCreate;
destructorDestroy;override;
functionAdd(constFileName:String):Integer;overload;
functionIndexOf(constFileName:String):Integer;overload;
functionRemove(constFileName:String):Integer;overload;
procedureLock;
procedureUnLock;
propertyDllClass:TDllClassreadFDllClasswriteFDllClass;
propertyDlls[constIndex:Integer]:TDllreadGetDlls;default;
propertyDllsByName[constFileName:String]:TDllreadGetDllsByName;
propertyOnDllLoaded:TDllEventreadFOnDllLoadwriteFOnDllLoad;
propertyOnDllBeforeUnLoaded:TDllEventreadFOnDllBeforeUnLoadedwriteFOnDllBeforeUnLoaded;
end;
{TDll
o代表一个Dll,Windows.HModule
o销毁时自动在Owner中删除自身;
o子类可通过覆盖overrideDoDllLoaded,以及DoDllUnLoaded进行功能扩展;
}
TDll=Class(TObject)
private
FOwner:TDllManager;
FModule:HMODULE;
FFileName:String;
FPermit:Boolean;
procedureSetFileName(constValue:String);
functionGetLoaded:Boolean;
procedureSetLoaded(constValue:Boolean);
procedureSetPermit(constValue:Boolean);
protected
procedureDoDllLoaded;virtual;
procedureDoBeforeDllUnLoaded;virtual;
procedureDoDllUnLoaded;virtual;
procedureDoFileNameChange;virtual;
procedureDoPermitChange;virtual;
public
constructorCreate;virtual;
destructorDestroy;override;
functionGetProcAddress(constOrder:Longint):FARPROC;overload;
functionGetProcAddress(constProcName:String):FARPROC;overload;
propertyFileName:StringreadFFileNamewriteSetFileName;
propertyLoaded:BooleanreadGetLoadedwriteSetLoaded;
propertyOwner:TDllManagerreadFOwner;
propertyPermit:BooleanreadFPermitwriteSetPermit;
end;
implementation
{TDll}
constructorTDll.Create;
begin
FOwner:=nil;
FFileName:=´´;
FModule:=0;
FPermit:=True;
end;
destructorTDll.Destroy;
var
Manager:TDllManager;
begin
Loaded:=False;
ifFOwner<>nilthen
begin
//在拥有者中删除自身
Manager:=FOwner;
//未防止在TDllManager中重复删除,因此需要将
//FOwner设置为nil;<--此段代码和TDllManager.Notify需要配合
//才能确保正确。
FOwner:=nil;
Manager.Remove(Self);
end;
inherited;
end;
functionTDll.GetLoaded:Boolean;
begin
result:=FModule<>0;
end;
functionTDll.GetProcAddress(constOrder:Longint):FARPROC;
begin
ifLoadedthen
result:=Windows.GetProcAddress(FModule,Pointer(Order))
else
raiseEDllError.CreateFmt(´DoLoadbeforeGetProcAddressof"%u"´,[DWORD(Order)]);
end;
functionTDll.GetProcAddress(constProcName:String):FARPROC;
begin
ifLoadedthen
result:=Windows.GetProcAddress(FModule,PChar(ProcName))
else
raiseEDllError.CreateFmt(´DoLoadbeforeGetProcAddressof"%s"´,[ProcName]);
end;
procedureTDll.SetLoaded(constValue:Boolean);
begin
ifLoaded<>Valuethen
begin
ifnotValuethen
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
OnE:Exceptiondo
begin
ifFModule<>0then
begin
FreeLibrary(FModule);
FModule:=0;
end;
raiseEDllError.CreateFmt(´LoadLibraryError:%s´,[E.Message]);
end;
end;
end;
end;
end;
procedureTDll.SetFileName(constValue:String);
begin
ifLoadedthen
raiseEDllError.CreateFmt(´DoUnloadbeforeloadanotherModulenamed:"%s"´,
[Value]);
ifFFileName<>Valuethen
begin
FFileName:=Value;
DoFileNameChange;
end;
end;
procedureTDll.DoFileNameChange;
begin
//dononthing.
end;
procedureTDll.DoDllLoaded;
begin
ifAssigned(FOwner)andAssigned(FOwner.OnDllLoaded)then
FOwner.OnDllLoaded(FOwner,Self);
end;
procedureTDll.DoDllUnLoaded;
begin
//dononthing.
end;
procedureTDll.DoPermitChange;
begin
//dononthing.
end;
procedureTDll.SetPermit(constValue:Boolean);
begin
ifFPermit<>Valuethen
begin
FPermit:=Value;
DoPermitChange;
end;
end;
procedureTDll.DoBeforeDllUnLoaded;
begin
ifAssigned(FOwner)andAssigned(FOwner.OnDllBeforeUnLoaded)then
FOwner.OnDllBeforeUnLoaded(FOwner,Self);
end;
{TDllManager}
functionTDllManager.Add(constFileName:String):Integer;
var
Dll:TDll;
begin
result:=-1;
Lock;
try
ifDllsByName[FileName]=nilthen
begin
Dll:=FDllClass.Create;
Dll.FileName:=FileName;
result:=Add(Dll);
end
else
result:=-1;
finally
UnLock;
end;
end;
constructorTDllManager.Create;
begin
FDllClass:=TDll;
InitializeCriticalSection(FLock);
end;
destructorTDllManager.Destroy;
begin
DeleteCriticalSection(FLock);
inherited;
end;
functionTDllManager.GetDlls(constIndex:Integer):TDll;
begin
Lock;
try
if(Index>=0)and(Index<=Count-1)then
result:=Items[Index]
else
raiseEDllError.CreateFmt(´ErrorIndexofGetDlls,Value:%d,TotalCount:%d´,[Index,Count]);
finally
UnLock;
end;
end;
functionTDllManager.GetDllsByName(constFileName:String):TDll;
var
I:Integer;
begin
Lock;
try
I:=IndexOf(FileName);
ifI>=0then
result:=Dlls[I]
else
result:=nil;
finally
UnLock;
end;
end;
functionTDllManager.IndexOf(constFileName:String):Integer;
var
I:Integer;
begin
result:=-1;
Lock;
try
forI:=0toCount-1do
ifCompareText(FileName,Dlls[I].FileName)=0then
begin
result:=I;
break;
end;
finally
UnLock;
end;
end;
procedureTDllManager.Lock;
begin
OutputDebugString(Pchar(´TRLockDM´+IntToStr(GetCurrentThreadId)+´:´+IntToStr(DWORD(Self))));
EnterCriticalSection(FLock);
OutputDebugString(Pchar(´LockedDM´+IntToStr(GetCurrentThreadId)+´:´+IntToStr(DWORD(Self))));
end;
procedureTDllManager.Notify(Ptr:Pointer;Action:TListNotification);
begin
ifAction=lnDeletedthen
begin
//若TDll(Ptr).Owner和Self不同,则
//表明由TDll.Destroy触发;
ifTDll(Ptr).Owner=Selfthen
begin
//防止FOwner设置为nil之后相关事件不能触发
TDll(Ptr).DoBeforeDllUnLoaded;
TDll(Ptr).FOwner:=nil;
TDll(Ptr).Free;
end;
end
else
ifAction=lnAddedthen
TDll(Ptr).FOwner:=Self;
inherited;
end;
functionTDllManager.Remove(constFileName:String):Integer;
var
I:Integer;
begin
result:=-1;
Lock;
try
I:=IndexOf(FileName);
ifI>=0then
result:=Remove(Dlls[I])
else
result:=-1;
finally
UnLock;
end;
end;
procedureTDllManager.UnLock;
begin
LeaveCriticalSection(FLock);
OutputDebugString(Pchar(´UnLockDM´+IntToStr(GetCurrentThreadId)+´:´+IntToStr(DWORD(Self))));
end;
end.