《COM原理与应用》学习笔记二——COM对象和COM接口的实现
COM對象是給用戶提供服務的封裝的實體。這個應該和C++中類的對象理解起來是相似的。但是有時候也把COM對象當作提供服務的那個類。COM對象也對數據進行了封裝,然后也提供了接口。不過和類還是有一些不一樣的。類中的數據可以申明為public,然后讓用戶能夠直接訪問這些數據成員。但是用戶不能對COM對象的數據進行直接訪問,只能通過接口(如果有提供這種接口的話)來對數據進行間接的訪問。一般COM接口指的是一組提供服務的接口,剛開始看這個定義很不習慣。因為C++中根本沒有接口的概念,但是像Java這些語言就有接口的概念。關于COM接口可以按照Java的接口來理解(多懂幾門語言真心是好事啊)。C++中的定義方式一般是用抽象類來實現,其中所有的函數全都是純需函數,全部交給子類來實現。如某個接口的定義如下:
1 struct ICalc 2 { 3 virtual long __stdcall add(long a, long b) = 0; 4 virtual long __stdcall minus(long a, long b) = 0; 5 virtual long __stdcall times(long a, long b) = 0; 6 virtual long __stdcall devide(long a, long b) = 0; 7 };
客戶使用COM組件的時候,是不知道COM組件的確切對象的。所以COM組件需要注冊注冊表。但是客戶還是需要一點什么標識來訪問COM組件,使用COM對象,第一個直接的想法就是取個名字。但是會出現這種情況,A公司做個插件叫做Calculator,B公司做個插件也可以叫做Calculator,甚至家里的旺財寫個插件都可以叫做Calculator。所以這個方法不是很好。為了解決這個重復的問題。微軟決定使用GUID來對插件進行標識。GUID全稱是Globally Unique Identifier,是一個128位的隨機數。大家都隨機,不怕隨到一樣的數嗎?恩,確實有那個可能,但是這個概率太低了。理論上,如果一臺計算機每秒產生10 000 000個GUID,則可以保證3240年不重復(當然是概率意義上,怎么算的了,我也不清楚啦)。反正GUID重復的概率是非常低的,可以放心使用。每個COM對象都有一個GUID來進行標識,這個GUID一般叫做CLSID。每一個COM接口也有一個GUID來進行標識,這個GUID一般叫做IID。在C++中,GUID定義如下:
1 typedef struct _GUID 2 { 3 DWORD Data1; 4 WORD Data2; 5 WORD Data3; 6 BYTE Data4[8]; 7 } GUID;按照COM規范,只要用戶獲得了一個COM對象的接口,那么用戶可以通過它獲取到該COM對象的其他接口(如果有的話)。一個用戶在使用COM對象以前,用戶需要建立COM對象(我覺得COM對象這個叫法真心的很討厭,書上說COM對象既指那個提供服務的類,也指根據這個類實例化的對象)。建立COM對象當然是要分配一些資源的,在用完這些資源以后當然也是需要釋放的,所以每一個COM對象都有一個計數。計數值為0的時候,那么對象就銷毀這個COM對象。當有另外一個指針獲得這個COM對象的話,那么計數就會增加一個,有一個指針釋放了對這個COM對象的控制了,那么計數就減一。這種計數的方式類似于智能指針。但是COM對象的計數也沒有智能指針那么智能,有時還是需要手動來釋放的,所以用戶承擔著釋放資源的重任。基于以上的說法,我們就需要一個獲取其他所有接口的接口,增加計數的接口和減少計數的接口。COM提供的IUnknown接口已經提供了這三個接口(注意:COM接口一般指的是一組接口,而不是一個接口)。實際上所有的COM接口都必須從IUnknown繼承而來。IUnknown提供了QueryInterface、AddRef和Release這三個接口。按C++的定義如下,但是實際定義的寫法比較麻煩,這里只是比較簡單的寫法。
1 class IUnknown 2 { 3 public: 4 virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) =0; 5 virtual ULONG __stdcall AddRef() =0; 6 virtual ULONG __stdcall Release() = 0; 7 }IUnknown是一個接口當然也有一個IID,IUnknown的IID為IID_IUnknown=00000000-0000-0000-C000-000000000046。然后剩下就是用戶自己定義接口了。用戶也可以定義多個接口。最后提供服務的類集成這些接口就組成了一個能夠被用來創建COM對象的類了。比如下面的ICalc是一個接口,CCalc就是一個實現服務的類。
1 class ICalc : public IUnknown 2 { 3 public: 4 virtual long __stdcall add(long a, long b) = 0; 5 virtual long __stdcall minus(long a, long b) = 0; 6 virtual long __stdcall times(long a, long b) = 0; 7 virtual long __stdcall devide(long a, long b) = 0; 8 }; 9 10 class CCalc : public ICalc 11 { 12 public: 13 CCalc(); 14 ~CCalc() = default; 15 16 public: 17 //IUnknown interface: 18 virtual HRESULT __stdcall QueryInterface(const IID &iid, void **ppv) override; 19 virtual ULONG __stdcall AddRef() override; 20 virtual ULONG __stdcall Release() override; 21 22 //ICalc interface: 23 virtual long __stdcall add(long a, long b) override; 24 virtual long __stdcall minus(long a, long b) override; 25 virtual long __stdcall times(long a, long b) override; 26 virtual long __stdcall devide(long a, long b) override; 27 28 private: 29 long m_lRef; 30 };其中override是C++11標準所提供的關鍵字。
這一篇博客就先寫到這吧,后面還有需要繼續寫的,但是現在要回寢室了,后續的明天或者后天繼續寫。
PS:博主也是一個菜鳥,最近才開始寫技術博客,如果各位發現了什么錯誤,歡迎拍磚,指出錯誤。
轉載于:https://www.cnblogs.com/DennisXie/p/3961648.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的《COM原理与应用》学习笔记二——COM对象和COM接口的实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信公众号根据URL取文章详情 API
- 下一篇: 实训三(cocos2dx 3.x 打包a