什么是com接口
按照前文所說的,你不用去釋放COM對象,需要做的僅僅是告訴它們你使用完了。每個COM對象實(shí)現(xiàn)的IUnknown接口都有一個Release()方法。你應(yīng)該調(diào)用這個方法通知COM對象你不再需要它了。一旦調(diào)用了Release(),COM對象就從內(nèi)存中消失,因此也就不能再使用接口指針了。
如果你的應(yīng)用程序使用許多不同的COM對象,那么當(dāng)你使用完接口之后調(diào)用Release()就顯得極為重要。如果你不釋放(release)接口,COM對象(還有包括代碼的那些DLLs)將被保存在內(nèi)存中,并且毫無必要的加入到你的應(yīng)用程序中。如果應(yīng)用程序要運(yùn)行很長一段時間,在程序閑時,你應(yīng)該調(diào)用CoFreeUnusedLibraries()函數(shù)。這個函數(shù)將卸載沒有顯著作用的COM服務(wù)器,這也能減少應(yīng)用程序的內(nèi)存使用量。
繼續(xù)上面的示例,下面展示應(yīng)該如何使用Release():
// Create COM object as above.? Then...
??? if ( SUCCEEDED ( hr ) )
??????? ...{
??????? // Call methods using pISL here.
??????? // Tell the COM object that we're done with it.
??????? pISL->Release();
??????? }
IUnknown接口將在下一部分詳細(xì)說明。
基本接口 - IUnknown
每個COM接口都是從IUnknown繼承而來。這個名字有點(diǎn)容易讓人誤解,因?yàn)閷?shí)際它并不是一個未知(unknown)接口。這個名字意味著即使你有了一個指向COM對象的IUnknown指針,你也不會知道它下面的對象是什么,因?yàn)槊總€COM對象都實(shí)現(xiàn)了IUnknown。
IUnknown 有三個方法:
1.? AddRef() - 告知COM對象增加它的引用計數(shù)。如果你拷貝了一個接口指針,你就需要使用這個方法,無論原始指針還是拷貝的副本都需要使用。在本文中,我們不必使用AddRef()方法。
2. Release() - 告知COM對象減少它的引用計數(shù)。你可以從前面的代碼片段中找到關(guān)于Release()的說明。
3. QueryInterface() - 從COM對象中獲取一個接口指針。當(dāng)COClass實(shí)現(xiàn)二個或二個以上接口的時候,需要使用這個方法。
我們已經(jīng)了解Release()是怎樣運(yùn)作的,那么QueryInterface()又是怎樣的呢?當(dāng)你用CoCreateInstance()創(chuàng)建一個COM對象的時候,你將得到一個接口指針。如果COM對象實(shí)現(xiàn)了二個或二個以上的接口(不包括IUnknown),你可以使用QueryInterface()來獲取任意你想要的額外指針。QueryInterface()的原型如下:
HRESULT IUnknown::QueryInterface (
??? REFIID iid,
??? void** ppv );
參數(shù)如下:
iid
??? 所請求接口的IID
ppv
??? 接口指針的地址。如果調(diào)用成功,QueryInterface()則通過這個參數(shù)返回接口。
讓我們繼續(xù)那個快捷方式的的示例。生成快捷方式的COClass實(shí)現(xiàn)了IShellLink和IPersistFile接口。如果你已經(jīng)有個一個IShellLink指針pISL,那面你可以像下面一樣來從COM對象中獲取IPersistFIle接口:
HRESULT hr;
IPersistFile* pIPF;
??? hr = pISL->QueryInterface ( IID_IPersistFile, (void**) &pIPF );
之后你可以用SUCCEEDED宏測試hr,然后證明QueryInterface()是否成功運(yùn)行了。如果成功,你就可以像使用其它接口一樣使用新的接口指針pIPF了。當(dāng)然,在你使用完畢后,一定要調(diào)用pIPF->Release()。
在討論COM以前,我們得認(rèn)識到一個事實(shí),編寫軟件實(shí)際上是一個非常耗費(fèi)時間和金錢的活動,所以人們不斷尋找方法以減少這些花費(fèi),一個很重要的就是“軟件重用”。在一個理想的環(huán)境下,我們應(yīng)該能夠編寫一次代碼,在任何地方都可以運(yùn)行,即使這個環(huán)境編寫者都沒有想到過。當(dāng)一個程序員修改了自己發(fā)布給別人使用的函數(shù)功能后,使用者應(yīng)該不需要改變或者重新編譯程序就可以使用這個功能。
早期的努力是使用類庫,這個工作在C++中比較常見,但是這種做法是有很大缺陷的,要共享C++的二進(jìn)制代碼是非常困難的。為了解決這個問題,程序員們試圖建立一種標(biāo)準(zhǔn)去達(dá)到軟件在二進(jìn)制級別上的共用。
Components Object Model (COM) 是軟件組件互相通訊的一種方式。它是一種二進(jìn)制和網(wǎng)絡(luò)標(biāo)準(zhǔn),允許任意兩個組件互相通訊,而不管它們是在什么計算機(jī)上運(yùn)行(只要計算機(jī)是相連的),不管各計算機(jī)運(yùn)行的是什么操作系統(tǒng)(只要該系統(tǒng)支持 COM),也不管該組件是用什么語言編寫的。COM 還提供了位置透明性:當(dāng)您編寫組件時,其他組件是進(jìn)程內(nèi) DLL、本地 EXE 還是位于其他計算機(jī)上的組件,對您而言都無所謂。COM 是基于對象的——但是這種對象概念與您熟悉的 C++ 或 Visual Basic 中的對象不太一樣。
首先,COM 對象被很好地封裝起來。您無法訪問對象的內(nèi)部實(shí)現(xiàn)細(xì)節(jié);您無法知道對象使用了什么數(shù)據(jù)結(jié)構(gòu)。實(shí)際上,對象的封裝是如此的嚴(yán)密,以致于 COM 對象通常被描繪為盒子。細(xì)節(jié)是不會告訴你的,但是我們可以通過接口來訪問COM對象里面的方法,當(dāng)然如果COM組件提供商肯告訴你那些接口中的函數(shù)和屬性起什么作用的話。
??? 概括地說,COM具有如下一些優(yōu)越性:
?? 編程技術(shù)難度和工作量降低,開發(fā)周期變短,開發(fā)成本降低。一般編程人員只須根據(jù)應(yīng)用功能要求選用合適的組件,而不必事無巨細(xì)都自己動手去完成。組件模塊將編程的技術(shù)難度和工作量在人員個體和時間上進(jìn)行了分?jǐn)?。我們使用ESRI的COM組件編寫程序就屬于這一級別。
?? 實(shí)現(xiàn)分層次的編程,從而促進(jìn)了軟件的專業(yè)化生產(chǎn)。專業(yè)人員可以開發(fā)出具有很強(qiáng)專業(yè)性的軟件組件,這樣既保證了普通的編程應(yīng)用人員能夠完成所需要的應(yīng)用開發(fā),又不至于降低使用的性能。應(yīng)用人員不便實(shí)現(xiàn)的組件模塊可以讓專業(yè)人員定做。ESRI的程序員們使用C語言為我們辨析了一個個COM組件給我們使用。
?? 軟件的復(fù)用率提高,使軟件的使用效率得到提高并延長了使用壽命。組件編程體系使大量的編程問題局部化了,使軟件的更新和維護(hù)變得快速和容易,軟件的成本大大降低。新的函數(shù)功能如果在接口沒有改變的情況下很容易使用。
談了這么多COM的好處,我們該講點(diǎn)技術(shù)型的東西了,我們在AO編程中需要那些COM知識呢?
1. COM不是接口,也不是對象,它是一種標(biāo)準(zhǔn)。
2. 符合COM標(biāo)準(zhǔn)的對象就是我們要談?wù)摰闹攸c(diǎn)——COM對象。其實(shí)COM對象也無非是實(shí)現(xiàn)了很多接口的對象而已。
3. COM對象必須實(shí)現(xiàn)Iunknown接口,這個接口是管理COM對象生命周期的,當(dāng)COM對象不使用的時候,是這個接口定義的方法負(fù)責(zé)釋放內(nèi)存。一個COM對象可以沒有任何別的接口,但是這個必須要,它是默認(rèn)實(shí)現(xiàn)的接口。
4. QI,即所謂查詢接口。由于COM對象有很多個接口,不同的接口管理著COM的不同類型的方法,因此從一個接口可以使用的方法轉(zhuǎn)到另一個接口可以使用的方法的過程稱為QI,這個過程是由Idispatch接口管理的。
5. GUIDs 每個組件都有一個獨(dú)一無二的標(biāo)識,這就是所謂的廣泛唯一標(biāo)識符。這個標(biāo)識符就是COM組件的身份,它是一個128bits的數(shù)字,由系統(tǒng)自由分配,不要擔(dān)心這個標(biāo)識會有重復(fù)的一天。如果我們每秒產(chǎn)生1000萬個UID,那么到5770年才可能遇到重復(fù)。別告訴我那個時候我們還使用WINDOWS的玩意。
6. 一個COM對象可以有多個接口,一個接口也完全可以被多個COM對象實(shí)現(xiàn)。
7. 接口分為兩種,內(nèi)置接口和外置接口。前一種定義的是COM對象的方法和屬性,用implements實(shí)現(xiàn),COM對象必須實(shí)現(xiàn)所有的接口內(nèi)容;后一種定義的是COM對象的事件,用withEvents實(shí)現(xiàn),這種接口在實(shí)現(xiàn)的時候不必實(shí)現(xiàn)所有的內(nèi)容。
8. COM組件必須被注冊后才能使用,它得到注冊表那里去登記“戶口”。
COM組件很不錯,可是它也有致命的缺陷,這個缺陷就來自它本身。我們知道,COM是可以被重用的,COM對象的實(shí)現(xiàn)過程也可以被修改升級(定義是不能修改的哦),如果兩個程序都使用一個COM對象,而這個COM組件升級了的話,很可能就出現(xiàn)某個程序無法使用新組件的情況,這就被稱為“DLL HELL(DLL災(zāi)難)”,我們有時候安裝了新軟件后很多別的軟件都無法使用,很多原因就是因?yàn)檫@個DLL HELL。別以為這是個小問題,這可是人家微軟提出.NET平臺的一個主要原因。
評論
查看更多