




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第二章 COM對象和接口,主要內(nèi)容,COM對象的概念與特征 接口的定義與標識 接口的內(nèi)存模型 接口的特點 IUknown接口 引用計數(shù) 接口查詢 字典組件舉例,COM基礎(chǔ)三個概念,COM組件 組件:可獨立發(fā)布的二進制組件 在Windows平臺上表現(xiàn)為DLL或者EXE COM對象 通過COM接口提供服務(wù) 符合OO中對象的基本概念 COM接口 客戶與對象之間的協(xié)議,對象實現(xiàn)COM接口,客戶使用COM接口從而訪問對象,需要思考的一些問題,COM組件 組件的類型:進程內(nèi)組件(DLL)、進程外組件(EXE) 為方便起見,只討論Windows平臺上DLL類型的組件 COM對象 如何標識一個對象?對象以什么
2、形式存在?客戶如何創(chuàng)建對象? 對象如何暴露接口?一個或是多個? COM接口 要求:跨編譯器、跨語言、跨平臺,2.1 COM對象,概念 COM對象是客戶程序與組件程序進行交互的實體。 COM對象包含屬性和方法(或者狀態(tài)和操作): 屬性反映對象的存在,也是區(qū)別于其他對象的要素; 方法是對象提供給外界的接口。 能夠提供服務(wù)(通過COM接口) 對象的實現(xiàn)由組件完全包裝起來,2.1.1 COM對象的標識CLSID,COM組件的位置透明性 客戶程序并不直接訪問COM對象,而是通過一個唯一的全局標識符進行對象的創(chuàng)建和初始化工作。 可選的標識符方案: 字符串形式:可讀性好,名字沖突的可能性大 定長位數(shù)的整數(shù):
3、如何保證唯一性?(管理組織 / 大隨機數(shù)) GUID 是COM規(guī)范采取的方案 是一個128位的隨機數(shù) 不絕對保證唯一性,但發(fā)生沖突的可能性非常小 例如: 54BF6567-1007-11D1-B0AA-444553540000 ,GUID續(xù),GUID的C/C+結(jié)構(gòu)描述 typedef struct _GUID DWORD Data1; WORD Data2; WORD Data3; BYTE Data48; GUID ; 保證隨機性的考慮 空間上:網(wǎng)絡(luò)中的計算機通常取網(wǎng)卡的地址(唯一的) 時間上:同一機器在不同時候產(chǎn)生的標識符總不相同,GUID (續(xù)),產(chǎn)生GUID的工具 Visual C+提
4、供的兩個工具: UUIDGen.exe :命令行程序 GUIDGen.exe :基于對話框的程序 COM庫提供的API函數(shù) HRESULT CoCreateGuid ( GUID * pguid) ; GUID 與 CLSID CLSID是標識COM對象的GUID 二者在結(jié)構(gòu)上完全一致,2.1.2 COM對象與C+對象的比較,層次差異 COM對象建立在二進制級的基礎(chǔ)上 C+對象建立在源代碼級的基礎(chǔ)上 封裝特性 COM對象的數(shù)據(jù)完全封裝在對象內(nèi)部,不能直接訪問 C+對象的公有數(shù)據(jù)成員是可以訪問的 可重用性 COM對象的重用表現(xiàn)為包容和聚合 C+對象的重用表現(xiàn)為繼承與組合 多態(tài)性的表現(xiàn)形式不同 C
5、OM對象的多態(tài)需要通過接口來表現(xiàn),2.2 COM接口,基本內(nèi)容 接口定義與標識 用C+定義接口 IDL 接口的內(nèi)存模型 接口的特點,2.2.2 接口定義和標識,定義 是一個函數(shù)集,以二進制的形式給出了從一方到另一方的調(diào)用規(guī)范;函數(shù)的地址封裝在一個數(shù)據(jù)結(jié)構(gòu)中。 這個數(shù)據(jù)結(jié)構(gòu)稱為“接口函數(shù)表” 在C+中稱為“虛函數(shù)表”,簡稱vtable 對于一個接口來說,它的vtable是確定的,即: 接口成員函數(shù)的個數(shù)是不變的; 其先后順序也是不變的 客戶程序通過一個指向vtable的指針來調(diào)用接口成員函數(shù),COM接口結(jié)構(gòu),COM接口舉例(C語言),struct IDictionaryVtble; struct
6、 IDictionary IDictionaryVtble * pVtbl ; ; struct IDictionaryVtble BOOL ( * Initialize) (Idictionary * this); BOOL ( * LoadLibrary) (Idictionary * this, String); void ( * FreeLibrary) (Idictionary * this); ;,COM接口標識-IID,Interface Identifier 是GUID的一種用法 例如: extern “C” const IID IID_Iunkown = 0 x0000000
7、0, 0 x0000, 0 x0000 0 xc0, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x00, 0 x46 ; 如果客戶程序要使用一個COM對象的某個接口,必須知道該接口的IID以及它能提供的方法。,2.2.3 用C+語言定義接口,COM接口結(jié)構(gòu)中的vtable與class的vtable完全一致 因此,用class描述COM接口是最方便的手段 舉例: class IDictionary virtual BOOL Initialize() = 0; virtual BOOL LoadLibrary(String) = 0; virtual void Fr
8、eeLibrary() = 0; ;,類IDictionary的內(nèi)存結(jié)構(gòu),2.2.4 接口描述語言IDL,以O(shè)SF 的 IDL為基礎(chǔ) 基本數(shù)據(jù)類型 與C語言非常接近,包括結(jié)構(gòu)、聯(lián)合、枚舉、typedef等 interface coclass library 可以產(chǎn)生類型庫,舉例,interface IDictionary HRESULT Initialize(); HRESULT LoadLibrary(in string); HRESULT InsertWord(in string, in string); HRESULT DeleteWord(in string); HRESULT Loo
9、kupWord(in string, out string *); HRESULT RestoreLibrary(in string); HRESULT FreeLibrary(); ; VC+的MIDL可以由IDL文件生成C/C+接口描述,IDL的意義,IDL語言無關(guān) 跨語言的中間語言 MIDL.exe產(chǎn)生C+頭文件定義 相當于C+定義 MIDL.exe產(chǎn)生TLB類型庫 COM本身提供了一套基礎(chǔ)設(shè)施來解釋類型庫 所有的標準接口都可以在SDK中找到IDL描述,編譯IDL文件,2.2.5 接口的內(nèi)存模型,如果我們用C+實現(xiàn)字典對象,則類定義為: class CDictionary : publi
10、c IDictionary public : CDictionary(); CDictionary(); public : virtual BOOL Initialize(); virtual BOOL LoadLibrary(String); / private : struct DictWord *m_pData; char *m_DictFilename128; / ;,接口和字典對象的內(nèi)存結(jié)構(gòu)圖,多個字典對象與接口的內(nèi)存結(jié)構(gòu)圖,不同方法實現(xiàn)的字典對象與接口關(guān)系,2.2.6 接口的特點,二進制特性 接口不變性 繼承性(擴展性) 多態(tài)性運行過程中的多態(tài)性 (lecture over),2.
11、3 IUnkown 接口,所有的COM接口都必須從IUnknown派生,原因在于Iunknown接口提供了兩個重要的特性: 生存期控制:通過“引用計數(shù)”來控制 接口查詢:QueryInterface函數(shù) Iunknown的IDL定義: Interface IUnknown HRESULT QueryInterface( in REFIID iid, out void * ppv ) ; ULONG AddRef( void ) ; ULONG Release( void ) ; ,2.3 IUnkown 接口(續(xù)),Iunknown的C+定義: class IUnknown public: v
12、irtual HRESULT _stdcall QueryInterface( const IID,2.3.1 引用計數(shù),目的:是為了控制對象的生命周期 多個客戶可以獨立地控制對象的生存 引用計數(shù)反映了COM對象被客戶引用的個數(shù) 引用計數(shù)是個整數(shù),從0開始 兩個操作:增 1 和 減 1 當客戶得到一個指向?qū)ο蟮慕涌谥羔槙r,引用計數(shù)1; 當客戶用完該接口指針時,引用計數(shù)1; 當引用計數(shù)為0時,表示沒有客戶在使用對象或者接口刪除,2.3.2 實現(xiàn)引用計數(shù),引用計數(shù)多實現(xiàn)方案的原因 一個COM組件可以實現(xiàn)多個COM對象 一個COM對象可以實現(xiàn)多個COM接口 組件級實現(xiàn) ? 對象級實現(xiàn) ? 接口級實現(xiàn)
13、? 實現(xiàn)方案比較(參見下頁的圖) 設(shè)置一個針對整個組件的全局引用計數(shù) 所有對象必須一起釋放 計數(shù)分辨率太粗 為每個COM對象設(shè)置一個引用計數(shù)(折中方案) 為每個接口設(shè)置一個引用計數(shù) 客戶不一定會用到對象的所有接口,造成資源浪費 計數(shù)分辨率太細,實現(xiàn)引用計數(shù)的層次(或粒度),重新定義IDictionary,class IDictionary : public IUnknown virtual BOOL Initialize() = 0; virtual BOOL LoadLibrary(String) = 0; virtual BOOL InsertWord(String, String) =
14、0; virtual void DeleteWord(String) = 0; virtual BOOL LookupWord(String, String *) = 0; virtual BOOL RestoreLibrary(String) = 0; virtual void FreeLibrary() = 0; ;,重新定義CDictionary,class CDictionary : public IDictionary public : CDictionary(); CDictionary(); public : virtual HRESULT QueryInterface(cons
15、t IID,部分實現(xiàn)代碼,CDictionary:CDictionary () m_Ref = 0; / . initialize ULONG CDictionary:AddRef () m_Ref +; return (ULONG) m_Ref; ULONG CDictionary:Release () m_Ref -; return (ULONG) m_Ref; ,客戶控制引用計數(shù)的基本規(guī)則,1、客戶創(chuàng)建了組件對象并獲得了第一個接口指針后,引用計數(shù)應(yīng)該為1( 0+1 1) 2、在客戶程序中,當把接口指針賦給其它變量時,應(yīng)該調(diào)用AddRef,使引用計數(shù)增1; 3、在客戶程序中,當一個接口指針
16、被用完之后,應(yīng)該調(diào)用Release,使引用計數(shù)減1;,客戶代碼舉例,IDictionary * pIDictionary = CreateObject(CLSID_Dictionary, IID_Dictionary); if( pIDictionary = NULL ) return; / reference count is 1 / load the dictionary BOOL retValue = pIDictionary-LoadLibrary(eng_ch.dict); if (retValue = FALSE) pIDictionary-Release(); return; .
17、 IDictionary *pIDictionaryForWord = pIDictionary; pIDictionaryForWord -AddRef(); / Insert or delete some word pIDictionaryForWord -InsertWord(.,.); pIDictionaryForWord -DeleteWord(.); pIDictionaryForWord -Release ( ); . / finally, release dictionary object pIDictionary-Release ( );,2.3.3 使用引用計數(shù)的規(guī)則,1
18、、函數(shù)參數(shù)中使用接口指針變量 輸入?yún)?shù):一般不用調(diào)用AddRef和Release 輸出參數(shù)或返回一個接口指針變量: 相當于生成了一個新的接口指針接口指針, 因此,需要調(diào)用AddRef 輸入輸出參數(shù) 如果參數(shù)未被修改,則不用調(diào)用AddRef和Release;否則: 在參數(shù)被修改前,對傳進來的原接口指針調(diào)用Release,在參數(shù)被修改之后,對新的接口指針調(diào)用AddRef。,2.3.3 使用引用計數(shù)的規(guī)則(續(xù)1),2、局部接口指針變量: 指的是用已有的值對局部變量賦值; 可以不調(diào)用AddRef和Release。 3、全局接口指針變量: 作為輸入?yún)?shù)傳給函數(shù)之前,調(diào)用AddRef 函數(shù)返回之后,調(diào)用R
19、elease 4、類成員變量 在類的作用域內(nèi),成員變量相當于全局變量,因此用R3.,2.3.3 使用引用計數(shù)的規(guī)則(續(xù)2),5、當以上情況都不合適時,采用下面的一般性規(guī)則: 在順序執(zhí)行過程中,如果要對一個接口指針變量賦值,則對賦值后的接口指針變量調(diào)用AddRef,并且,如果賦值前的接口指針變量還沒有結(jié)束,則賦值前必須對它調(diào)用Release以便先結(jié)束它的使用。 如果要結(jié)束使用一個接口指針變量,以后不再用到它了,則調(diào)用Release函數(shù)。 盡量養(yǎng)成遵循規(guī)則的好習慣,以免出現(xiàn)錯誤。 在整個生存期內(nèi),AddRef與Release一定要配對,否則: 漏掉AddRef,程序出錯 漏掉Release,對象永
20、不釋放,2.3.3 使用引用計數(shù)的規(guī)則(續(xù)3),頻繁調(diào)用AddRef和Release會降低程序運行效率 需要靈活運用,明顯可以省略時要省略,比如: IDictionary * pIDictionaryForWord = pIDictionary; pIDictionaryForWord -AddRef(); / Insert or delete some word pIDictionaryForWord -InsertWord(.,.); pIDictionaryForWord -DeleteWord(.); pIDictionaryForWord -Release ( ); ,2.3.4 接
21、口查詢,問題的提出 一個COM對象可以實現(xiàn)多個接口,客戶程序可以在運行時刻對COM對象的接口進行詢問,以確定其是否已經(jīng)實現(xiàn)。但對象的多個接口之間如何聯(lián)系起來呢? 通過IUnknown接口的QueryInterface函數(shù)解決。 QueryInterface函數(shù)的形式 HRESULT QueryInterface( in REFIID iid, out void * ppv ); 輸入?yún)?shù)iid是欲查詢接口的IID 輸出參數(shù)ppv為查詢得到的結(jié)果接口指針 如果對象沒有實現(xiàn)iid所標識的接口,則ppv為空(NULL) 函數(shù)的返回值是一個32位的整數(shù),含義為: S_OK,查到了指定的接口,接口指針放
22、在ppv中; E_NOINTERFACE,沒有這個接口,ppv為NULL; E_UNEXPECTED,發(fā)生了意外, ppv為NULL。,客戶程序如何調(diào)用QueryInterface?,假設(shè)字典組件除了實現(xiàn)了IUnknown接口外,還實現(xiàn)了IDictionary接口和ISpellCheck接口,則客戶程序只要得到其中的一個接口指針,就可以得到另外任何一個接口指針。下面是具體的例子: /create a new dictionary object, and got the first interface pointer IDictionary * pIDictionary = CreateObje
23、ct(CLSID_Dictionary, IID_Dictionary); if( pIDictionary = NULL ) return; / reference count is 1 / load the dictionary retValue = pIDictionary-LoadLibrary(eng_ch.dict); if (retValue = FALSE) pIDictionary-Release(); return; .,調(diào)用QueryInterface(續(xù)),ISpellCheck *pISpellCheck; HRESULT result = pIDictionary-
24、QueryInterface(IID_SpellCheck, (void *) .,2.3.6 QueryInterface函數(shù)的實現(xiàn),假設(shè)字典對象類CDictionary的定義如下: class CDictionary : public IDictionary , public ISpellCheck public : CDictionary(); CDictionary(); public : / IUnknown member function virtual HRESULT QueryInterface(const IID,CDictionary的定義(續(xù)),/ IDictionary member function virtual BOOL _stdcall Initialize(); virtu
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 量子計算技術(shù)在商業(yè)服務(wù)行業(yè)的潛在應(yīng)用與發(fā)展趨勢研究報告
- 城市園林綠化項目勞動力配置策略
- 2024-2030全球煤油空間加熱器行業(yè)調(diào)研及趨勢分析報告
- 小學校園節(jié)能減排工作計劃
- 外科疾病患者的家庭護理措施
- 腋臭手術(shù)護理查房
- 一年級上冊數(shù)學復(fù)習計劃與評估
- 學校環(huán)保社團活動計劃
- 讓熱水變涼水中班安全
- 謹防網(wǎng)絡(luò)安全成癮
- 2024-2030年中國輻射探測器行業(yè)市場發(fā)展趨勢與前景展望戰(zhàn)略分析報告
- HSE知識能力測驗試題大全附答案
- 國際經(jīng)濟與貿(mào)易《大學生專業(yè)勞動實踐》教學大綱
- 工作談心談話100篇簡短
- BOSCH共軌噴油器維修基本知識摘要
- 蜀道難全文注音版
- 月子中心護理部護理檔案模板
- 房地產(chǎn) -旭輝第五代住宅產(chǎn)品手冊 H系全產(chǎn)品結(jié)構(gòu)及標準化體系-(上)
- 養(yǎng)老機構(gòu)認知癥老人非藥物干預(yù)療法操作指南
- 一例結(jié)腸穿孔手術(shù)患者護理查房
- 《鐵路職業(yè)道德》課件-3.1 鐵路職業(yè)意識
評論
0/150
提交評論