本文主要介紹 COM 的基礎知識,傾向於理論性的理解,面向初學者,淺嘗輒止。 1. COM 是什麼: COM 的英文全稱是,Component Object Model,中文譯為,組件對象模型。它官方的概念是:The Microsoft Component Object Model (COM) is ...
本文主要介紹 COM 的基礎知識,傾向於理論性的理解,面向初學者,淺嘗輒止。
1. COM 是什麼:
COM 的英文全稱是,Component Object Model,中文譯為,組件對象模型。它官方的概念是:The Microsoft Component Object Model (COM) is a platform-independent, distributed, object-oriented system for creating binary software components that can interact. 與其說 COM 是 System,更確切的說,應該叫做 Standard。因為它實際上是一套公共的 binary 標準,用於規定 software component 的介面的標準。也有人會把 COM 叫做 Common Object Model,但這其實是一種誤傳,起源於當初一名微軟的工作人員 Mark Ryland[1]!
但是,在長期的使用中,大家口中念叨的 COM 漸漸生出了各種各樣的含義,已經不僅僅是最初的含義了。這也是為什麼,對於初學者來說,理解起來特別費勁。因為總會查到層出不窮,又參差不齊的含義,讓人很疑惑到底哪個含義才是標準!
- 首先,在系統設計上,它是一種,設計理念,
- 然後,在 Object 的世界中,它是那個世界中的,規範和標準,
- 再然後,在編程語境下,它是一種,可以調用的,其他程式的介面,
- 再然後,在實際的電腦文件中,它多數是一個個 DLL 文件,
- 最後,在內部性質上,它是一個個二進位(Binary)的小程式,
其實在我 Research 的時候,這些概念也是最頭疼的地方。因為對 COM 概念的不瞭解,所以無法區分在不同視角,或者不同角度下的概念。而在 Research 的時候,往往會看到很多不同的網頁,給出各種 COM 的概念。而讓人頭疼的就是,這些概念都不統一,讓人無法理解。甚至開始懷疑,這些網頁真的都是說的同一個東西的概念麽?這種混亂,就是因為,不同的網站,在解釋 COM 的時候,用的是不同的角度。而同一個東西,在不同的角度和情景之下,自然會有不同的含義。所以,往往 COM 到底是什麼,要因情景而視之!但是,上面列出的幾個角度,已足以讓我們對 COM 的概念,構建出一個較為立體的理解了!
2. 科技歷史與 COM 的由來:
要瞭解 COM 的歷史由來,我們首先要從科技發展的歷史開始捋順下來。先說 Object Oriented 這種概念,其實,這種概念據說是19世紀60年代就有了,是源自於 MIT。但是那個時候 PC 還沒有普及,大多數公司使用的都是十分昂貴的大型機,微軟還沒有成立,這種情況下,自然對軟體的需求也是非常基本的,大多數停留在數學計算,文字處理,和軍事使用的範圍。而且那個時候,CPU 的概念都還沒出現,自然電腦也是不可能具備足夠的運算能力的。第一個 CPU,是 Intel 在 1971 年,為完成一家日本公司的訂單而設計發明的,自此才解鎖的計算的巨大潛力,進入了現代電腦的篇章。而 CPU 的發展與成熟,才造就了後來的軟體行業。微軟也於 1975 年正式成立。同年,IBM 也開始生產 Portable Computers。那時起,微型電腦開始變成潮流。Microsoft BASIC 這種最早期的編程語言,也誕生於 1975年。那時候,絕大多數的微型電腦,雖然系統都不同,但是幾乎都支持 BASIC 這種編程語言。正是這種編程語言,成為了日後微軟的基礎。1981年,微軟首次為 IBM 提供了操作系統,叫做 QDOC,是微軟的第一套系統,但卻是買來的,別人研發的系統。1983年,微軟研發出了 Lotus Software,是最早期的電子錶格軟體,這個軟體成為了 IBM 電腦上的明星軟體,裝機必備。後來 1985年 Windows 1 誕生了,同時伴隨著 Microsoft Excel 的誕生。自此之後,軟體行業開始變得日益繁榮,微軟也開啟了自己的軟體帝國。
軟體行業變得日益繁榮,但是 Object Oriented 這種思想,還並沒有發展到一定的高度。那時候,開發個軟體或者系統是非常麻煩,非常複雜的。日後,想給軟體添加一個功能,或者升級一個功能時,就更麻煩,因為,沒辦法獨立的,去更新,或者改進,某一個特定的功能。若想要添加新功能,需要全盤改動後,再重新進行編譯,非常的費時費力。於是人們就開始想辦法解決,上面這個問題,然後 Object Oriented Programming(面向對象的編程)的概念就開始興起。這時,雖然面向對象編程的概念已經興起,但是,還沒有統一的 Framework 或者說是標準,能讓不同軟體之間里的 Object 可以互相交流。於是,不同的軟體,就變成了一個個,孤立在大海中的小島,裡面住著一堆 Objects,無法和外界交流。人們想出的解決辦法就是,開發一個系統或者體系,在這個體系中,寫軟體的人只需要製造出,Software Component 就行了。而,這個 Component 就像是,買回來一個,方塊形的,電子配件一樣,插在我們自己的電路板上,就可以開始發揮作用。而這些,Software Component 外表上,必須遵循系統中的統一標準,而內部,就隨便怎麼編程都可以。後來,微軟在1993年,開發出了這個標準,這標準就被叫做,Component Object Model (COM)。
我們再把 COM 形成前後的,技術發展,掰開來看下。首先,在 1987年,也就是在 Windows 2 發行的時候,Dynamic Data Exchange (DDE) 技術產生了,作為一種進程間通信手段(Inter-process communication)。在這個技術之前,只支持系統和客戶端應用程式之間的通信,這個通信,則是通過 Windows Messaging Layer 實現的。而 DDE 技術,則再此基礎之上,實現了客戶端應用程式之間的通信,這也就成為了進程間通信技術的開端。但這時的通信,還只是停留在 Text conversations 和 Windows messages 的層面上。之後 Antony Williams 分別於 1988年 和 1990年 發表了兩篇微軟內部文章,分別是 【Object Architecture: Dealing With the Unknown】和【On Inheritance: What It Means and How To Use It】。正是兩篇文章奠定了日後 COM 產生的理論基礎。之後,1991年,微軟在 DDE 的基礎上,開發出了第一個 object-based framework(基於對象的框架),叫做 Object Linking and Embedding (OLE),即對象的連接與嵌入。這個技術是同 Word 軟體的發行一同發佈的,專註於實現 Compound document(複合型文件),就是將 Excel 文件,嵌入到 Word 中。同在 1991年,微軟發佈了 Visual Basic 1.0 編程語言,並以 dynamic-link library (DLL) 的形式,附帶了 Visual Basic Extensions (VBX) 插件。這個插件讓使用者,可以通過 Properties and Methods 來操控 objects (對象)。1992年,隨著 Windows 3.1 的發佈,OLE2 和它自己的 Object Model,也一同發佈了。和 OLE1 不同,OLE2 是在 COM 概念的基礎上重新實施的。這時的 COM Application binary interface (ABI),即 COM 應用介面的標準也發生了改變。1994的時候,微軟宣佈,OLE2 改名為 OLE,從此 OLE 變成了,微軟組件技術(Component Technologies)的統稱。同年還發佈了 OLE Custom Controls (OCXs) ,作為 VBX 的升級版。後來,在1995年,微軟發佈了 Visual Basic 4.0,開始支持 OCXs,這時微軟也開始考如何讓 COM 組件可以實現跨語言支持。這就要求,COM 架構下,必須要提供一個一致的介面,以及提供一組可以調用介面內方法的能力。此後,才發展成了我們現今熟悉的 COM 的含義。在1996年,微軟有發現 OCXs 可以應用在瀏覽器上,所以就把部分 OLE 改名為 Internet "ActiveX",然後,逐漸的,所有的 OLE 都改名叫做 ActiveX 了。同年後期,微軟又拓展了 COM 的能力,使得組件對象,擁有了在網路上通信的的能力。這個技術被稱為 DCOM (Distributed COM)。自此便形成了今時今日的 COM 的概念。
這篇文章中涉及到了不少的歷史,之前在學習,近200年的,科技發展歷史時,把 Technology Timeline 寫在博客里,感興趣的同學可以點進去看一下。在那篇博客中,我把微軟技術發展的 Timeline,和科技發展的 Timeline 揉合在了一起,這樣能幫助我們感覺到,技術是在伴隨著科技的發展而發展。也可以看到,COM 這種技術理念的產生,是在PC漸漸普及起來,操作系統漸漸成熟,軟體需求逐漸提高之後才有的。所以很多事情的發展,往往都是自然而然的,因為有了需求,才會有相應的發展。COM 的產生,從這個角度說,也是一種必然。因為 COM 實際上,就是一種規範,就像行業規範一樣,行業太小自然不用規範,而規模大了,需求大了,自然會產生規範,所以 COM 的產生是一種必然結果。而技術的發展,既在推進著科技的發展,也受制於現有科技的邊緣。
3. 介面(Interface)周圍的概念:
個人認為,關於 COM,的一切的一切,最後都是為了這個“介面”。因為只有有了“介面”,才算是真正的實現了 Component Object 的理念(或者說,才算是實現了,把 Object 變成 Component 的想法)。因為只有有了“介面”,Component 才能被叫做組件,才能被調用。所以下麵簡單描述下,幾個常見的,圍繞著“介面”的概念:
3.1. API (Application Programming Interface)
API 中文為,應用程式編程介面;很多時候,都被直接叫做 “介面” (Interface)。“介面”是“操作系統” 或 “程式庫”,提供給應用程式的,接入點,讓應用程式能調用,系統某一方面的功能。其主要作用是,讓開發人員,可以輕鬆調用這些功能,而不需要瞭解,到底怎麼做到的,和底層代碼。但是,API 並不是代碼,他只是一個介面,或者說只是一個地址。
3.2. IDL(Interface Defining Language)
IDL 中文為,介面描述語言。它是一種 Specification language(規範語言)。是用來描述,軟體 Component 的 API 的 “規範語言”。與之相比,Programming Language(編程語言)是可以直接運行,用於系統實現的,形式語言。而,“規範語言” 是通常不能直接運行的,而是用於系統分析和設計的,描述語言。然後,這些一段一段的用來描述 Interface 的文字,就被儲存在了 IDL 文件中(文件尾碼就是 “.idl”)。每個這樣的文件裡面都有,一個 header 和一個 body。格式很整齊。
3.3. OLE (Object Linking and Embedding)
OLE 中文為,對象鏈接與嵌入。是能讓應用程式創建,包含不同來源的文檔,的複合文檔技術。OLE 是建立在 COM 理念的基礎之上的。COM 是理論框架,而 OLE 是根據這個框架,實施出來的一套技術。正如之前在,PC Mag 雜質上看到的一個副標題,就很好的詮釋了這種關係型:"COM-the master plan that lets Windows apps interact through OLE.[2]" 一個比較常見的例子就是,把 Excel 表格,整個插入到 Word 文檔中。而這個 Excel Object,就是通過這個 OLE 技術,連接並嵌入(Linking and Embedding)到 Word 中的。但,正如上文所說,後來 OLE 就變成了,微軟組件技術(Component Technologies)的統稱。而,像這樣的一個典型的 OLE 功能(或 OLE 特性),其背後是有一大堆,Interface(介面)作為支持,才得以實現的。
3.4. GUID (Globally Unique Identifier)
GUID 中文為,全局唯一標識符,也被稱為,UUID (Universally Unique Identifier),即,通用唯一識別碼。是一個用於標識信息的,128-bit的,標識符;由一組,32位數的,16進位的,數字組成。數字串,的格式為 8-4-4-4-12 的32個字元;大概長成這樣:550e8400-e29b-41d4-a716-446655440000。GUID 具有全球唯一性,出現重覆的概率幾乎為零。所以才叫做,全局唯一標識符。
3.5. CLSID (Class IDentifier)
CLSID 中文為,類標識符。是一個 GUID,但是,是專門用於,標識 COM class object 的。每一個 OLE Class,都會有一個與之對應的,全球獨一的 CLSID。
3.6. ProgID (PROGrammatic IDentifier)
ProgID 可以翻譯為,程式標識符,或者,編程標識符。通常情況下,每個 CLSID,都會有對應的 ProgID。例如,ProgID 是 Msxml2.DOMDocument 的字元串;而 CLSID 則長成這個樣子 {F9043C85-F6F2-101A-A3C9-08002B2F49FB}。所以 ProgID 的存在,是為了編程的時候,方便調用。
3.7. Registry (Windows)
Registry 中文為,註冊表。它是一個 hierarchical database (分層的資料庫)。用於儲存 Windows 系統,或者應用程式的 low-level settings。但並不是,所有的應用程式都選擇把設置,存在註冊表裡。Registry 是從 Windows 3.0,推出 OLE 的時候,開始有的。在那之前,應用程式都是把自己的設置信息存在一個尾碼為“.ini”的文本文件中的。除了設置之外,所有的 OLE Objects 的 CLSID, 也都儲存在這個 Registry 中。感興趣的同學可以去 Regedit.exe 中,這個位置(HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID)看下,所有的 CLSID 都長成什麼樣。而在每個 CLSID 的“文件夾”中,又都會儲存著,這個 Class 的 ProgID 的名字。
4. 調用組件的流程
閱讀到這裡的同學,應該已經對基本的概念有一些瞭解。那麼我們就再來看下,在實際運行中,Component(組件)到底是怎麼被調用的。就用在 Word 裡面插入一張 Bitmap Image 來舉例;當我們在 Word 程式里,點擊插入 Object 的時候,Word 會彈出,插入對象的對話框。然後,程式會立刻開始掃描,系統的 Registry,看哪些 Object 是能夠插入的,然後,把它們都列在你面前,供你選擇。當你選中 Bitmap Image 這個對象後,程式會,立刻調出他的 ProgID 名字,然後,把這個名字,遞給一個叫做 CoCreateInstance 的 OLE Function。再然後,在這個 Function 的內部,就開始了一系列流程。
首先 OLE 會用立刻這個 ProgID(或者 CLSID)去找出與它對應的 Regstry 條目。然後,通過註冊表裡登記的信息,便可以輕易的找到,提供這個“服務”的,應用程式,或者 Component(.exe 或者 .dll)到底住在哪裡。一旦找到了,便可以立刻調用(Invoke)這個 Component,然後創建出,一個 Bitmap 對象的 Instance(這個Instance,似乎也叫做 Interface Pointer)。
這和我們寫代碼的時候是一樣的,在我們要使用某個模塊的功能之前,都是先通過 PorgID 創建一個 Instance(例如,在 VBScript 中,通常是用Set XL = CreateObject("Excel.Application")
這樣的語句)。然後通過這個 Instance,和它提供的 Interface(介面),我們就可以開始調用,這個實例的各種屬性和功能了(例如 XL.Workbooks.Open("FilePath")
)。
當然,這個流程中省略了很多的細節,想要瞭解具體細節的同學,就去看我“腳註2”中的 Article 吧,這篇文章雖然是1995年的,但是寫的非常的好,非常值得閱讀,尤其是在學習 COM 的同學,這篇文章能很好的提升我們的理解。好吧,這部分就這麼多啦。
5. 篇尾結語:
研究的過程中發現,COM 相關的東西,真的是博大精深,作為一隻小白,也只能是淺嘗輒止了。感謝您花時間閱讀,小白貢獻,語失莫怪。文章中涉及到的歷史並沒有列在這裡的參考閱讀,而是列在了我另一篇叫做 Technology Timeline 的博客里,有需要的同學可以點進去看下 (^_−)☆。
P.S. 為了寫完這篇,關於 COM 的小白文章,真的是有一種,跋山涉水,翻山越嶺的感覺啊 (T^T),希望能對同學們有所幫助....
相關書籍:
- 《COM技術內幕》,Dale Rogerson
- 《Learning DCOM》,Thuan L. Thai
- 《Inside OLE》,Kraig Brockschmidt
- 《COM本質論》,Don Box
- 《MFC Windows程式設計》,Jeff Prosise
- 《Windows XP Under the Hood》,Brian Knittel
參考閱讀:
- 組件對象模型_百度百科
- Component Object Model - Wikipedia
- COM Technical Overview - Win32 apps | Microsoft Docs
- The Component Object Model - Win32 apps | Microsoft Docs
- COM - Marvin's Blog
- PC Mag - Google Books