程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> COM基礎

COM基礎

編輯:關於JAVA

COM是一種二進制規范,致力於實施可相互操作的對象。例如,COM認為一個對象的二進制布局必須能夠調用另一個COM對象裡的服務。由於是對二進制布局的一種描述,所以只要某種語言能生成這樣的一種布局,就可通過它實現COM對象。通常,程序員不必關注象這樣的一些低級細節,因為編譯器可自動生成正確的布局。例如,假設您的程序是用C++寫的,那麼大多數編譯器都能生成符合COM規范的一張虛擬函數表格。對那些不生成可執行代碼的語言,比如VB和Java,在運行期則會自動掛接到COM。
COM庫也提供了幾個基本的函數,比如用於創建對象或查找系統中一個已注冊COM類的函數。
一個組件對象模型的基本目標包括:
■讓對象調用其他對象裡的服務
■允許新類型對象(或更新對象)無縫插入環境
第一點正是面向對象程序設計要解決的問題:我們有一個客戶對象,它能向一個服務器對象發出請求。在這種情況下,“客戶”和“服務器”這兩個術語是在常規意義上使用的,並非指一些特定的硬件配置。對於任何面向對象的語言,第一個目標都是很容易達到的——只要您的代碼是一個完整的代碼塊,同時實現了服務器對象代碼以及客戶對象代碼。若改變了客戶和服務器對象相互間的溝通形式,只需簡單地重新編譯和鏈接一遍即可。重新啟動應用程序時,它就會自動采用組件的最新版本。
但假若應用程序由一些未在自己控制之下的組件對象構成,情況就會變得迥然有異——我們不能控制它們的源碼,而且它們的更新可能完全獨立於我們的應用程序進行。例如,當我們在自己的程序裡使用由其他廠商開發的ActiveX控件時,就會面臨這一情況。控件會安裝到我們的系統裡,我們的程序能夠(在運行期)定位服務器代碼,激活對象,同它建立鏈接,然後使用它。以後,我們可安裝控件的新版本,我們的應用程序應該仍然能夠運行;即使在最糟的情況下,它也應禮貌地報告一條出錯消息,比如“控件未找到”等等;一般不會莫名其妙地掛起或死機。
在這些情況下,我們的組件是在獨立的可執行代碼文件裡實現的:DLL或EXE。若服務器對象在一個獨立的可執行代碼文件裡實現,就需要由操作系統提供的一個標准方法,從而激活這些對象。當然,我們並不想在自己的代碼裡使用DLL或EXE的物理名稱及位置,因為這些參數可能經常發生變化。此時,我們想使用的是由操作系統維護的一些標識符。另外,我們的應用程序需要對服務器展示出來的服務進行的一個描述。下面這兩個小節將分別討論這兩個問題。

1. GUID和注冊表
COM采用結構化的整數值(長度為128位)唯一性地標識系統中注冊的COM項目。這些數字的正式名稱叫作GUID(Globally Unique IDentifier,全局唯一標識符),可由特殊的工具生成。此外,這些數字可以保證在“任何空間和時間”裡獨一無二,沒有重復。在空間,是由於數字生成器會讀取網卡的ID號碼;在時間,是由於同時會用到系統的日期和時間。可用GUID標識COM類(此時叫作CLSID)或者COM接口(IID)。盡管名字不同,但基本概念與二進制結構都是相同的。GUID亦可在其他環境中使用,這裡不再贅述。
GUID以及相關的信息都保存在Windows注冊表中,或者說保存在“注冊數據庫”(Registration Database)中。這是一種分級式的數據庫,內建於操作系統中,容納了與系統軟硬件配置有關的大量信息。對於COM,注冊表會跟蹤系統內安裝的組件,比如它們的CLSID、實現它們的可執行文件的名字及位置以及其他大量細節。其中一個比較重要的細節是組件的ProgID;ProgID在概念上類似於GUID,因為它們都標識著一個COM組件。區別在於GUID是一個二進制的、通過算法生成的值。而ProgID則是由程序員定義的字串值。ProgID是隨同一個CLSID分配的。
我們說一個COM組件已在系統內注冊,最起碼的一個條件就是它的CLSID和它的執行文件已存在於注冊表中(ProgID通常也已就位)。在後面的例子裡,我們主要任務就是注冊與使用COM組件。
注冊表的一項重要特點就是它作為客戶和服務器對象之間的一個去耦層使用。利用注冊表內保存的一些信息,客戶會激活服務器;其中一項信息是服務器執行模塊的物理位置。若這個位置發生了變動,注冊表內的信息就會相應地更新。但這個更新過程對於客戶來說是“透明”或者看不見的。後者只需直接使用ProgID或CLSID即可。換句話說,注冊表使服務器代碼的位置透明成為了可能。隨著DCOM(分布式COM)的引入,在本地機器上運行的一個服務器甚至可移到網絡中的一台遠程機器,整個過程甚至不會引起客戶對它的絲毫注意(大多數情況下如此)。

2. 類型庫
由於COM具有動態鏈接的能力,同時由於客戶和服務器代碼可以分開獨立發展,所以客戶隨時都要動態偵測由服務器展示出來的服務。這些服務是用“類型庫”(Type Library)中一種二進制的、與語言無關的形式描述的(就象接口和方法簽名)。它既可以是一個獨立的文件(通常采用.TLB擴展名),也可以是鏈接到執行程序內部的一種Win32資源。運行期間,客戶會利用類型庫的信息調用服務器中的函數。
我們可以寫一個Microsoft Interface Definition Language(微軟接口定義語言,MIDL)源文件,用MIDL編譯器編譯它,從而生成一個.TLB文件。MIDL語言的作用是對COM類、接口以及方法進行描述。它在名稱、語法以及用途上都類似OMB/CORBA IDL。然而,Java程序員不必使用MIDL。後面還會講到另一種不同的Microsoft工具,它能讀入Java類文件,並能生成一個類型庫。

3. COM:HRESULT中的函數返回代碼
由服務器展示出來的COM函數會返回一個值,采用預先定義好的HRESULT類型。HRESULT代表一個包含了三個字段的整數。這樣便可使用多個失敗和成功代碼,同時還可以使用其他信息。由於COM函數返回的是一個HRESULT,所以不能用返回值從函數調用裡取回原始數據。若必須返回數據,可傳遞指向一個內存區域的指針,函數將在那個區域裡填充數據。我們把這稱為“外部參數”。作為Java/COM程序員,我們不必過於關注這個問題,因為虛擬機會幫助我們自動照管一切。這個問題將在後續的小節裡講述。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved