COM編程入門篇_第1頁(yè)
COM編程入門篇_第2頁(yè)
COM編程入門篇_第3頁(yè)
COM編程入門篇_第4頁(yè)
COM編程入門篇_第5頁(yè)
已閱讀5頁(yè),還剩20頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、COM編程入門本文的目的是為剛剛接觸COM的程序員提供編程指南,并幫助他們理解COM的基本概念。內(nèi)容包括COM規(guī)范簡(jiǎn)介,重要的COM術(shù)語(yǔ)以及如何重用現(xiàn)有的COM組件。本文不包括如何編寫自己的COM對(duì)象和接口。COM即組件對(duì)象模型,是ComponentObjectModel取前三個(gè)字母的縮寫,這三個(gè)字母在當(dāng)今Windows的世界中隨處可見。隨時(shí)涌現(xiàn)出來的大把大把的新技術(shù)都以COM為基礎(chǔ)。各種文檔中也充斥著諸如COM對(duì)象、接口、服務(wù)器之類的術(shù)語(yǔ)。因此,對(duì)于一個(gè)程序員來說,不僅要掌握使用COM的方法,而且還要徹底熟悉COM的所有一切。本文由淺入深描述COM的內(nèi)在運(yùn)行機(jī)制,教你如何使用第三方提供的CO

2、M對(duì)象(以Windows外殼組件Shell為例)。讀完本文后,你就能掌握如何使用Windows操作系統(tǒng)中內(nèi)建的組件和第三方提供的COM對(duì)象。本文假設(shè)你精通C+語(yǔ)言。在例子代碼中使用了一點(diǎn)MFC和ATL,如果你不熟悉MFC和ATL也沒關(guān)系,本文會(huì)對(duì)這些代碼進(jìn)行完全透徹的解釋。本文包括以下幾個(gè)部分:到底是什么?一一標(biāo)準(zhǔn)的要點(diǎn)介紹,它被設(shè)計(jì)用來解決什么問題?基本元素的定義術(shù)語(yǔ)以及這些術(shù)語(yǔ)的含義。使用和處理對(duì)象如何創(chuàng)建、使用和銷毀對(duì)象。基本接口描述基本接口及其方法。掌握串的處理在代碼中如何處理串。應(yīng)用技術(shù)例子代碼,舉例說明本文所討論的所有概念。處理一一類型描述,如何監(jiān)測(cè)錯(cuò)誤及成功代碼。COM到底是什么

3、?簡(jiǎn)單地說,COM是一種跨應(yīng)用和語(yǔ)言共享二進(jìn)制代碼的方法。與C+不同,它提倡源代碼重用。ATL便是一個(gè)很好的例證。源碼級(jí)重用雖然好,但只能用于C+。它還帶來了名字沖突的可能性,更不用說不斷拷貝重用代碼而導(dǎo)致工程膨脹和臃腫。Windows使用DLLs在二進(jìn)制級(jí)共享代碼。這也是Windows程序運(yùn)行的關(guān)鍵重用kernel32.dll,user32.dll等。但DLLs是針對(duì)C接口而寫的,它們只能被C或理解C調(diào)用規(guī)范的語(yǔ)言使用。由編程語(yǔ)言來負(fù)責(zé)實(shí)現(xiàn)共享代碼,而不是由DLLs本身。這樣的話DLLs的使用受到限制。MFC引入了另外一種MFC擴(kuò)展DLLs二進(jìn)制共享機(jī)制。但它的使用仍受限制只能在MFC程序中

4、使用。COM通過定義二進(jìn)制標(biāo)準(zhǔn)解決了這些問題,即COM明確指出二進(jìn)制模塊(DLLs和EXEs)必須被編譯成與指定的結(jié)構(gòu)匹配。這個(gè)標(biāo)準(zhǔn)也確切規(guī)定了在內(nèi)存中如何組織COM對(duì)象。COM定義的二進(jìn)制標(biāo)準(zhǔn)還必須獨(dú)立于任何編程語(yǔ)言(如C+中的命名修飾)。一旦滿足了這些條件,就可以輕松地從任何編程語(yǔ)言中存取這些模塊。由編譯器負(fù)責(zé)所產(chǎn)生的二進(jìn)制代碼與標(biāo)準(zhǔn)兼容。這樣使后來的人就能更容易地使用這些二進(jìn)制代碼。在內(nèi)存中,COM對(duì)象的這種標(biāo)準(zhǔn)形式在C+虛函數(shù)中偶爾用到,所以這就是為什么許多COM代碼使用C+的原因。但是記住,編寫模塊所用的語(yǔ)言是無關(guān)的,因?yàn)榻Y(jié)果二進(jìn)制代碼為所有語(yǔ)言可用。此外,COM不是Win32特有的

5、。從理論上講,它可以被移植到Unix或其它操作系統(tǒng)。但是我好像還從來沒有在Windows以外的地方聽說過COM?;驹氐亩x我們從下往上看。接口只不過是一組函數(shù)。這些函數(shù)被稱為方法。接口名字以大寫的I開頭,例如C+中的IShellLink,接口被設(shè)計(jì)成一個(gè)抽象基類,其中只有純粹的虛擬函數(shù)。接口可以從其它接口繼承,這里所說的繼承的原理就好像C+中的單繼承。接口是不允許多繼承的。coclass(簡(jiǎn)稱組件對(duì)象類componentobjectclass)被包含在DLL或EXE中,并且包含著一個(gè)或者多個(gè)接口的代碼。組件對(duì)象類(coclasss)實(shí)現(xiàn)這些接口。COM對(duì)象在內(nèi)存中表現(xiàn)為組件對(duì)象類(cocl

6、asss)的一個(gè)實(shí)例。注意COM類和C+類是不相同的,盡管常常COM類實(shí)現(xiàn)的就是一個(gè)C+類。COM服務(wù)器是包含了一個(gè)或多個(gè)coclass的二進(jìn)制(DLL或EXE)。注冊(cè)(Registration)是創(chuàng)建注冊(cè)表入口的一個(gè)過程,告訴Windows操作系統(tǒng)COM服務(wù)器放在什么位置。取消注冊(cè)(Unregistration)貝閑反從注冊(cè)表刪除這些注冊(cè)入口。GUID(諧音為fluid意思是全球唯一標(biāo)示符globallyuniqueidentifier)是個(gè)128位的數(shù)字。它是一種獨(dú)立于COM編程語(yǔ)言的標(biāo)示方法。每一個(gè)接口和coclass有一個(gè)GUID。因?yàn)槊恳粋€(gè)GUID都是全球唯一的,所以避免了名字沖突(

7、只要你用COMAPI創(chuàng)建它們)。有時(shí)你還會(huì)碰到另一個(gè)術(shù)語(yǔ)UUID(意思也是全球唯一標(biāo)示符universallyuniqueidentifier)。UUIDs和GUIDs在實(shí)際使用時(shí)的用途是一樣的。類ID或者CLSID是命名coclass的GUID。接口ID或者IID是命名接口的GUID。在COM中廣泛地使用GUID有兩個(gè)理由:1、GUIDs只是簡(jiǎn)單的數(shù)字,任何編程語(yǔ)言都可以對(duì)之進(jìn)行處理。2、GUIDs可以在任何機(jī)器上被任何人創(chuàng)建,一旦完成創(chuàng)建,它就是唯一的。因此,COM開發(fā)人員可以創(chuàng)建自己特有的GUIDs而不會(huì)與其它開發(fā)人員所創(chuàng)建的GUIDs有沖突。這樣就消除了集中授權(quán)發(fā)布GUIDs的必要。H

8、RESULT是COM用來返回錯(cuò)誤和成功代碼的整型數(shù)字。除此之外,別無它意,雖然以H作前綴,但沒有句柄之意。下文會(huì)對(duì)它有更多的討論。最后,COM庫(kù)是在你使用COM時(shí)與你交互的操作系統(tǒng)的一部分,它常常指的就是COM本身。但是為了避免混淆才分開描述的。使用和處理COM對(duì)象每一種語(yǔ)言都有其自己處理對(duì)象的方式。例如,C+是在棧中創(chuàng)建對(duì)象,或者用new動(dòng)態(tài)分配。因?yàn)镃OM必須獨(dú)立于語(yǔ)言,所以COM庫(kù)為自己提供對(duì)象管理例程。下面是對(duì)COM對(duì)象管理和C+對(duì)象管理所做的一個(gè)比較:創(chuàng)建一個(gè)新對(duì)象C+中,用new操作符,或者在棧中創(chuàng)建對(duì)象。COM中,調(diào)用COM庫(kù)中的API。刪除對(duì)象C+中,用delete操作符,或?qū)?/p>

9、棧對(duì)象踢出。COM中,所有的對(duì)象保持它們自己的引用計(jì)數(shù)。調(diào)用者必須通知對(duì)象什么時(shí)候用完這個(gè)對(duì)象。當(dāng)引用計(jì)數(shù)為零時(shí),COM對(duì)象將自己從內(nèi)存中釋放。由此可見,對(duì)象處理的兩個(gè)階段:創(chuàng)建和銷毀,缺一不可。當(dāng)創(chuàng)建COM對(duì)象時(shí)要通知COM庫(kù)使用哪一個(gè)接口。如果這個(gè)對(duì)象創(chuàng)建成功,COM庫(kù)返回所請(qǐng)求接口的指針。然后通過這個(gè)指針調(diào)用方法,就像使用常規(guī)C+對(duì)象指針一樣。創(chuàng)建COM對(duì)象為了創(chuàng)建COM對(duì)象并從這個(gè)對(duì)象獲得接口,必須調(diào)用COM庫(kù)的API函數(shù),CoCreatelnstance()。其原型如下:以下是參數(shù)解釋:rclsidcoclass的CLSID,例如,可以傳遞CLSID_ShellLink創(chuàng)建一個(gè)COM

10、對(duì)象來建立快捷方式。pUnkOuter這個(gè)參數(shù)只用于COM對(duì)象的聚合,利用它向現(xiàn)有的coclass添加新方法。參數(shù)值為null表示不使用聚合。dwClsContext表示所使用COM服務(wù)器的種類。本文使用的是最簡(jiǎn)單的COM服務(wù)器,一個(gè)進(jìn)程內(nèi)(in-process)DLL,所以傳遞的參數(shù)值為CLSCTX_INPROC_SERVER。注意這里不要隨意使用CLSCTX_ALL(在ATL中,它是個(gè)缺省值),因?yàn)樵跊]有安裝DCOM的Windows95系統(tǒng)上會(huì)導(dǎo)致失敗。riid請(qǐng)求接口的IID。例如,可以傳遞IID_IShellLink獲得IShellLink接口指針。ppv接口指針的地址。COM庫(kù)通過這

11、個(gè)參數(shù)返回請(qǐng)求的接口。當(dāng)你調(diào)用CoCreateInstance()時(shí),它負(fù)責(zé)在注冊(cè)表中查找COM服務(wù)器的位置,將服務(wù)器加載到內(nèi)存,并創(chuàng)建你所請(qǐng)求的coclass實(shí)例。以下是一個(gè)調(diào)用的例子,創(chuàng)建一個(gè)CLSID_ShellLink對(duì)象的實(shí)例并請(qǐng)求指向這個(gè)對(duì)象IShellLink接口指針。的不是用聚合服務(wù)器類型接口的指向接口的指針用調(diào)用方法不能創(chuàng)建對(duì)象,為出錯(cuò)代碼首先聲明一個(gè)接受CoCreatelnstance()返回值的HRESULT和IShellLink指針。調(diào)用CoCreateInstance()來創(chuàng)建新的COM對(duì)象。如果hr接受到一個(gè)表示成功的代碼,則SUCCEEDED宏返回TRUE,否則返

12、回FALSE。FAILED是一個(gè)與SUCCEEDED對(duì)應(yīng)的宏用來檢查失敗代碼。刪除COM對(duì)象前面說過,你不用釋放COM對(duì)象,只要告訴它們你已經(jīng)用完對(duì)象。IUnknown是每一個(gè)COM對(duì)象必須實(shí)現(xiàn)的接口,它有一個(gè)方法,Release()。調(diào)用這個(gè)方法通知COM對(duì)象你不再需要對(duì)象。一旦調(diào)用了這個(gè)方法之后,就不能再次使用這個(gè)接口,因?yàn)檫@個(gè)COM對(duì)象可能從此就從內(nèi)存中消失了。如果你的應(yīng)用程序使用許多不同的COM對(duì)象,因此在用完某個(gè)接口后調(diào)用Release()就顯得非常重要。如果你不釋放接口,這個(gè)COM對(duì)象(包含代碼的DLLs)將保留在內(nèi)存中,這會(huì)增加不必要的開銷。如果你的應(yīng)用程序要長(zhǎng)時(shí)間運(yùn)行,就應(yīng)該在

13、應(yīng)用程序處于空閑期間調(diào)用CoFreeUnusedLibraries()API。這個(gè)API將卸載任何沒有明顯引用的COM服務(wù)器,因此這也降低了應(yīng)用程序使用的內(nèi)存開銷。繼續(xù)用上面的例子來說明如何使用Release。:像上面一樣創(chuàng)建對(duì)象,然后,用調(diào)用方法通知對(duì)象不再使用它接下來將詳細(xì)討論IUnknown接口?;窘涌贗Unknown每一個(gè)COM接口都派生于IUnknown。這個(gè)名字有點(diǎn)誤導(dǎo)人,其中沒有未知(Unknown)接口的意思。它的原意是如果有一個(gè)指向某COM對(duì)象的IUnknown指針,就不用知道潛在的對(duì)象是什么,因?yàn)槊總€(gè)COM對(duì)象都實(shí)現(xiàn)IUnknown。IUnknown有三個(gè)方法:AddRe

14、f()通知COM對(duì)象增加它的引用計(jì)數(shù)。如果你進(jìn)行了一次接口指針的拷貝,就必須調(diào)用一次這個(gè)方法,并且原始的值和拷貝的值兩者都要用到。在本文的例子中沒有用到AddRef()方法。Release()通知COM對(duì)象減少它的引用計(jì)數(shù)。參見前面的Release()示例代碼段。QueryInterface()從COM對(duì)象請(qǐng)求一個(gè)接口指針。當(dāng)coclass實(shí)現(xiàn)一個(gè)以上的接口時(shí),就要用到這個(gè)方法。前面已經(jīng)看到了Release()的使用,但如何使用QueryInterface()呢?當(dāng)你用CoCreateInstance()創(chuàng)建對(duì)象的時(shí)候,你得到一個(gè)返回的接口指針。如果這個(gè)COM對(duì)象實(shí)現(xiàn)一個(gè)以上的接口(不包括IU

15、nknown),你就必須用QueryInterface()方法來獲得任何你需要的附加的接口指針。QueryInterface()的原型如下:以下是參數(shù)解釋:iid所請(qǐng)求的接口的IID。ppv接口指針的地址,Querylnteface()通過這個(gè)參數(shù)在成功時(shí)返回這個(gè)接口。讓我們繼續(xù)外殼鏈接的例子。它實(shí)現(xiàn)了IShellLink和IPersistFile接口。如果你已經(jīng)有一個(gè)IShellLink指針,pISL,可以從COM對(duì)象請(qǐng)求IPersistFile接口:HRESULThr;IPersistFile*pIPF;hr=pISL-QueryInterface(IID_IPersistFile,(vo

16、id*)&pIPF);然后使用SUCCEEDED宏檢查hr的值以確定QueryInterface()的調(diào)用情況,如果成功的話你就可以象使用其它接口指針那樣使用新的接口指針,pIPF。但必須記住調(diào)用pIPF-Release()通知COM對(duì)象已經(jīng)用完這個(gè)接口。仔細(xì)做好串處理這一部分將花點(diǎn)時(shí)間來討論如何在COM代碼中處理串。如果你熟悉Unicode和ANSI,并知道如何對(duì)它們進(jìn)行轉(zhuǎn)換的話,你就可以跳過這一部分,否則還是讀一下這一部分的內(nèi)容。不管什么時(shí)候,只要COM方法返回一個(gè)串,這個(gè)串都是Unicode串(這里指的是寫入COM規(guī)范的所有方法)。Unicode是一種字符編碼集,類似ASCII,但用兩個(gè)

