COM組件三個最基本的接口類和使用COM庫的三種方法_第1頁
COM組件三個最基本的接口類和使用COM庫的三種方法_第2頁
COM組件三個最基本的接口類和使用COM庫的三種方法_第3頁
COM組件三個最基本的接口類和使用COM庫的三種方法_第4頁
COM組件三個最基本的接口類和使用COM庫的三種方法_第5頁
全文預覽已結束

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、COM組件三個最基本的接口類 /VC6中使用COM庫的三種方法COM組件有三個最基本的接口類,分別是IUnknown、IClassFactory、IDispatch。COM規(guī)范規(guī)定任何組件、任何接口都必須從IUnknown繼承,IUnknown包含三個函數,分別是 QueryInterface、AddRef、Release。這三個函數是無比重要的,而且它們的排列順序也是不可改變的。QueryInterface用于查詢組件實現的其它接口,說白了也就是看看這個組件的父類中還有哪些接口類,AddRef用于增加引用計數,Release用于減少引用計數。引用計數也是COM中的一個非常重要的概念。大體上簡

2、單的說來可以這么理解,COM組件是個DLL,當客戶程序要用它時就要把它裝到內存里。另一方面,一個組件也不是只給你一個人用的,可能會有很多個程序同時都要用到它。但實際上DLL只裝載了一次,即內存中只有一個COM組件,那COM組件由誰來釋放?由客戶程序嗎?不可能,因為如果你釋放了組件,那別人怎么用,所以只能由COM組件自己來負責。所以出現了引用計數的概念,COM維持一個計數,記錄當前有多少人在用它,每多一次調用計數就加一,少一個客戶用它就減一,當最后一個客戶釋放它的時侯,COM知道已經沒有人用它了,它的使用已經結束了,那它就把它自己給釋放了。引用計數是COM編程里非常容易出錯的一個地方,但所幸VC

3、的各種各樣的類庫里已經基本上把AddRef的調用給隱含了,在我的印象里,我編程的時侯還從來沒有調用過AddRef,我們只需在適當的時侯調用Release。至少有兩個時侯要記住調用Release,第一個是調用了 QueryInterface以后,第二個是調用了任何得到一個接口的指針的函數以后,記住多查MSDN 以確定某個函數內部是否調用了AddRef,如果是的話那調用Release的責任就要歸你了。 IUnknown的這三個函數的實現非常規(guī)范但也非常煩瑣,容易出錯,所幸的事我們可能永遠也不需要自己來實現它們。IClassFactory的作用是創(chuàng)建COM組件。我們已經知道COM組件實際上就是一個類

4、,那我們平常是怎么實例化一個類對象的?是用new命令!很簡單吧,COM組件也一樣如此。但是誰來new它呢?不可能是客戶程序,因為客戶程序不可能知道組件的類名字,如果客戶知道組件的類名字那組件的可重用性就要打個大大的折扣了,事實上客戶程序只不過知道一個代表著組件的128位的數字串而已,這個等會再介紹。所以客戶無法自己創(chuàng)建組件,而且考慮一下,如果組件是在遠程的機器上,你還能new出一個對象嗎?所以創(chuàng)建組件的責任交給了一個單獨的對象,這個對象就是類廠。每個組件都必須有一個與之相關的類廠,這個類廠知道怎么樣創(chuàng)建組件,當客戶請求一個組件對象的實例時,實際上這個請求交給了類廠,由類廠創(chuàng)建組件實例,然后把實

5、例指針交給客戶程序。這個過程在跨進程及遠程創(chuàng)建組件時特別有用,因為這時就不是一個簡單的new操作就可以的了,它必須要經過調度,而這些復雜的操作都交給類廠對象去做了。IClassFactory最重要的一個函數就是CreateInstance,顧名思議就是創(chuàng)建組件實例,一般情況下我們不會直接調用它,API函數都為我們封裝好它了,只有某些特殊情況下才會由我們自己來調用它,這也是VC編寫COM組件的好處,使我們有了更多的控制機會,而VB給我們這樣的機會則是太少太少了。IDispatch叫做調度接口。它的作用何在呢?這個世上除了C+還有很多別的語言,比如VB、 VJ、VBScript、JavaScrip

6、t等等??梢赃@么說,如果這世上沒有這么多亂七八糟的語言,那就不會有IDispatch。:-) 我們知道COM組件是C+類,是靠虛函數表來調用函數的,對于VC來說毫無問題,這本來就是針對C+而設計的,以前VB不行,現在VB也可以用指針了,也可以通過VTable來調用函數了,VJ也可以,但還是有些語言不行,那就是腳本語言,典型的如 VBScript、JavaScript。不行的原因在于它們并不支持指針,連指針都不能用還怎么用多態(tài)性啊,還怎么調這些虛函數啊。唉,沒辦法,也不能置這些腳本語言于不顧吧,現在網頁上用的都是這些腳本語言,而分布式應用也是COM組件的一個主要市場,它不得不被這些腳本語言所調用

7、,既然虛函數表的方式行不通,我們只能另尋他法了。時勢造英雄,IDispatch應運而生。:-) 調度接口把每一個函數每一個屬性都編上號,客戶程序要調用這些函數屬性的時侯就把這些編號傳給IDispatch接口就行了,IDispatch再根據這些編號調用相應的函數,僅此而已。當然實際的過程遠比這復雜,僅給一個編號就能讓別人知道怎么調用一個函數那不是天方夜潭嗎,你總得讓別人知道你要調用的函數要帶什么參數,參數類型什么以及返回什么東西吧,而要以一種統一的方式來處理這些問題是件很頭疼的事。IDispatch接口的主要函數是Invoke,客戶程序都調用它,然后Invoke再調用相應的函數,如果看一看MS的

