Com原理及應用——Com對象和接口
1、COM對象的理解
COM對象類似於C++語言中類的概念,類的每個實例代表一個COM對象,它也包括屬性(即狀態)和方法(即操作),狀態反映對象的存在,方法就是接口。
2、COM對象的標識-CLSID
GUID是一個128位的隨機數,重複概率極低。它的值來源於兩部分:空間值(網卡地址或隨機數)和時間值。
獲得GUID值可以使用VC++提供的工具:GUIDGen.exe 和 UUIDGen.exe。或者使用COM庫的API函數CoCreatGuid()。
3、COM對象與C++對象的比較
COM對象將數據完全封裝在對象的內部。C++對象的封裝是在語義上的封裝,通過不同的數據類型實現數據的封裝。
COM對象的可重用性通過包容和聚合實現。C++對象的可重用性通過類的繼承來實現。
COM對象的多態性通過其接口體現,C++對象的多態性通過其虛函數體現。
4、COM接口的作用和意義
COM規範的核心內容是關於接口的定義,雖然COM本身並不複雜,但是圍繞COM接口有很多內容值得仔細探討,包括接口的標識、接口函數的調用習慣、參數處理、接口與對象的關係以及接口與C/C++的關係、COM接口多具有的特性等。
COM定義了一套完整的接口規範,不僅可以彌補API作為組件接口的不足,還從分發揮了組件對象的優勢,並實現了組件對象的多態性。
5、接口定義和標識
從技術上講,接口是包含了一組函數的數據結構,通過這組數據結構,客戶代碼可以調用組件對象的功能。
客戶程序用一個指向接口函數結構的指針來調用接口成員函數。實際上接口指針指向另一個指針pVtable。
接口函數表稱為虛函數表(Virtual Function Table ,簡稱vtable),指向vtable的指針為pVtable。對於一個接口來說,它的虛函數表vtable是確定的。
6、接口設計的問題
在接口成員函數中,字符串變量必須用Unicode字符指針,這是COM規範的要求。
COM API函數使用大多數語言慣用的_stdcall調用習慣。
用C語言定義COM接口,需要有結構體struct定義其接口結構,接口成員函數必須有一個this指針。
用C++語言定義COM接口,因為由C++語言class的實現機理可以看出,COM接口結構中的vtable與class的vtable(類的虛函數表)完全一致,因此,用class描述COM接口是最方便的手段。此時,接口成員函數隱藏了this指針。
class 型接口的說明要比struct 型接口的說明簡捷得多。
7、COM接口與對象的聯係
接口類隻是一種描述,並不提供具體的實現過程。如果COM對象要實現接口,則COM對象必須以某種方式把它自身與接口類聯係起來,然後把接口類的指針暴露給客戶程序,於是客戶程序就可以調用對象的接口功能了。
用 class型接口通過把接口指針(this)與對象數據綁定在一起的方法實現對COM接口的支持比較直觀、簡捷易於理解。實際上,也可以采用其他的方法來實現接口,隻要接口成員函數中this指針(即接口指針)與對象數據能建立確定的連接,在接口成員函數中可以訪問到對象數據即可。例如,VC++的MFC 庫和ATL(active template library ,活動模板庫)模板庫分別采用了不同的機製來提供對COM接口的支持。
8、接口描述語言IDL
COM 規範在采用OSF的DCE規範描述遠程調用接口IDL(interface description language ,接口描述語言)的基礎上,進行擴展形成了COM接口的描述語言。接口描述語言提供了一種不依賴於任何語言的接口描述方法,因此,它可以成為組件程序和客戶程序之間的共同語言。
COM 規範使用的IDL接口描述語言不僅可用於定義COM接口,同時還定義了一些常用的數據類型,也可以描述自定義的數據結構,對於接口成員函數,我們可以製定每個參數的類型、輸入輸出特性,甚至支持可變長度的數組的描述。VC++提供了MIDL工具,可以把IDL接口描述文件編譯成C/C++兼容的接口描述頭文件(.h)。
9、接口的內存模型
COM對象往往有自己的屬性數據,它們反映對象的狀態,並用於區分不同的對象。對於有多個對象的客戶,數據屬性是不能公用的。
10、接口的特點
二進製特性
接口不變性
繼承性(擴展性):類似於C++中類的繼承性,接口也可以繼承發展,但方式不同。類繼承不僅是說明繼承,也是實現繼承,即派生類可以繼承基類的函數實現,而接口繼承隻是說明繼承,即派生的接口隻繼承了基接口的成員函數說明,而沒有繼承基接口的實現。類繼承允許多重繼承,但接口繼承隻允許單繼承。根據COM規範,所有接口都必須從IUnknown派生,可以直接派生,也可以間接派生。但大多數都是直接派生。OLE係統中,接口最後字母是“2”或“Ex”的,標煤它是一個繼承接口。
多態性:COM對象具有多態性,其通過COM接口體現。
11、IUnknown接口提供了兩個非常重要的特性:生存期控製(使用引用計數)和接口查詢。
12、IUnknown接口引用計數的設置層級
引用計數在組件一級實現則計數分辨率太粗(選擇全局變量),在對象一級實現恰好(使用C++類的成員變量),在接口一級實現則計數分辨率太細(使用類成員變量)。
13、使用引用計數的規則
根據不同場合使用或者傳遞接口指針標量進行分類,並給出相應的規則:
(1)函數的參數中使用接口指針變量。
輸入參數:由於輸入參數由調用函數控製,因此被調用函數執行過程中,接口指針一定保持有效,引用計數不需要改變。
輸出參數:輸出參數是指在被調用函數執行過程中進行賦值的參數,而且被調用函數並沒有用到函數初始化傳進來的值,輸出參數相當於函數的一個返回值。在C/C++語言中,輸出參數為一個指針變量(COM中不使用引用變量)。因為輸出參數相當於在被調用函數中生成了一個新的接口指針變量,因此,在被調用函數返回之前,對輸出參數應該調用AddRef使接口引用計數增1。這條規則也適用於函數返回值為接口指針變量的情況。
輸入-輸出參數:在參數被修改之前,對原來傳進來的接口指針調用Release以使引用計數減1,在參數被修改之後,對新的接口指針變量調用AddRef,以標記對新的接口指針的引用。如果在函數執行過程中參數沒有被修改,則不需要改變。
(2)局部接口指針變量:因為在局部函數塊中,接口指針總是有效的,所以,一個局部接口指針變量被賦了值並調用了接口成員函數,引用計數不需要改變。
(3)全局接口指針變量:把全局接口指針變量作為輸入參數傳給某個函數之前,應該調用AddRef以保證在函數調用中可以使用給接口指針變量,因為它是全局變量,其他的函數有可能會調用Release函數。在函數返回之後應該調用Release函數。
(4)C++中類成員變量為接口指針變量:因為對於類的作用域來講,成員變量相當於全局變量,因此適用於規則(3)。
(5)當以上情形都不適合時,使用以下一般的規則:
在順序執行過程中,如果要對一個接口指針變量賦值,則對賦值後的接口指針變量調用AddRef,並且,如果賦值前的接口指針變量還沒有結束,則賦值前必須對它調用Release以便先結束它的使用。
如果要結束使用一個接口指針變量,以後不再用到它了,則調用Release函數。
14、接口查詢
使用QueryInterface函數查詢接口,其返回值有S_OK、E_NOINTERFACE、E_UNEXPECTED。
15、COM對象的接口原則
(1)對於同一個對象的不同接口指針,查詢得到的IUnknown接口必須完全相同。即每個對象的IUnknown接口指針是唯一的。
(2)接口對稱性。即對一個接口查詢其自身總應該成功。
(3)接口自反性。
(4)接口傳遞性。
(5)接口查詢時間無關性。
16、多接口COM對象的實現方法
在C++語言中有兩種實現方法:一是使用多重繼承,把所支持的接口作為其基類,然後在對象類中實現接口成員函數;二是使用內嵌接口類成員。
最後更新:2017-04-03 15:22:11
上一篇:
Java中CallableStatement調用Oracle存儲過程總結
下一篇:
2014Microsoft 校招筆試真題(找工作的蝦米們趕緊做題曬答案嘍)
#雲存儲的成本到底省在哪兒# 終於搞明白,存儲TCO原來是這樣算的......
PHPnow中ZendDebugger與ZendOptimizer 共存
c語言 王者歸來
高效地顯示Bitmap圖片 2 - 在UI線程之外處理Bitmaps
獨家視頻教程,玩轉《阿裏巴巴Java開發手冊》P3C掃描插件
《vSphere性能設計:性能密集場景下CPU、內存、存儲及網絡的最佳設計實踐》一1.5.1 虛擬機可擴展性
程序員的困境
這一課,一生難忘
[WCF權限控製]WCF自定義授權體係詳解[實例篇]
java 企業網站源碼 模版 屏幕自適應 前後台 spring mvc SSM 生成靜態化