COM 是由 Microsoft 提出的組件標準,它不僅定義了組件程式之間進行互動的標準,並且也提供了組件程式運行所需的環境。在 COM 標準中,一個組件程式也被稱為一個模組,它可以是一個動態程式庫,被稱為進程內組件(in-process component);也可以是一個可執行程式(即 EXE 程式),被稱作進程外組件(out-of-process component)。
基本介紹
- 中文名:com原理
- 提出者:Microsoft
- 類別:組件標準
- 性質:動態程式庫
技術概括,接口類型,進程模型,技術原理,
技術概括
一個組件程式可以包含一個或多個組件對象,因為 COM 是以對象為基本單元的模型,所以在程式與程式之間進行通信時,通信的雙方應該是組件對象,也叫做 COM 對象,而組件程式(或稱作 COM 程式)是提供 COM 對象的代碼載體。 COM 對象不同於一般面向對象語言(如 C++ 語言)中的對象概念,COM 對象是建立在二進制可執行代碼級的基礎上,而 C++ 等語言中的對象是建立在原始碼級基礎上的,因此 COM 對象是語言無關的。這一特性使用不同程式語言開發的組件對象進行互動成為可能。
接口類型
COM 對象與接口
類似於 C++ 中對象的概念,對象是某個類(class)的一個實例;而類則是一組相關的數據和功能組合在一起的一個定義。使用對象的套用(或另一個對象)稱為客戶,有時也稱為對象的用戶。 接口是一組邏輯上相關的函式集合,其函式也被稱為接口成員函式。按照習慣,接口名常是以“I”為前綴。對象通過接口成員函式為客戶提供各種形式的服務。
在 COM 模型中,對象本身對於客戶來說是不可見的,客戶請求服務時,只能通過接口進行。每一個接口都由一個 128 位的全局唯一標識符(GUID,Global Unique Identifier)來標識。客戶通過 GUID 來獲得接口的指針,再通過接口指針,客戶就可以調用其相應的成員函式。
與接口類似,每個組件也用一個 128 位 GUID 來標識,稱為 CLSID(class identifer,類標識符或類 ID),用 CLSID 標識對象可以保證(機率意義上)在全球範圍內的唯一性。實際上,客戶成功地創建對象後,它得到的是一個指向對象某個接口的指針,因為 COM 對象至少實現一個接口(沒有接口的 COM 對象是沒有意義的),所以客戶就可以調用該接口提供的所有服務。根據 COM 規範,一個 COM 對象如果實現了多個接口,則可以從某個接口得到該對象的任意其他接口。從這個過程我們也可以看出,客戶與 COM 對象只通過接口打交道,對象對於客戶來說只是一組接口。
進程模型
COM 所提供的服務組件對象在實現時有兩種進程模型:進程內對象和進程外對象。如果是進程內對象,則它在客戶進程空間中運行;如果是進程外對象,則它運行在同機器上的另一個進程空間或者在遠程機器的空間。
進程內服務程式:
服務程式被載入到客戶的進程空間,在 Windows 環境下,通常服務程式的代碼以動態連線庫(DLL)的形式實現。
本地服務程式:
服務程式與客戶程式運行在同一台機器上,服務程式是一個獨立的應用程式,通常它是一個 EXE 檔案。
遠程服務程式:
服務程式運行在與客戶不同的機器上,它既可以是一個 DLL 模組,也可以是一個 EXE 檔案。如果遠程服務程式是以 DLL 形式實現的話,則遠程機器會創建一個代理進程。
雖然 COM 對象有不同的進程模型,但這種區別對於客戶程式來說是透明的,因此客戶程式在使用組件對象時可以不管這種區別的存在,只要遵照 COM 規範即可。然而,在實現 COM 對象時,還是應該慎重選擇進程模型。進程內模型的優點是效率高,但組件不穩定會引起客戶進程崩潰,因此組件可能會危及客戶;(savetime 註:這裡有點問題,如果組件不穩定,進程外模型也同樣會出問題,可能是因為進程內組件和客戶同處一個地址空間,出現衝突的可能性比較大?)進程外模型的優點是穩定性好,組件進程不會危及客戶程式,一個組件進程可以為多個客戶進程提供服務,但進程外組件開銷大,而且調用效率相對低一點。
技術原理
由於 COM 標準是建立在二進制代碼級的,因此 COM 對象的可重用性與一般的面向對象語言如 C++ 中對象的重用過程不同。對於 COM 對象的客戶程式來說,它只是通過接口使用對象提供的服務,它並不知道對象內部的實現過程,因此,組件對象的重用性可建立在組件對象的行為方式上,而不是具體實現上,這是建立重用的關鍵。COM 用兩種機制實現對象的重用。我們假定有兩個 COM 對象,對象1 希望能重用對象2 的功能,我們把對象1 稱為外部對象,對象2 稱為內部對象。 (1)包容方式。
對象1 包含了對象2,當對象1 需要用到對象2 的功能時,它可以簡單地把實現交給對象2 來完成,雖然對象1 和對象2 支持同樣的接口,但對象1 在實現接口時實際上調用了對象2 的實現。
(2)聚合方式。
對象1 只需簡單地把對象2 的接口遞交給客戶即可,對象1 並沒有實現對象2 的接口,但它把對象2 的接口也暴露給客戶程式,而客戶程式並不知道內部對象2 的存在。