这篇文章首先走马观花了解一下程序启动那一刻都做了些什么
1 Program StarOfficeMain; 2 3 uses 4 StarOfficeApplication, 5 MainForm in ‘Form\MainForm.pas‘ {frmMain}, 6 StarMainFormInterface in ‘Interface\StarMainFormInterface.pas‘; 7 8 {$R *.res} 9 10 begin 11 ReportMemoryLeaksOnShutdown:=True; 12 Application.Initialize; 13 Application.MainFormOnTaskbar := True; 14 Application.CreateForm(TfrmMain, frmMain); 15 Application.Run; 16 end.
这是主程序的工程文件,和默认工程相比,是把原本的Forms替换成StarOfficeApplication
1 unit StarOfficeApplication; 2 3 var 4 Application:TStarOfficeApplication;
StarOfficeApplication定义了一个TStarOfficeApplication对象的全局变量Application,所以替换了Forms的Application
1 constructor TStarOfficeApplication.Create; 2 begin 3 FModuleMgr:=TStarModuleManager.Create; 4 end;
TStarOfficeApplication构造函数里创建了一个TStarModuleManager对象,该对象负责框架的模块管理
1 procedure TStarOfficeApplication.Run; 2 begin 3 Forms.Application.Run; 4 FModuleMgr.final; 5 end;
当工程文件里执行Application.Run的时候,实际调用的是TStarOfficeApplication的Run函数
Run函数首先是调用了Forms文件里的 Application.Run;使程序运行起来
但程序退出时FModuleMgr.final;是对模块的卸载
1 constructor TStarModuleManager.Create; 2 begin 3 FLoadBatch:=‘‘; 4 FModuleList := TObjectList.Create(True); 5 TStarObjectFactoryExt.Create([IStarModuleInfoEnum,IStarModuleLoader], self); 6 end;
模块管理类TStarModuleManager构造函数里注册了一个IStarModuleLoader接口实例对象
TStarObjectFactoryExt实例扩展工厂继承自TStarBaseFactoryExt,在TStarBaseFactoryExt的构造函数里
创建了类厂管理对象FFactoryManager
1 constructor TStarBaseFactoryExt.Create(const IIDs: array of TGUID); 2 var i:Integer; 3 begin 4 FIIDList:=TStringList.Create; 5 6 for i:=low(IIDs) to high(IIDs) do 7 begin 8 if StarOfficeFactory.Exists(IIDs[i]) then 9 Raise Exception.CreateFmt(Err_IntfExists,[GUIDToString(IIDs[i])]); 10 11 FIIDList.Add(GUIDToString(IIDs[i])); 12 end; 13 StarOfficeFactory.RegisterFactory(self); 14 end;
1 function StarOfficeFactory:TStarFactoryManager; 2 begin 3 if FFactoryManager=nil then 4 FFactoryManager:=TStarFactoryManager.Create; 5 6 Result:=FFactoryManager; 7 end;
从代码可以看出,不管何时调用StarOfficeFactory函数,只会在首次调用创建一个类厂管理对象
同理,通知管理,事件管理也在程序启动之时被创建,并添加到类厂管理对象中
1 procedure TfrmMain.FormCreate(Sender: TObject); 2 var Intf: IStarModuleLoader; 3 begin 4 TStarObjectFactory.Create(IStarMainForm,Self);; 5 6 Intf:=StarOffice as IStarModuleLoader; 7 Intf.LoadBegin; 8 Intf.LoadModulesFromDir; 9 Intf.LoadFinish; 10 11 (StarOffice as IStarEventManager).EnumEvent(Self); 12 end;
1 function StarOffice: IInterface; 2 begin 3 if not Assigned(FSysService) then 4 FSysService := TStarOfficeService.Create; 5 6 Result := FSysService; 7 end;
StarOffice 返回的是一个IInterface对象,该对象由TStarOfficeService类创建
StarOffice返回的IInterface对象并没有与接口IStarModuleLoader有任何继承关系,可为什么可以 as 呢?
这是接口的特性之接口查询
1 TStarOfficeService = class(TObject, IInterface) 2 private 3 FRefCount: Integer; 4 protected 5 function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; 6 function _AddRef: Integer; stdcall; 7 function _Release: Integer; stdcall; 8 public 9 end;
TStarOfficeService 类实现了IInterface的接口函数
1 function TStarOfficeService.QueryInterface(const IID: TGUID; out Obj): HResult; 2 var 3 aFactory: TStarFactory; 4 begin 5 Result := E_NOINTERFACE; 6 if self.GetInterface(IID, Obj) then 7 Result := S_OK 8 else 9 begin 10 aFactory := StarOfficeFactory.FindFactory(IID); 11 if Assigned(aFactory) then 12 begin 13 aFactory.CreateInstance(IID, Obj); 14 Result := S_OK; 15 end; 16 end; 17 end;
当对一个接口对象进行 as 操作时就会调用 QueryInterface 函数,这是接口的机制
首先会调用默认的GetInterface函数进行接口查询,GetInterface会从继承关系中查找接口,当找不到时再从接口工厂中寻找接口工厂
如果找到了就通过相应工厂创建接口实例对象
这就是统一接口调用的原理
回到主程序的窗体创建函数,调用了IStarModuleLoader接口的LoadModulesFromDir函数,该接口函数实现了将当前程序目录下的模块全部加载进来
(StarOffice as IStarEventManager).EnumEvent(Self);
则调用了事件管理接口的事件枚举函数,将所有注册到事件管理的事件枚举出来并依此动态创建菜单
这就是DEMO程序的启动时刻