?? 205.htm
字號:
<html><body><span id=Layer1><p><font size=2 color=#3c3c3c face=arial>對於Microsoft Windows 2000,沒有任何軟體開發技術比元件物件模型還要更基本的了。幾乎每個在這個平臺上或Microsoft其它作業系統上撰寫的應用程式都會使用COM。即使跨多個系統執行的應用程式也能使用增強型式的COM,就是所謂的分散式的COM(Distributed COM,DCOM)。</span><span id=Layer2></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>為Windows 2000撰寫軟體表示使用COM</span><span id=Layer3></font></p><hr><p><font size=2 color=#3c3c3c face=arial>Windows 2000引進了COM+,它是這個核心技術的延伸版本。本章將詳細地介紹COM的基本,大部份的技術和COM+是一樣沒有改變的。若要詳細了解COM+的特性,可參考</span><span id=Layer4> <a href=208.htm# target=_new>第八章</span><span id=Layer5></a> 。</span><span id=Layer6></font></p><a name=205001><font color=#3e70d7 face=arial size=5><b>了解COM物件</span><span id=Layer7></b></font><p><font size=2 color=#3c3c3c face=arial>在COM中,客戶端存取COM物件所提供的服務。第一個該回答的問題便是:什麼是一個COM物件?就像其它的類型的物件一樣,一個COM物件就是一個抽象的軟體,封裝兩個東西:資料與method。一個物件的資料,也稱為它的狀態,就是指物件儲存在記憶體中的資訊,而它的method就是它的程式碼,允許物件提供它的服務。舉例來說,一個COM物件允許銷售員開出的訂單內包含訂單明細資料,這些資料是訂單的一部份,以及訂單建立的時間。這個物件的method包含將訂單項目加到訂單、提交訂單、判斷訂單建立的時間...等等方法。</span><span id=Layer8></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>一個COM物件有兩樣東西:資料和method</span><span id=Layer9></font></p><hr><p><font size=2 color=#3c3c3c face=arial>就類似在程式語言中的method一樣,一個COM物件的method可以擁有參數。舉例來說,一個新增一個項目到訂單的method可能夾帶一個整數參數,其中包含欲新增訂單項目的數量。在COM中,method必須組成介面,而每個COM物件都要實作一些介面。(實際上數目上總是超過一個,理由稍後再解釋。)舉例來說,剛提及的訂單物件可能會將所有建立一份訂單用到的所有method組成一個介面,所有用來處理與訂單相關資訊的method,如建立訂單,可能會組成第二個介面。介面只顯露一個物件的method,資料已封裝,只能透過物件實作的介面中的method存取。如</span><span id=Layer10> <a href=201.htm# target=_new>第一章</span><span id=Layer11></a> 所展示的一樣,物件提供的每一個介面在慣例上是使用一個小圈圈連結到一個物件來表示。</span><span id=Layer12></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>許多Method組成許多介面</span><span id=Layer13></font></p><hr><p><font size=2 color=#3c3c3c face=arial>每個COM物件都有一個或多個客戶端使用它的服務之軟體。若要存取一個物件的服務,客戶端必須呼叫物件所提供的method。在呼叫特定介面上的method之前,客戶端必須要求指向那個介面的介面指標。一切端賴客戶端所使用的程式開發語言的不同,客戶端不一定可以看到真正的指標;不過不管它看起來像什麼樣子,它允許客戶端呼叫它所參考到的介面內的method。就如圖5-1中顯示,客戶端握住同一個COM物件的多個介面指標是很平常的事,每一個介面一個指標,指向它欲呼叫的介面。</span><span id=Layer14></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>客戶端使用介面指標呼叫method</span><span id=Layer15></font></p><hr><br><center><a target=_new href=imagesh/5-1.gif><img border=0 src='imagesl/5-1.gif'></a></center></span><span id=Layer16><center><table border=0 ><td align=center><font color=#3c3c3c face=arial size=2><font size=2 face=arial color=#3e80d7><b> 圖5-1</span><span id=Layer17> </b></font>若要呼叫特定介面上的method,客戶端必須握住指向那個介面的介面指標。</span><span id=Layer18></td></table></font></center><p><font size=2 color=#3c3c3c face=arial>在更深入探討介面之前,得要強調一下COM物件可以使用許多不同的程式開發語言建立。事實上,一個COM物件與它的客戶端可能,或者也可能不是以同一種程式語言寫成的。因為COM定義了與語言獨立的一種標準,以供客戶端和物件進行互動。COM程式設計師最普遍的選擇便是Microsoft Visual Basic、C++與Java,但現在幾乎所有在Windows 2000上與Microsoft其它作業系統的開發工具都能夠支援COM。這叁種最流行的語言每一種都對物件有自己的解釋。這些概念幾乎是很類似的,也和COM對物件的定義相近,但是它們并不是完全相同。撰寫使用COM的軟體需要了解COM對物件的觀點:它們都是相同的,不管使用的程式語言是哪一種,然後看看這些觀點要如何對應到特定的程式語言。</span><span id=Layer19></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>COM物件可讓許多不同的程式開發語言使用</span><span id=Layer20></font></p><hr><p><font size=2 color=#3c3c3c face=arial>不用太訝異,C++的程式設計師要了解的最詳細,如果選擇使用COM的話,就得很痛苦地了解COM的低階部份。他們也可以使用高階的開發工具,如現在流行的Microsoft ActiveX Template Library (ATL) 來隱藏許多的細節。對照之下,對Visual Basic的程式設計師而言,COM的細節已完全隱藏起來了。因此在Visual Basic中使用COM就變得很簡單,但有時也令人很 氣。Visual Basic/COM的對照不見得都相同。最後,很意外地,Java對物件原生的觀點和COM非常類似。Microsoft的Java virtual machine (JVM)的偉大功勛便是支援Java物件到COM物件直接的對應,反之亦然。若使用Microsoft JVM,Java可能是COM程式設計師最自然的語言,為的就是這兩類物件最簡單直覺的對應關系了。</span><span id=Layer21></font></p><font color=#3e72d7 face=arial size=4><b>介面(Interface)</span><span id=Layer22></b></font><p><font size=2 color=#3c3c3c face=arial>在COM中,整體看來一個客戶端從來就不會握住一個正在執行的物件之參考。而是客戶端盡透過呼叫介面指標來呼叫物件的method與其互動。從客戶端的觀點,一個COM物件主要可視為一群介面的集合。不管用來撰寫物件的語言為何,COM介面永遠符合一個定義在記憶體中的結構。為了讓客戶端呼叫物件上的method,透過正確的記憶體布局,COM讓使用某一種語言撰寫的COM物件和其它語言寫的物件相互溝通。</span><span id=Layer23></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>COM定義介面在記憶體中的結構</span><span id=Layer24></font></p><hr><p><font size=2 color=#3c3c3c face=arial><font size=2 face=arial color=#3e80d7><b> 介面的類型</span><span id=Layer25> </b></font>在一個完美的世界,一個介面的樣式可以用在所有客戶端與物件的組合。然而在不完美的世界里,COM的存在就不是那麼回事了,因此便存在著叁種不同類型的COM介面。在COM的演進過程中,每一種介面都是為了特殊的理由存在的,如果COM是在今天建立的,那麼這些差異點可能就不存在了。</span><span id=Layer26></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>COM擁有叁種類型的介面</span><span id=Layer27></font></p><hr><p><font size=2 color=#3c3c3c face=arial>第一個選擇,vtable介面,最原始是為C++設計的。也就是所謂的自訂介面,它們記憶體中的結構映照到流行的C++編譯器中method呼叫的方式(包含Microsoft Visual C++)。如此在C++中實作vtable介面的動作就變得相當簡單,并能很有效地透過vtable介面呼叫C++撰寫的物件之method。</span><span id=Layer28></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>第一種介面類型,vtable介面,最初是為C++定義的</span><span id=Layer29></font></p><hr><p><font size=2 color=#3c3c3c face=arial>今天,vtable介面也能夠很簡單、快速,并普遍地在Visual Basic與Java中使用。不過當COM在1993年初次發表時,vtable介面并不適合Visual Basic使用。還有一點,Visual Basic程式在呼叫使用C++導向的介面結構之method時仍有一些挑戰。不過對Visual Basic來說這不是vtable介面帶來的唯一問題。對任何技術來說,還有一個更棘手的問題,便是如何讓以不同程式語言撰寫的客戶端與物件互動:如何轉換某種語言的資料型態到另一種語言定義的資料型態呢?假設一個使用C++撰寫的物件將要給Visual Basic客戶端使用,那麼若這個物件介面中其中一個method實作時,以一個指標當做參數,這會發生什麼事? Visual Basic并不支援指標,因此要從Visual Basic客戶端呼叫這個method便成為一件不可能的事。當兩個語言牽涉到兩者都支援一種特殊的資料型態,但卻以不同的方式來處理時,一個更微妙但無傷大雅的問題就發生了。舉例來說,C++與Visual Basic兩者都支援字元字串,不過它們處理字串的方式卻有天壤之別。這些問題該怎麼解決呢?</span><span id=Layer30></font></p><p><font size=2 color=#3c3c3c face=arial>COM一開始的答案便是定義第二類型的介面,通常稱為分派介面(dispatch interface),但更常被稱為dispinterface。dispinterface可讓Visual Basic程式能夠有效地實作COM物件,并能扮演COM物件的客戶端。Dispinterface在記憶體中的結構與vtable的結構有一些不同,以便讓Visual Basic更容易呼叫method。(事實上,每個dispinterface依賴於一個特定的vtable介面,稱IDispatch。)同樣地,在dispinterface中,method的參數只限定於某些資料型態。和vtable介面不一樣的地方在於,vtable介面的method能接受的參數是限定在C++中定義的型態;dispinterface的資料型態基本上只限制於Visual Basic中可用的(雖然dispinterface同樣也可以在Java中使用)。因為使用dispinterface有時也稱做自動化(automation),所以一個介面的參數型態如果遵循這個限制就可稱為自動化相容(automation-compatible)。</span><span id=Layer31></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>第二個介面類型,dispin-terface,一開始是為了Visual Basic而定義的</span><span id=Layer32></font></p><hr><p><font size=2 color=#3c3c3c face=arial>當參數傳送到一個dispinterface method,或從這個method傳出時,這些參數都是包裝成一個或多個Variant。一個Variant包含任何自動化相容型態的值,同樣的也包含一個指示,指明它的資料型態。舉例來說,一個特定的Variant可能包含某些整數值,以及一個標注(Tag)指明它的資料是一個長整數。Variant對於Visual Basic程式設計師來說是很方便的,Visual Basic會為你進行所有將參數轉換成這個格式的動作,反之亦然。</span><span id=Layer33></font></p><p><font size=2 color=#3c3c3c face=arial>今天,Visual Basic又提升了,它現在可以讓Visual Basic的客戶端使用vtable,以及這些自動化相容的介面來存取或實作COM物件。而第叁種可用的介面是,Dual Interface。一個Dual Interface基本上將vtable與dispinterface在記憶體中的結構組合在一起,允許使用任一種介面的樣式來呼叫method。然而dual Interface仍是自動化相容的,以便適用於Visual Basic與Java。事實上,使用Visual Basic建立的COM物件預設便是使用dual Interface來顯露它們的method。</span><span id=Layer34></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>第叁個介面類型,dual interface,合并了前兩種介面類型</span><span id=Layer35></font></p><hr><p><font size=2 color=#3c3c3c face=arial><font size=2 face=arial color=#3e80d7><b> 辨識介面</span><span id=Layer36> </b></font>若要呼叫特定介面上的method,客戶端必須取得指向某個執行中的COM物件其介面的指標。正確完成這個動作的過程將於稍後描述,不過很明顯的,客戶端若要取得這個指標得靠某些方式來辨識自己感興趣的介面。換句話說,介面必須擁有名稱。</span><span id=Layer37></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>每一個介面要有名稱</span><span id=Layer38></font></p><hr><p><font size=2 color=#3c3c3c face=arial>在COM中,每個介面都擁有兩個名稱。其中一個名稱是讓人使用的,因此它只是一個字元字串。根據命名原則,COM介面的名稱都是以字母「I」開始的。舉例來說,前面提到的訂單物件可能有一個類似IOrderEntry與IOrderStatistics的名稱。當你談論到COM物件,第一種樣式的名稱讓人很容易記得。</span><span id=Layer39></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>人類可以讀取的介面通常以「I」開頭</span><span id=Layer40></font></p><hr><p><font size=2 color=#3c3c3c face=arial>然而,這類介面的名稱并不是唯一的。有可能兩個不同的人(也完全地合法)定義兩個不同的介面,而名稱都是稱為,IMyInterface。為了要取得正確介面的介面指標,客戶端必須有某種方式來區分某個特定的介面。因此,每一個介面都需要有一個唯一可供辨別的名稱。</span><span id=Layer41></font></p><p><font size=2 color=#3c3c3c face=arial>因為第二類的名稱必需是唯一的,對使用者來說它并沒有太親切的名稱,它是要讓軟體使用的。因此每一個COM介面都指派一個值,也就是所謂的全域唯一識別碼(Universally Unique Identifier,UUID)或稱Globally Unique Identifier (GUID)。(這些術語通常交互使用,不過在本書中主要使用的是後者。) GUID是一個16位元組的值,在時間與空間上都是唯一的。指定到一個特定介面的GUID就是所謂的介面識別碼(interface identifier,IID)。一旦一個IID(也就是一個GUID)指定到一個介面,這個IID就可以永遠用來辨識這個介面。</span><span id=Layer42></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>每個介面也擁有一個全域唯一的IID</span><span id=Layer43></font></p><hr><p><font size=2 color=#3c3c3c face=arial>因為GUID是全域唯一的,所以每當你要定義一個新介面時,不能單單只產生一個GUID。有許多不同的方式可以取得GUID。最困難也最不常用的方式便是從Microsoft要求一個GUID。最簡單的方式便是在你的電腦上執行一個簡單的軟體工具。每當使用這個工具時,它便會產生一個新的GUID,而且保證是全域唯一的。GUID另一個重要的應用是當做IID,它們也可以用來當做其他東西的命名,我們將會看得到的。</span><span id=Layer44></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>GUID一向都是使用軟體工具建立的</span><span id=Layer45></font></p><hr><hr><font face=Arial Black color=#3e77d7 size=3><b>附注 </b></font><p><font size=2 color=#3c3c3c face=arial>為何能讓在不同臺機器上獨立執行的相同軟體,確能夠確保軟體產生的值都不相同呢?答案就在GUID所包含的東西。它的主要組成份子包含一個時間戳記(timestamp)指明建立的時間,以及安裝在GUID產生的這臺電腦之網路卡的Medium Access Control (MAC)位址。 時間戳記能確保在這臺機器上產生的每個GUID都是不同的,而MAC位址確保兩個同時產生的GUID不會相同,因為MAC位址是由一個集中的機構制定,每塊網卡的MAC位址在這個世界上都是唯一的。這使得GUID的產生相當容易,但仍可以確保唯一性。若要論及所牽涉到某些公司的安全性,則Windows 2000可以產生GUID,將MAC位址再做個包裝,而非全封不動地出現在GUID。</span><span id=Layer46></font></p><hr><p><font size=2 color=#3c3c3c face=arial><font size=2 face=arial color=#3e80d7><b> 定義介面</span><span id=Layer47> </b></font>一個COM介面是一個相當簡單的概念,它只定義了客戶端需要知道以便呼叫method的東西。因為COM使用許多方式來定義COM介面,所以你有許多種選擇。定義介面最正式也最強大的方式便是使用COM的介面定義語言(Interface Definition Language,IDL)。IDL的語法是由C衍生的,而COM的IDL事實上是基於Open Group的Distributed Computing Environment (DCE)定義的IDL。</span><span id=Layer48></font></p><hr><font face=Arial Black color=#3e77d7 size=3><b></b></font><p><font size=2 color=#3c3c3c face=arial>IDL可以用來定義介面</span><span id=Layer49></font></p><hr><p><font size=2 color=#3c3c3c face=arial>若前述的訂單項目的介面是一個vtable介面,它的IDL看起來可能如下:</span><span id=Layer50></font></p><div style="background-color: #D7D7D7;"><font face=Arial size=3><pre>[ object,, uuid(A7CD0D00-1827-11CF-9946-493655354000)]
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -