這篇文章首先走馬觀花瞭解一下程式啟動那一刻都做了些什麼 1 Program StarOfficeMain; 2 3 uses 4 StarOfficeApplication, 5 MainForm in 'Form\MainForm.pas' {frmMain}, 6 StarMainFormInt
這篇文章首先走馬觀花瞭解一下程式啟動那一刻都做了些什麼
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程式的啟動時刻