8、類庫里實現 Invoke的代碼就會驚嘆它實現的復雜了,因為你必須考慮各種參數類型的情況,所幸我們不需要自己來做這件事,而且可能永遠也沒這樣的機會。:-)/本文所用的程序框架均為對話框模式的MFC EXE工程。在編程前,首先要確定待操作的代碼組件是否已經在系統中注冊。如果代碼組件沒有注冊,可以通過WindowsSystem目錄下的regsvr32. exe程序對其進行注冊。一、使用COM庫函數1包含COM的頭文件和接口定義的.c文件在頭文件中包含了接口的C+定義,在.c文件中說明了接口ID IID和類ID CLSID的符號化常量,例如寫了一個COM庫名稱叫“SimpleTest”,則需要包含以下

9、文件:#include simpletest.h#include simpletest_i.c2添加COM初始和終止代碼。在應用程序類的初始化實例函數InitInstance()中添加如下代碼:CoInitialize(NULL);CoUnInitialize();上述語句運行在MFC框架/非MFC框架中,但由于本文程序使用MFC框架,所以也可以利用AfxOleInit()函數對其進行初始化。3.創(chuàng)建組件對象。HRESULT hr;ISimpleInterface* pIntf = NULL; hr = CoCreateInstance(CLSID_SimpleInterface, NULL,

10、 CLSCTX_SERVER , IID_ISimpleInterface, (void *)& pIntf); if(SUCCEEDED(hr) pIntf-Welcome(); pIntf-Release(); 二、使用類向導導入類型庫通過類向導可以直接閱讀組件的類型庫,并產生包裝類型庫中每個接口的類,通過這些類的成員函數可以訪問組件接口的方法和屬性,與使用ActiveX控件的方法有些類似。1添加對COM組件進行初始化的代碼。通過類向導的From a Type Library加入組件的.tlb類型庫文件,并從中引入其接口類。在本例中引入的類型庫文件中只包含一個從ColeDispatchDr

11、iver派生的組件包裝類IAccount。通過包裝類的成員,可以了解到組件接口能提供哪些服務,而且可以通過它們訪問組件接口的方法和屬性。在初始化對話框函數里用COleDispatchDriver類的CreateDispatch()成員函數創(chuàng)建Account組件對象:IAccount m_account;m_account.CreateDispatch(“ATLSample.Account.1”);其中ProgID值“ATLSample. Account. 1”可以通過Microsoft Visual Studio Tools 6.0里的OLE View工具查找到,其前提是該組件已被成功注冊過。

12、釋放Account組件對象也可以用COleDispatch-Driver類的ReleaseDispatch()函數來完成。2調用方法對于在COM庫函數方法中用過的Post方法可用下述方法調用:CString str=m_account. Post(100);可以看出此種方法實現了同樣的功能但實現起來要比上一種方法簡單些,而且對理解COM的要求也不高。三、使用#import 指令1簡要介紹對于類型庫文件采用該指令是非常合適的,因為不管是調試版本還是發(fā)行版本,對于類型庫文件而言,其路徑是固定的。import指令在執(zhí)行時將會從待引入的類型庫中提取出兩個文件:一個.tlh文件和一個.tli文件,后者僅

13、僅是包裝類的函數實現,而前者則包含了許多有關的重要信息。智能接口指針也在其中定義:_COM_SMARTPTR_TYPEDEF(IAccount,_uuidof(IAccount);在實際編譯時,編譯器會將其展開成下述代碼,并通過_com_ptr_t模板類為接口IAccount定義一個智能指針I(yè)AccountPtr。之所以說其是智能指針,是由于它替代IAccount時,會自動處理CoCreate-Instance和所有的IUnknow方法,使用起來非常方便:typedef _com_ptr_t_com_IIID IAccountPtr;由于有了智能指針,我們就可以調用_com_ptr_t模板類的

14、CreateInstance()函數來完成對接口指針的創(chuàng)建工作:IAccountPtr m_account=NULL;m_account.CreateInstance(_uuidof(Account);由于在生成的.tlh文件中包含結構聲明和declspec(uuid(“”)聲明,所以在這里可以很方便地用_uuidof(Account)獲取接口的GUID。declspec(uuid(“”)聲明將GUID和類及每個接口聯系起來,允許開發(fā)人員以uuidof操作符來獲取類和接口的GUID。需要特別指出的是: 為防止原有代碼和新引入的代碼之間發(fā)生名字沖突,編譯器會定義一個由類型庫名稱標識的命名空間,并

15、在其中聲明的任何名稱內附加一個標識符。而為了避免指定命名空間標識,可以在#import 語句后加上using namespace,而且還可以用rename_namespace來改變命名空間。比如在本例中可以進行如下處理:#import “Account.tlb” rename_namespace(“AccountDriver”)using namespace AccountDriver;這樣,在使用智能接口指針I(yè)AccountPtr時只需定義即可:IAccountPtr m_account;至于對代碼組件中的函數和屬性的調用則同前兩種方法一樣,也是通過m_account來完成訪問的。由于_com_ptr_t模板類和智能指針的引入,#import 指令方法是這三種方法中使用COM組件最簡單的一種。2使用方法在stdafx.h文件的最后加上下面這句話:#import SimpleTest.tlb no_namespaceISimpleInterfacePtr* m_account= new ISimpleInterfacePtr;m_acc

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論