COM 学习小记录
COM組件程序:模塊,它可以是 動態連接庫(DLL) && 可執行程序(EXE),稱為 進程內組件(in-of-process component) && 進程外組件(out-of-process component)。
COM對象:建立在二進制可執行代碼級的基礎上,因此COM對象是語言無關的,這一特性使得使用不同編程語言開發的組件對象進行交互成為可能。
COM標準:規范 && 實現。規范:定義了組件和組件之間的通信機制,不依賴于特定的語言和操作系統;實現:COM庫,COM庫為COM規范的具體實現提供了一些核心服務。實現包括一些核心的系統級代碼,這部分核心代碼使得對象和客戶之間可通過接口在二進制代碼級進行交互 。
標志對象:每個對象用一個128位GUID來標識,稱為CLSID(class identifier,類標識符或類ID),用CLSID標識對象可以保證(概率意義上)在全球范圍內的唯一性。只要系統中含有這類COM對象的信息 && 包括COM對象所在的模塊文件(DLL或EXE文件) && COM對象在代碼中的入口點,客戶程序就可以由此CLSID來創建COM對象。
標志接口:COM模型中,對象本身對客戶來說是不可見,客戶只能通過接口請求服務。每一個接口都由一個128位的全局唯一標識符(GUID,Globally Unique Identifier)來標識,客戶通過GUID獲得接口的指針,通過接口指針調用相應的成員函數。
使用服務:客戶成功創建對象后,它得到一個指向對象某個接口的指針,因為COM對象至少實現一個接口,所以客戶就可以調用該接口提供的所有服務。
COM庫:一般不在應用程序層實現,而在操作系統層次上實現,因此一個操作系統只有一個COM庫實現,而且COM庫的實現必須依賴于具體的系統平臺,尤其是系統底層的一些標準。庫可以保證所有的組件按照統一的方式進行交互操作,使我們在編寫COM應用時,可以不編寫為進行COM通信而必需的大量基礎代碼,而直接利用COM庫提供的API進行編程,加快了開發速度。
COM對象特性:封裝性 && 重用性 && 多態性。但這種多態性需要通過COM對象所具有的接口才能體現出來,就像C++對象的多態性需要通過其(virtual)函數才能體現一樣。
COM接口規范:接口是包含了一組函數的數據結構,這組成員函數是組件對象暴露出來的所有信息,通過這組數據結構,客戶代碼可以調用組件對象的功能。客戶程序用一個指向接口數據機構的指針來調用接口成員函數。接口指針實際上又指向另一個指針,這第二個指針指向一組函數,稱為接口函數表(虛函數表),接口函數表中的每一項為4個字節長的函數指針,這與對象的具體實現連接起來,客戶只要獲得了接口指針,就可以調用到對象的實際功能。對于一個接口來說,他的虛函數表vtable是確定的,因此接口的成員函數個數是不變的,而且成員函數的先后順序也是不變的;對于每個成員函數來說,其參數和返回值也是確定的。
接口描述語言:如何描述接口呢?COM接口描述語言是IDL,IDL接口描述語言不僅可用于定義COM接口,同時還定義了一些常用的數據類型,也可以描述自定義的數據結構。對于接口成員函數,我們可以指定每個參數的類型,輸入輸出特性,甚至支持可變長度的數組的描述。IDL支持指針類型,與C/C++很類似。Microsoft Visual C++提供了MIDL工具,可以把IDL接口描述文件編譯成C/C++兼容的接口描述頭文件(.h),從而可以把一種奇怪的東東IDL描述的接口轉化C++形式:
IUnknown的定義(IDL):interface IUnknown {HRESULT QueryInterface([in] REFIID iid, [out] void **ppv); ULONG AddRef(void); ULONG Release(void); }IUnknown的定義(C++):class IUnknown {Public: virtual HRESULT _stdcall QueryInterface([in] REFIID iid, [out] void **ppv)=0; virtual ULONG _stdcall AddRef(void)=0; virtual ULONG _stdcall Release(void)=0; }? IUnKnown是:一個接口,所有COM接口都繼承IUnKnown。定義在WIN32 SDK中的UNKNWN頭文件中。
QueryInterface是:IUnKnown的成員函數,客戶可以通過此函數來查詢組件是否支持某個特定的接口,返回一個指向組件支持的接口的指針,沒有找到則返回NULL。用QueryInterface將組件抽象成由多個相互獨立的接口構成的集合。
組件的生命期:這一點是通過對接口的引用計數實現的。客戶并不能直接控制組件的生命期,當使用完一個接口而要用組件的另一個接口時,是不能將該組件釋放的,對組件的釋放可以由組件在客戶使用完所有組件之后自己完成。AddRef和Release實現的是一種名為引用計數的內存管理技術,當客戶從組件獲得一個接口時,此引用數值將增加;當使用完某個接口時,組件的引用計數值將減1;當引用計數值為0時組件可以將自己從內存中刪除。AddRef和Release可以增加和減少這一計數值。
進程內組件:進程內組件和客戶程序運行在同一個進程地址空間中,所以一旦客戶程序與組件程序建立起通信關系之后,客戶程序得到的接口指針指向組件程序中接口的vtable,這vtable包含了所有成員函數地址,客戶代碼可以直接調用這些成員函數,所以效率非常高。DLL程序是在運行時刻被客戶裝入到內存中的,所以DLL模塊本身也是獨立的,它并不依賴于客戶程序。
操作DLL程序:有三個系統函數,LoadLibrary && GetProcAddress && FreeLibrary。一般地,對于DLL程序的使用過程按照這樣的步驟進行:
首先,客戶程序使用LoadLibrary函數裝入DLL,該函數返回模塊的實例句柄,供以后操作該模塊使用。然后,客戶程序可以調用GetProcAddress函數獲得DLL中引出的函數的地址,我們既可以按函數的序號(在DEF文件中指定)也可以按函數的名字來獲取引出函數的地址,因為客戶程序和DLL程序在相同的內存地址空間中,所以客戶程序可以直接調用這些引出函數。最后,FreeLibrary,把DLL程序卸出內存,以便釋放資源。? COM組件不是:COM組件不是DLL,COM只是利用DLL來給組件提供動態鏈接的能力;COM組件不是一個API函數集;COM組件不是類。
創建COM對象:客戶程序通過調用CoCreateInstance來創建對象的一個實例,并向想要創建的對象傳送一個CLSID。
?DLL:是一種程序動態調用以及連接的技術,他和組件是完全兩種不同的概念,很多組件都采用這種技術作為自身的連接方式。
IDispatch:IDispatch的存在是因為有些語言不支持虛函數表vtable,比如vb,asp等,它的主要作用是”接收一個函數的名稱并執行它“,IDispatch有幾個函數:
GetIDsOfNames:取一個函數的名稱并返回其調度ID,或稱DISPID Invoke:可以將DISPID作為函數數組指針的索引附:
http://blog.csdn.net/l12345678/article/details/1707629
轉載于:https://www.cnblogs.com/jiayith/p/3862277.html
總結
- 上一篇: 另外五个 PHP 设计模式
- 下一篇: Web页面布局方式小结