17、字節(jié)表示一個(gè)字符。如果你想更好地控制或操作串的話,應(yīng)該將它轉(zhuǎn)換成TCHAR類型串。TCHAR和以_t開頭的函數(shù)(如_tcscpy()被設(shè)計(jì)用來讓你用相同的源代碼處理Unicode和ANSI串。在大多數(shù)情況下編寫的代碼都是用來處理ANSI串和ANSIWindowsAPIs,所以在下文中,除非另外說明,我所說的字符/串都是指TCHAR類型。你應(yīng)該熟練掌握TCHAR類型,尤其是當(dāng)你閱讀其他人寫的有關(guān)代碼時(shí),要特別注意TCHAR類型。當(dāng)你從某個(gè)COM方法返回得到一個(gè)Unicode串時(shí),可以用下列幾種方法之一將它轉(zhuǎn)換成char類型串:1、調(diào)用WideCharToMultiByte()API。2、調(diào)用CR

18、T函數(shù)wcstombs()。3、使用CString構(gòu)造器或賦值操作(僅用于MFC)。4、使用ATL串轉(zhuǎn)換宏。WideCharToMultiByte()你可以用WideCharToMultiByte()將一個(gè)Unicode串轉(zhuǎn)換成一個(gè)ANSI串。此函數(shù)的原型如下:以下是參數(shù)解釋:CodePageUnicode字符轉(zhuǎn)換成的代碼頁(yè)。你可以傳遞CP_ACP來使用當(dāng)前的ANSI代碼頁(yè)。代碼頁(yè)是256個(gè)字符集。字符0127與ANSI編碼一樣。字符128255與ANSI字符不同,它可以包含圖形字符或者讀音符號(hào)。每一種語(yǔ)言或地區(qū)都有其自己的代碼頁(yè),所以使用正確的代碼頁(yè)對(duì)于正確地顯示重音字符很重要。dwFlag

19、sdwFlags確定Windows如何處理復(fù)合Unicode字符,它是一種后面帶讀音符號(hào)的字符。如e就是一個(gè)復(fù)合字符。如果這些字符在CodePage參數(shù)指定的代碼頁(yè)中,不會(huì)出什么事。否貝|,Windows必須對(duì)之進(jìn)行轉(zhuǎn)換。傳遞WC_COMPOSITECHECK使得這個(gè)API檢查非映射復(fù)合字符。傳遞WC_SEPCHARS使得Windows將字符分為兩段,即字符加讀音,如e。傳遞WC_DISCARDNS使得Windows丟棄讀音符號(hào)。傳遞WC_DEFAULTCHAR使得Windows用lpDefaultChar參數(shù)中說明的缺省字符替代復(fù)合字符。缺省行為是WC_SEPCHARS。lpWideChar

20、Str要轉(zhuǎn)換的Unicode串。cchWideCharIpWideCharStr在Unicode字符中的長(zhǎng)度。通常傳遞-1,表示這個(gè)串是以0 x00結(jié)尾。lpMultiByteStr接受轉(zhuǎn)換的串的字符緩沖cbMultiByteIpMultiByteStr的字節(jié)大小。lpDefaultChar可選當(dāng)dwFlags包含WC_COMPOSITECHECK|WC_DEFAULTCHAR并且某個(gè)Unicode字符不能被映射到同等的ANSI串時(shí)所傳遞的一個(gè)單字符ANSI串,包含被插入的缺省字符。可以傳遞NULL,讓API使用系統(tǒng)缺省字符(一種寫法是一個(gè)問號(hào))。lpUsedDefaultChar可選指向BO

21、OL類型的一個(gè)指針,設(shè)置它來表示是否缺省字符曾被插入ANSI串??梢詡鬟fNULL來忽略這個(gè)參數(shù)。我自己都有點(diǎn)暈菜了,萬(wàn)事開頭難啊,不搞清楚這些東西就很難搞清楚COM的串處理。何況文檔中列出的比實(shí)際應(yīng)用的要復(fù)雜得多。下面就給出了如何使用這個(gè)API的例子:假設(shè)已經(jīng)有了一個(gè)串代碼頁(yè)檢查重音字符原串意思是串以結(jié)尾目的字符串初始化庫(kù)(讓加載)。通常是在程序的0緩沖大小肥缺省字符串忽略這個(gè)參數(shù)調(diào)用這個(gè)函數(shù)后,將包含串的版本。wcstombs()這個(gè)CRT函數(shù)wcstombs()是個(gè)簡(jiǎn)化版,但它終結(jié)了WideCharToMultiByte()的調(diào)用,所以最終結(jié)果是一樣的。其原型如下:以下是參數(shù)解釋:mbst

22、r接受結(jié)果ANSI串的字符(char)緩沖。wcstr要轉(zhuǎn)換的Unicode串。countmbstr參數(shù)所指的緩沖大小。wcstombs()在它對(duì)WideCharToMultiByte()的調(diào)用中使用WC_COMPOSITECHECK|WC_SEPCHARS標(biāo)志。用wcstombs()轉(zhuǎn)換前面例子中的Unicode串,結(jié)果一樣:wcstombs(szANSIString,wszSomeString,sizeof(szANSIString);CStringMFC中的CString包含有構(gòu)造函數(shù)和接受Unicode串的賦值操作,所以你可以用CString來實(shí)現(xiàn)轉(zhuǎn)換。例如:/假設(shè)有一個(gè)Unicode串wszSomeStringCStringstr1(wszSomeString);/用構(gòu)造器轉(zhuǎn)換CStringstr2;str2=wszSomeString;/用賦值操作轉(zhuǎn)換ATL宏ATL有一組很方便的宏用于串的轉(zhuǎn)換。W2A()用于將Unicode串轉(zhuǎn)換為ANSI串(記憶方法是widetoANSI寬字符到ANSI)。實(shí)際上使用OLE2A()更精確,OLE表示的意思

溫馨提示

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

最新文檔

評(píng)論

0/150

提交評(píng)論