Can you summarize the following document?
        
  COM的核心是一組元件物件間互動的規範,定義了元件物件如何與其使用者通過二進位制介面標準進行互動,COM的介面是元件的型別紐帶。  除了規範之外,COM還是一個稱為“COM庫”的實現,包括若干API函式,用於COM程式的建立與使用。  COM還提供定位服務的實現,可以根據Windows系統登錄檔,從一個類標識(CLSID)來確定元件的位置。  COM採用自己的IDL來描述元件的介面(interface),支援多介面,解決版本相容問題。COM為所有元件定義了一個共同的父介面IUnknown。GUID 是一個 128 位整數(16 位元組),COM將其用於計算機和網路的唯一識別符號。  除了基本規範和系統實現之外,COM的構成還包括永久儲存、綽號(moniker智慧命名/標記)和統一資料轉移(UDT = Uniform Data Transfer)三個核心的作業系統部件。  COM實質上是一種語言無關的物件實現方式,這使其可以在建立環境不同的場合、甚至跨計算機的分佈環境下被複用。COM允許複用這些物件,而不必知道物件內部是如何實現,因為元件實現者必須提供良好定義的介面從而遮蔽實現細節。通過引用計數,元件物件自己負責動態建立與銷燬,從而遮蔽了不同程式語言之間的記憶體分配語義差異。在COM介面之間的型別轉換通過QueryInterface方法。  對於某些應用程式來說,COM已經部分被.NET框架取代。COM通過Windows Communication Foundation(WCF)支援Web Service。COM物件通過.NET COM Interop可以被所有.NET語言使用。網路化的DCOM使用二進位制私有格式,而WCF鼓勵使用基於XML的SOAP訊息機制。COM非常類似其他軟體元件介面技術,如CORBA與JavaBeans,它們各自有其優點與弱點。  與C++不同,COM提供了一個穩定的應用二進位制介面(ABI),不隨編譯器版本而改變 。

  早在1988年,微軟的Anthony Williams的論文“Object Architecture: Dealing with the Unknown or Type Safety in a Dynamically Extensible Class”以及1990年的“On Inheritance: What It Means and How To Use it”論文奠定了COM的理論基礎。  Windows作業系統提供了三種程序間的通訊機制:剪貼簿、DDE與OLE。OLE原名是物件連結與嵌入(Object Linking and Embedding),OLE可以說是DDE的改良版。1992年,OLE 1.0版隨Windows 3.1作業系統釋出,提供複合文件(compound document)處理,但它過於複雜,Brockschmidt, Kraig的「Inside OLE」一書中提到,必須經過六個月的心靈混沌期,才能瞭解OLE是什麼。1993年,COM架構隨OLE 2.0第一次公開發布。在微軟Office套件中,COM取代了OLE。這成為COM技術戰勝Windows 95團隊開發的其他物件技術的關鍵因素。  1996年,為應對CORBA,DCOM隨Windows NT 4 Option Pack釋出。  1999年,Windows 2000釋出了COM+,關注MTS,並放棄了DCOM這個名稱。

  COM是基於元件物件方式概念來設計的,在基礎中,至少要讓每個元件都可以支援二個功能:  這二個功能即為COM的根:codice_1介面所提供的codice_2,codice_3及codice_4三個方法的由來。所有的COM元件都要實作codice_1,表示每個COM元件都有相同的能力。  只由COM衍生實作出來的元件,稱為純COM元件。  但在Windows持續發展時,Visual Basic 4.0開始支援OCX,也就是OLE Custom Control,這讓微軟開始思考要如何讓COM元件可以跨語言支援,在這樣的要求下,必須要提供一個一致的介面,以及提供一組可以呼叫介面內方法的能力,由於純COM元件只能夠支援C/C++的直接存取,為了要達到跨語言的能力,在COM中必須要支援在外部呼叫內部方法的機能,這個機能造就了codice_6方法,另外為了跨語言的支援,COM應該要提供簡單的元件存取識別方式,這也就是會有codice_7的原因,將這些方法組合起來,定義出的必要介面,稱為codice_8介面,所有實作此介面的,都可以支援跨語言的支援。  微軟將實作此介面的元件都稱為自動化(Automation)元件。

  COM曾是Windows平臺下主要的軟體開發平臺,並且影響至其他許多相關軟體技術。

  COM+是微軟Windows 2000中,Microsoft Transaction Server的強化實作版本,除了提供基本的元件交易支援外,還提供了鬆散藕合式事件(loosely-coupled events)與物件共享池(object pooling)等應用程式伺服器的能力,成為Windows 2000開始在微軟平臺上主要的應用程式伺服器平臺,目前.NET Framework也提供了System.EnterpriseServices名稱空間以支援COM+。

  Distributed COM是依據RPC(Remote Procedure Call)的規範發展的可以在網路上通訊的COM元件,它將COM元件的能力擴及到網路上,但因為網路安全以及防火牆因素,DCOM無法廣泛的流行。

  .NET Framework是新一代的Microsoft Windows應用程式開發平臺。使用C#開發COM元件,首先建立型別為Class Library的專案,然後在專案的Property中進入Build頁,對“Register for COM interop”選項打勾。開啟AssemblyInfo.cs檔案,設定[assembly: ComVisible(true)],這樣就可以生成.tlb檔案。源程式示例如下:

  不同的COM元件型別用類ID(CLSID)標示,這是一種全域性唯一識別符號(GUID)。每個COM元件用一個或多個介面來暴露其功能。這些介面也採用GUID唯一標識,稱為介面ID(IID)。  COM介面與幾種程式語言有語言繫結,如C語言、C++、Visual Basic、Delphi語言、Python以及Windows平臺上的幾種指令碼語言。它們都是通過介面的方法來訪問元件。

  所有COM元件都實現了IUnknown介面,該介面暴露了引用計數實現的物件生命期管理與型別轉換,以訪問不同的預定義介面。  IUnknown介面以及基於IUnknown的定製介面包括一個指向虛擬函式表的指標,虛擬函式表中包含若干函式指標,分別指向介面所宣告的函式實現。對於程序內的COM元件呼叫,其效率等同於C++的虛擬函式呼叫。  除了基於IUnknown的定製介面,COM也支援繼承自IDispatch的dispatch介面,從而支援了用於OLE自動化的晚繫結。不能訪問定製介面的程式語言(例如VBS)可以通過dispatch介面訪問COM元件。  Windows API提供了C語言定義COM介面的方法:

  COM類(coclass)是一個或多個介面的具體實現,它很類似物件導向程式設計語言中的類。類的GUID標識被稱作類ID(CLSID);或者programmatic identifier字串(progid),因為VBS等指令碼語言不能使用GUID,只能用字串查詢、使用COM元件。  COM物件不能被直接訪問,只能通過COM介面來訪問物件。COM也支援同一個介面的多個實現,因此客戶程式執行時可以選擇例項化介面的哪個實現。

  型別庫(type library)包含著COM型別的後設資料。這些型別採用微軟介面定義語言(MIDL)描述。  IDL檔案定義了類、介面、結構、列舉與其他使用者定義型別。IDL類似於C++的宣告,使用了一些額外的關鍵字如interface、library等。IDL還支援在宣告前給出方括號屬性(bracketed attribute)以提供額外資訊,如介面的GUID、指標引數與長度域之間的關係等。  MIDL編譯器用來編譯IDL檔案,產生編譯器獨立的標頭檔案。標頭檔案包含了IDL檔案中宣告的介面對應的結構定義。結構只包含一項成員,即指向在介面中宣告函式的地址表的指標(vtbl),以模仿C++對虛擬函式的實現。標頭檔案還包含了類與介面等的GUID的常量的定義。MIDL編譯器也可以產生C++原始檔,包含代理模組(proxy module),用以把COM呼叫轉為遠端過程呼叫,以支援跨程序的DCOM通訊。  IDL檔案也可以被MIDL編譯器生成型別庫(TLB)檔案codice_9,以供其他語言編譯器與執行時環境使用,如VB、Delphi、.NET等生成語言相關表示COM型別的結構。C++把TLB轉回到IDL表示。

  使用C++的預編譯directivecodice_10,可以裝入如下格式的型別資訊: codice_10建立兩個標頭檔案以用C++原始碼形式恢復型別庫資訊: 兩個檔案被放在輸出目錄中。編譯器在現場就地codice_12主標頭檔案。  型別庫主標頭檔案(.TLH)包含七部分: 從第2至第6部分都包含在名稱空間中,其名字在最初的IDL檔案的codice_16語句中給出。改名字在codice_10語句中可用屬性no_namespace抑制掉;也可用rename_namespace屬性更名。

  COM是一個執行時框架,型別必須在執行時單獨地標識並可指定。為此,使用GUID,每個COM型別被指定了它自己的GUID用於執行時標識。這也解決了C/C++語言的名字修飾導致的連結相容性問題。  為了使COM型別資訊在編譯時與執行時都可以訪問,COM使用型別庫。這使得COM成為物件互動的動態框架。  考慮下述用IDL定義coclass的例子:  上述程式碼框架宣告瞭一個COM類,稱為codice_18,實現了介面codice_19。  這在概念是等價於下述C++類:  其中ISomeInterface是一個C++虛基類。  包含COM介面與類的IDL檔案被編譯為型別庫(TLB)檔案。客戶程式可以在執行時分析型別庫檔案,以確定物件支援哪些介面,然後呼叫物件的介面方法。  C/C++程式以類ID(CLSID)與介面ID(IID)作為引數,用codice_20函式例項化COM物件。codice_18的例項化程式碼如下:  在這個例子中,使用COM子系統獲取指向codice_19介面的實現物件的指標,用CLSID_SomeClass指示用這個特定的coclass。

  所有COM物件採用引用計數管理物件的生命期。客戶程式通過所有COM物件都要強制實現的IUnknown介面的AddRef與Release方法來控制引用計數。當引用計數降到0時,COM物件自己負責釋放記憶體。即對動態分配記憶體建立的COM物件,其Release函式內部引用計數降為0時,就釋放自身所佔的動態分配記憶體。有的COM物件(如IClassFactory)往往是靜態物件,Release函式內部引用計數降為0時不需做額外的操作。  特定語言(例如Visual Basic)提供了自動引用計數,所以COM物件開發者在原始碼中不需要顯式維護任何內部的引用計數。C/C++程式設計者或者執行顯式的引用計數,或者使用智慧指標(如MFC提供的CComPtr)自動管理引用計數。  下述是如何呼叫COM物件的AddRef與Release的指引:  不向遠端物件發出引用計數的呼叫。代理模組保持著遠端物件的一個引用,並維持著它自己的本地引用計數。  為簡化COM開發,引入了活動模板庫(Active Template Library,ATL)用於C++開發。ATL提供了更高層次的COM開發正規化。ATL也有益於COM客戶應用程式開發擺脫直接維護引用計數,而是用智慧指標物件。  其他能直接支援COM的庫與語言還包括MFC Visual C++編譯器的COM支援、VBScript、Visual Basic、ECMAScript(JavaScript)和Borland Delphi等。

  COM是一個語言獨立的二進位制標準,任何能夠理解與實現COM的二進位制定義的資料型別與介面的語言都可以開發COM元件。  COM實現負責進入、離開COM環境,例項化與引用計數COM物件,查詢物件支援的介面,以及錯誤處理。  Microsoft Visual C++編譯器支援對C++語言的擴充套件:稱作"C++ Attributes"。這些擴充套件被設計用於簡化COM開發,去除實現COM伺服器時大量臃腫的程式碼。

  在Windows作業系統中,COM類、介面、型別庫都會根據其GUID登記到Windows登錄檔。HKEY_CLASSES_ROOT\CLSID下是COM類;HKEY_CLASSES_ROOT\Interface下是介面。COM型別庫註冊在每個COM物件的本地庫條目下或者遠端服務的網路位置處。

  不使用登錄檔的COM(RegFree COM)是Windows XP引入的技術,允許COM元件不在登錄檔中存期啟用的後設資料與類ID(CLSID),而是在實現類的assembly manifest或者儲存在可執行檔案的資源中或元件安裝時的單獨檔案中。這使得同一元件的不同版本可以安裝在不同目錄下,用其各自的manifest描述,直接複製安裝。這種技術有限支援EXE COM伺服器且不能用於系統範圍元件如MDAC、MSXML、DirectX或Internet Explorer。  應用程式裝入時,Windows裝入器搜尋manifest。如果存在,裝入器從它增加資訊到啟用上下文。COM類工廠試圖例項化一個類時,啟用上下文首先檢查這個CLSID的實現是否可以找到。僅當查詢失敗時,才掃描Windows登錄檔。

  COM物件可以透明地例項化與引用在同一程序、跨程序邊界、甚至在網上遠端(DCOM)。程序外或遠端物件用marshalling序列化方法呼叫與返回值。這種marshalling對使用者是不可見的,就如同訪問程序內的COM物件。

  一個程序載入了一個COM的DLL檔案後,該DLL可能定義並使用了一些可修改的全域性變數或訪問共享資源。該程序內的多個執行緒如何併發訪問該DLL並保證是執行緒安全的,這就是“套間”(apartment)技術需要解決的問題。  COM物件與建立或呼叫COM物件的執行緒可以按兩種策略來實現併發安全:  COM的併發安全的具體實現,提出了套間(apartment)概念。每一種套間型別表示在一個程序內部是多執行緒情況下,如何同步對COM物件的呼叫。套間是一個邏輯容器,收納遵循相同執行緒訪問規則的COM物件與COM執行緒(建立了COM物件的執行緒或者呼叫了COM物件的方法的執行緒)。套間本質上只是一個邏輯概念而非物理實體,沒有控制代碼型別可以引用它,更沒有可呼叫的API操縱它。套間有兩種:  一個COM物件只能存在於一個套間。COM物件一經建立就確定所屬套間,並且直到銷燬它一直存在於這個套間。COM物件有4種套間模式:單執行緒套間(Single Threading Apartment,STA),多執行緒套間(MTA),執行緒中立套間(Thread Neutral Apartment,NA),以及Both(STA+MTA)。詳見下表。COM物件的套間型別寫在Windows登錄檔相關條目中。  一個COM執行緒從建立到結束都屬於同一個套間。COM執行緒只有兩種套間模式:STA或MTA。執行緒必須通過呼叫CoInitializeEx()函式並且設定引數為COINIT_APARTMENTTHREADED或者COINIT_MULTITHREADED,來指明該執行緒的套間模式。呼叫了CoInitializeEx()函式的執行緒即已進入套間,直到執行緒呼叫CoUninitialize()函式或者自身終止,才會離開套間。COM為每個STA的執行緒自動建立了一個隱藏視窗,其Windows class是"OleMainThreadWndClass" 。跨套間呼叫這個STA套間內的COM物件,實際上是向這個隱藏視窗傳送了一條視窗訊息,通過訊息迴圈與分派,該視窗過程收到這條視窗訊息並呼叫相應的COM物件的介面方法。  執行緒與屬於同一套間的物件遵循相同的執行緒訪問規則,可以直接執行方法呼叫而不需COM的輔助。執行緒跨套間邊界去呼叫COM物件,傳遞的指標需要marshalling。如果通過標準的COM的API來呼叫,可以自動完成安整。例如,把一個COM介面指標作為引數傳遞給另外一個套間的COM物件的proxy的情形。但如果軟體程式設計者跨套間傳遞介面指標而沒有使用標準COM機制,就需要手工完成安整(通過CoMarshalInterThreadInterfaceInStream函式)與反安整(通過CoGetInterfaceAndReleaseStream函式獲取COM介面的proxy)。例如,把COM介面指標作為執行緒啟動時的引數傳遞的情形。  跨程序的呼叫COM物件類似於同一程序內跨套間的呼叫COM物件。

  

  STA初始化時,建立一個隱藏視窗,用於apartment之間、程序間的訊息路由。該視窗必須有正常的訊息佇列泵。這種結構稱為訊息泵。早期版本的Windows,訊息泵的失敗會導致系統範圍的死鎖。這個問題被初始化COM的Windows API複雜化了,並會導致實現細節的洩露。

  如果多個物件是迴圈引用,則可能會導致問題。  Objects may also be left with active reference counts if the 使用COM事件池(event sink)模型,則物件可能一直保持活動的引用計數而不能被銷燬。因為傳送事件的物件必須有處理事件的物件的引用,因而物件引用計數永遠不為0.  引用迴圈可以採取下述技術來克服:

  程序內的COM元件是用DLL檔案實現,每個版本的DLL用CLSID登記到Windows登錄檔,因而某些情況下會發生DLL Hell效應。無需註冊的COM克服了這一問題。

  COM元件間的約定,純粹是通過使用者與元件之間的語義保證和假設的形式來表示的。COM用型別的形式表示元件約定。但是該約定存在如下兩個關鍵問題,使得其對語義的表示並不是最優的。
元件物件模型(英語:Component Object Model,縮寫英語:COM)是微軟的一套軟體元件的二進位制介面標準。這使得跨程式語言的程序間通訊、動態物件建立成為可能。COM是多項微軟技術與框架的基礎,包括OLE、OLE自動化、ActiveX、COM+、DCOM、Windows shell、DirectX、Windows Runtime。