藉由 C++ 的 Polymorphism 能力,加上 dll 檔執行時期的動態連結,並配合 UUID 作為元件識別,完美建構出極具機動性的動態元件。元件的使用端可編寫出更自由、更具機動性的程式,元件的設計端只須編寫 cxxlObject 的延伸類別就能作為元件,其他的細節由本程式庫提供的元件集中管理中心(CentralizedMgr)來處理。 元件的設計端要做的事如下:
元件的使用端要做的事如下:
CxxlMan_ObjectFactory() 的格式如下:extern "C" CXXL_DLLEXPORT cxxlObject * cxxlCDECL CxxlMan_ObjectFactory(const wchar_t *ClassID, void *Arg,ISpirit *spirit)
cxxlCM_Init() 的原形宣告如下:void cxxlFASTCALL cxxlCM_Init(const Smart_Ptr<cxxlList<string_wrapper<wchar_t> > > &SearchPath_list); 可藉由 cxxlList 指定多個搜尋路徑 cxxlCM_ElementReg() 的原形宣告如下:bool cxxlFASTCALL cxxlCM_ElementReg(const UNICODE_String &ClassID, const UNICODE_String &Group, const UNICODE_String &Dll); ClassID:元件的識別字串,最好使用 UUID 以避免衝突 Group:元件自取的群組名稱做歸類,藉此可分別註冊相同介面不同實作的 dll Dll:元件所在的元件檔名,也可包含 絕對路徑 或 相對路徑,若是只有 檔名 或只包含 相對路徑,會到 cxxlCM_Init() 指定的搜尋路徑去尋找 若回覆失敗表示 ClassID 已註冊過了,原先的註冊不受影響 cxxlCM_ElementImport() 的原形宣告如下:bool cxxlFASTCALL cxxlCM_ElementImport(std::wistream &TLC); bool cxxlFASTCALL cxxlCM_ElementImport( 第一種註冊表的格式採用 TLC 格式,內部會轉換後呼叫第二種註冊表的匯入函數,內容架構請見以下範例二 若失敗表示註冊表不正確(損毀)。若有相同的 ClassID 存在,原先的註冊不會受影響 cxxlCM_GetElement() 的原形宣告如下:// 只在指定的 Group 尋找 其中的參數 Group 和 ClassI(D,即註冊的 Group 和 ClassI(D。若失敗傳回 NULL,若成功所傳回的是 ClassI(D 指定界面的 cxxlObject 實作物件,得再用 Smart_Cast 轉形成所要的界面
以上對幾個比較主要的功能做介紹,全部功能請看 CENTRALIZEDMGR.HPP
範例一以下示範兩個簡單元件,一個加法 class Addition,一個減法 class Subtraction,這兩個元件有一個共同界面 class IUnit 宣告在 Calculate.h,我測試所用的編譯器為 vs2008,會編譯成元件檔名為 testdll.dll,完成之後即可把 Calculate.h 和 testdll.dll 釋放出去,使用端得到這兩個檔即可編寫應用程式。 /******************* ** Calculate.h ********************/
在 Win32 平台下,CentralizedMgr 內部採用 LoadLibraryW() 載入 dll 檔,但 LoadLibraryW() 這個函數算是半調子的 Unicode 版本,內部還是再轉為 ANSI,因此範例中才多加了 setlocale(LC_CTYPE, ""); 幫它做正確的轉碼。
範例二接下來示範使用元件註冊表來代替一個個註冊元件的方式,元件註冊表的格式採用 TLC 格式,最上層節點代表 Group,其下的各節點代表元件的註冊項目,各項目的節點名稱即為 ClassID,內容為 "只包含元件檔名",或是 "包含相對路徑的元件檔名",或是 "包含絕對路徑的元件檔名",若是 "只包含元件檔名" 或 "包含相對路徑的元件檔名",則在索取元件時會到 cxxlCM_Init() 指定的搜尋路徑中去尋找。 一般的做法應會把元件註冊表做成檔案,以下的範例為了簡明,就直接在程式建立,否則應用 wifstream 來代替 wistringstream。
範例可到本文結尾處下載
物件的生命期與元件檔的卸載當用 cxxlCM_GetElement() 成功得到一個物件時,那麼產生這個物件的元件檔(dll 檔)的計數器會加 1,而這個物件結束時,元件檔的計數器會減 1,當計數器歸 0 時,這個元件檔便會被卸載,但當元件檔卸載後是不是這個元件檔所提供物件都已結束了?元件檔提供的所有物件全都是由 cxxlCM_GetElement() 產生的這是沒有問題的,但若非如此就問題就嚴重了。 一般來說最有可能發生這問題的情況是,cxxlCM_GetElement() 所產生的物件額外再提供物件給使用端,但這物件並沒有經 cxxlCM_GetElement() 來產生,而這物件的程式碼又存在這個元件檔中。面對這些問題的解決辦法有兩種:
若採用第 1 種方法,第 2 的要求就非必要了,若不採用第 1 種方法,則第 2 的要求一定要遵守。 CxxlMan_ObjectFactory() 不可以直接傳回 cxxlCM_GetElement() 的物件cxxlCM_GetElement() 取得的物件會被 CentralizedMgr 再處理,因此 CxxlMan_ObjectFactory() 若再直接傳回 cxxlCM_GetElement() 取得的物件,會再被 CentralizedMgr 處理一次,這會造成很大的問題。標準的做法是把 cxxlCM_GetElement() 取得的物件置於 CxxlMan_ObjectFactory() 要傳回的物件中。
|
機動性元件架構 >