1、1,第三十一章 COM程式的開發,COM到底是什麼東西?DCOM、COM+、dll、ActiveX與COM的關係又是什麼?微軟所推出的這麼多東西真的這麼複雜嗎?我們將在這一章讓各位讀者了解這些名詞的意義,並使用幾個COM的範例實作,讓各位讀者除了在理論上了解外,對於COM的實作也是相當的清楚。,2,大綱,31-1. COM簡介 31-2. COM程式開發 31-3. COM Object的應用 本章習題,3,31-1. COM簡介,現今在世界上我們常看到的分散式物件模型大概有OMG組織的CORBA、微軟的COM(DCOM)、SUN的Java RMI、以及OFS的OODCE等等。 在這麼多種分散
2、式物件模型中,目前最常被使用到的就是Microsoft所提出來的COM了,所以在這一章節中,我們將慢慢的從簡介到開發到應用,一一的將COM呈現在各位讀者的面前。 COM有時被稱為Common Object Model,而微軟官方則稱他為Component Object Model。 要談論COM的歷史,就必須追溯到1994年Microsoft Windows 3.1的時代上,因為在Windows 3.1的環境中出現了OLE(Object Linking and Embedding)這樣的介面,當時的OLE所提供的功能只是在不同的應用程式中提供Copy & Paste的功能,只可惜當時的電腦設備
3、不是很好,在使用OLE可以說是痛苦萬分。,4,31-1. COM簡介,隨著硬體設備的提升以及微軟的持續開發,沒有多久的時間,OLE2就出現在這個世界上了。OLE2的發展基礎就是我們這一章的重點COM。 OLE2提供了各個應用程式間的通訊介面以及通訊方法,我們可以透過OLE2很簡單的在不同的應用程式間交互使用各自的功能,例如我們可以很簡單的將一個Excel的試算表插入到Word中。 提供這些Component的開發原理就是COM,也就是COM提供了一種規範,讓每個程式設計師根據這樣的規範來開發Application或是Component,而依據COM的規範所開發出來的程式或是元件,就可以利用OL
4、E的運作方式在各個應用程式間交互使用其功能。 例如現在你想要自己寫一個瀏覽器,第一步我們就是去查詢MSDN,看看Microsoft Explorer提供了哪些COM Component可以讓我們使用,接下來我們就可以很輕易的在自己的程式中利用OLE的方式將Explorer的COM元件Link進來我們的程式中,讓我們可以再自己的程式中任意的使用Explorer所提供的所有Function。,5,31-1. COM簡介,除了COM,我們也很常聽到DCOM這個名詞。 COM本身的應用只能在單一電腦上運作,而DCOM則提供了分散式的COM元件,所以DCOM的D就是Distribution。 DCOM讓
5、我們的COM元件也可以透過網路來使用。 在1995年底和1996年的時候,微軟也順著時代的潮流進入了Internet的世界,在這時候,微軟將COM、DCOM、OLE、OCX等等的技術都統稱為ActiveX,而且在之後的命名規則上似乎都有著X的身影,例如X-BOX、DirectX等等。 目前微軟已經將他們所開發的軟體全面DCOM化,不管是一般的Application或是Server,甚至只是一些Component,都已經是DCOM的元件,所以我們可以很輕易的透過MSND去查詢這些DCOM所提供的Function,如此我們就可以將這些Function應用在我們自己要開發的應用程式上了。,6,31-
6、1. COM簡介,以上都是我們對於COM比較文字敘述上的解釋,接下來我們要告訴各位的是COM的技術,也就是從技術面來介紹COM這樣的一個東西。首先我們先來看看COM最簡單的使用架構圖。,7,31-1. COM簡介,在上面這張示意圖中很清楚的可以看出來,Application是與COM Object中的一個Interface溝通,而這個Interface的定義就是利用IDL這樣的語言定義出來的。 COM物件具有相當複雜的介面,但是這麼複雜的架構中有兩個很重要的東西用來定義這些複雜的介面,這兩個就是我們常聽到的CLSID以及GUID。 在COM的每一個類別中一定有一個獨自擁有而且唯一的Class
7、Identifier,也就是所謂的CLSID;而對於COM的Interface來說,則必須要有一個GUID來當作一個唯一識別字,以避免名字的衝突。 COM的Interface是Microsoft IDL來定義的,IDL全名是Interface Definition Language,在這邊我們要強調是Microsoft IDL,因為世界上的IDL太多的,就算一樣都是分散式架構下的技術,如CORBA,他的IDL就是由OMG所提供。,8,31-1. COM簡介,在這邊所謂的Interface就是提供讓COM Object和Client端連接的一個溝通管道,而Application和COM Obje
8、ct之間的(Client/Server)連接方式總共有三種。 In-Process Server Out-of-process Server(Local Server) Remote Server,9,31-1. COM簡介,In-Process Server,Client端和Server端都存在同一個行程(Process)中,所以也表示都在同一台電腦上執行。在這個模式下Server的執行方式是以DLL(Dynamic Link Library)的形式運作,執行時才會將該DLL載入到記憶體中,對於容錯的能力較差,也因為執行在同一個Process內,所以沒有所謂的安全機制。一般來說,這樣的方式常
9、見於單純的只是想要提供一些功能,所以採用Component的方式撰寫程式。例如撰寫一個符合COM Object規範的dll來提供某些功能。,10,31-1. COM簡介,Out-of-Process Server(Local Server),Client端和Server端都在同一台電腦上執行,和In-Process不同的是Client端和Server端是分開在不同的Process中運作的。 在這個模式下一般都是以EXE的檔案格式運作。因為Client和Server分開在不同的Process運作,所以兩者不會互相影響,穩定性較高,之間的通訊利用IPC當作通訊的環境;不過也因為分開在不同的Proc
10、ess中運作,所以之間的溝通管道比較複雜,必須在Client和Server這兩端都包上相對應的Proxy/stub,所以執行效率比In-Process的模式還要慢。,11,31-1. COM簡介,Remote Server,在Remote Server的模式下,Client端和Server端分屬於不同電腦,是分散式的架構,就是DCOM的運作模式。Client和Server使用RPC通訊,所以RPC Service一定不可以關閉。 在遠端Server上COM Object的格式可以是一個DLL檔案,也可以是一個EXE檔案,並沒有受到限制。不過若是dll檔案的話,則需要一個代理程序來處理,一般都是
11、dllhost.exe這支程式在負責這部分的工作。在Remote Server這種模式下的實作技巧上,也要將相對應的proxy/stub都包進來。,12,31-2. COM程式開發,經過上面的說明後,相信各位讀者對於COM已經有一些基本的觀念。接下來我們要做的就是利用BCB寫出我們的第一個COM Object,並且利用一個小小的範例程式使用這個COM Object。 我們將會利用範例31-1一步一步的帶領各位讀者開發一個COM Object,也會利用範例31-2實際的在Application中使用這個COM Object。,13,31-2. COM程式開發,範例31-1:COM Object程
12、式開發 範例說明 這個範例我們將實作一個可以傳入字串至COM Object中,再傳回一串利用URL Encode/Decode編碼過後的資料,我們將利用FastNet元件內的TNMURL幫我們作URL Encode和Decode的工作。 在這個範例中,將會依照Out-of-process Server這種模式運作,所以我們一開始所建議的專案會是一個一般的Application,如果現在你想要開發的是In-Process的模式,則是開一個DLL Library專案的Project。接下來我們就一步一步的告訴各位讀者該如何在BCB6中完整的開發一個COM Object。,14,31-2. COM程
13、式開發,範例31-1:COM Object程式開發 Step 1: 開新專案,並且在該專案中開啟COM Object的開發對話窗 首先我們先開啟一個最基本的Application Project,如果讀者不希望有視窗畫面,可以開啟一個Console程式的Project。 接著再次按下New的按鈕,選擇新增ActiveX這個頁次的COM Object。,15,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 2: 設定COM Object的一些相關屬性 當我們新增一個COM Object之後,會馬上跳出一個對話窗要我們輸入一些該COM Object的基本資料,我們
14、將CoClassName設定成URLCoder,這時候Implemented Interface會自動幫我們設定成IURLCoder,Threading Model我們使用原本的預設值,描述則根據事實填入一小段文字。,16,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 2: 設定COM Object的一些相關屬性 (2) CoClass Name:Client端看到的COM Object名稱,一般來說習慣在ClassName的最前面加上T,在BCB內預設會加上T這個字母。 ClassName最好不要亂填,避免到最後看到該ClassName卻不知道這個Clas
15、s的作用!在這個範例中我們將CoClass Name設定成URLCoder。 Threading Model:設定COM Object的執行緒模式。執行緒的模式總共有五種,分別是Single、Apartment(Single-threaded apartment)、Free(Multi-threaded apartment)、Both以及Neutral。 對COM Object的深入設定有興趣的讀者可以參考BCB的Help,利用COM Object當作關鍵字就可以找到相關的說明文件了,該說明文件的標題為Choosing a threading model。,17,31-2. COM程式開發,範
16、例31-1:COM Object程式開發 Step 2: 設定COM Object的一些相關屬性 (3) Implemented Interface:實作的介面,可以自己定義一個新的介面,也可以從已經註冊的介面中選取,在這邊我們是自己定義一個ITMD5Hash的Interface。 Event support(Generate Event support code):確認是否要建立各種Event的處理介面。 Oleautomation(Mark interface Oleautomation):是否要做proxy/stub的marshing,建議要勾選(預設),否則得自己處理marshing這
17、部分的程式碼,蠻麻煩的。,18,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 3: 設定該COM Object的Type Library 首先我們先將Attribute中的Name以及Help String中的Project1改成CH31_001,讓他可以符合我們的專案名稱(在這邊要取什麼名字隨便,好記就好),接下來可以轉去Text這一個Page,將會發現,BCB已經將該Object的GUID跟CLSID都Generate出來了,我們不需要像使用VC來開發一樣,需要利用ID產生器來Generate這些ID。,19,31-2. COM程式開發,範例31-1:C
18、OM Object程式開發 Step 3: 設定該COM Object的Type Library (2) 設定Type Library的Attribute之後,接下來要利用這個Type Library的編輯器建立我們COM Object Interface的Method。設定好Method後,再用該Tool Generate該COM Object的IDL檔案。 當要新增一個Method的時,必須要先知道將在哪個Interface上建立,我們就在要建立Method的那個Interface上按下滑鼠的右鍵,利用選單選擇新增一個Method。 我們在這個範例就是在整個Type Library編輯工具
19、的左半邊選擇IURLCoder這個Interface,然後在該Interface上按右鍵,選擇New選單下的Method來新增一個屬於該Interface的Method。,20,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 3: 設定該COM Object的Type Library (3) 利用上面的方法,我們在IURLCoder這個Interface上新增一個Method叫做Encode。新增這個Method後,在Type Library的右邊就會出現該Method的Input/Output設定畫面,我們可以透過這個畫面設定好我們所需要的輸入以及輸出變數。
20、 因為這個Method所需要的功能是,輸入一個字串,經過URL Encode/Decode之後輸出一個字串,所以我們在這邊使用LPSTR這個資料型態。,21,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 3: 設定該COM Object的Type Library (4) 一般在COM的實作中,我們對於String的處理都會使用BSTR這個資料型態,但是因為BSTR對應的是WideString這個Data Type,在BCB中處理還要稍微轉換一下,但是如果使用LPSTR的話,則可以直接使用AnsiString。 這兩個型態間的轉換全部由BCB幫我們搞定了,所以
21、在這邊筆者使用LPSTR這個Data Type。 在outStr部分,因為是要傳回一個LPSTR的字串,所以需要使用指標來傳遞,因此在outStr的Type設定上,需要自己設定成LPSTR *,因為在下拉式選單中並沒有指標型態的LPSTR。,22,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 3: 設定該COM Object的Type Library (5) 在這個範例內我們共新增兩個Method,分別是Encode以及Decode這兩個。 將Method新增完畢後,一定要按下上面那排按鈕的最右邊那個,否則剛剛的辛苦就白做了。 這個按鈕就是Export To
22、 IDL。主要的功能就是將我們剛剛設定的東西全部用MIDL(Microsoft Interface Definition Language)的語法表示出來。,23,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 3: 設定該COM Object的Type Library (6) 當按下Export To IDL這個按鈕後,BCB會自動將畫面帶到程式編輯器上面,並且顯示剛剛所產生的IDL檔案內容。 在這個IDL的檔案內,我們可以很清楚的看到剛剛所設定的那些Interface、Method、甚至是程式自動幫我們建立的GUID等,都已經包含在該idl的檔案內。,24
23、,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 3: 設定該COM Object的Type Library (7) 接下來就可以按下Save All的按鈕,將專案一開始就建立的檔案到剛剛才產生出來的idl檔案全部都儲存到電腦的硬碟中。 存完這些檔案後,我們將程式編輯器的Active Window換到URLCoderImpl.cpp這個檔案來。 這個檔案就是我們整個COM Object主要的程式碼,這個檔案也是由BCB自動幫我們產生出來,我們完全不需要自己動手寫這些煩人的東西,只要按下存檔之後,這個檔案內的Function Definition就全部都會幫我們
24、建立好(還沒存檔之前只有該檔案的前面部分,不會有Function的block)。,25,31-2. COM程式開發,範例31-1:COM Object程式開發 Step 4: 設計該COM Object的視窗畫面 這個步驟蠻特別的,因為一般來說,COM Object通常都會做成dll格式或是Console的程式來運作。 這邊我們為了讓各位讀者更清楚COM Object,我們將COM Object也發展成視窗介面的程式,在這邊我們在Form上面將放上一個Memo,來紀錄什麼時候COM Client送了一個String要求Encode或是Decode,設計畫面如下:,26,31-2. COM程式開
25、發,範例31-1:COM Object程式開發 Step 5: 撰寫主要程式碼 設計好畫面後,就到了撰寫程式的步驟,在這邊我們要撰寫的檔案是URLCoderImpl.cpp這個檔案。 在我們的程式碼當中,因為我們有用到TNMURL這個元件,所以必須要Include這個重要的標頭檔,這樣我們才有辦法繼續我們的撰寫過程。該範例的程式碼相當的簡單,各位讀者可以參考書上講解FastNet部分的章節就可以知道NMURL的詳細用法。 Step 6: 編譯COM Object 當我們編輯完程式碼之後,就可以按下F9或是直接按下Run的按鈕,讓BCB編譯執行該COM Object。,27,31-2. COM程
26、式開發,範例31-1:主要程式碼(URLCoderImpl.cpp ),28,31-2. COM程式開發,範例31-1:主要程式碼(URLCoderImpl.cpp ),29,31-2. COM程式開發,範例31-1:COM Object程式開發 執行結果 在COM Object的運作中,其實很少會有執行畫面的出現,但是因為我們在這個範例將COM Object寫成一個視窗化的狀態,所以也會有所謂的執行畫面,現在我們就將這個COM Object的執行畫面顯示在下面。,30,31-3. COM Object的應用,講完了COM Object的開發,免不了一定得介紹一下該怎麼在程式中使用我們開發出來
27、的COM Object,我們將在範例31-2中告訴大家該如何在一般的應用程式中使用COM Object。 在使用COM Object之前,有一個很重要的觀念那就是註冊COM Object。因為我們是在自己的電腦上開發這個COM Object,所以在編譯執行程式的時候,BCB會自動幫我們將這個COM Object註冊到系統中,但是如果我們將這個COM Object拿到別台電腦上運作時,第一個步驟就是要做註冊的動作。 利用BCB開發出來的COM Object可以使用/regserver這樣的參數向系統註冊這個COM Object;如果想要反安裝這個COM Object,可以使用/unregserv
28、er來向系統要求反安裝這個COM Object。 在我們這個例子中,要安裝CH31_001的COM Object需要在MS-DOS視窗(命令提示字元)裡輸入CH31_001 /regserver;如果要反安裝則要輸入CH31_001 /unregserver。,31,31-3. COM Object的應用,有沒有註冊某個COM Object可以在Registry中找到,32,31-3. COM Object的應用,COM的運作 COM的運作其實很簡單,就是透過CLSID去Registry中搜尋該CLSID的相關資料,這些資料就有包括該COM Object在系統那一個資料夾內,所以COM Cli
29、ent很容易的可以得知要去哪裡使用COM Object的資源。除了知道COM Object放在哪裡外,在Registry中也可以知道COM Object的版本、Type Library等重要資訊,有興趣的讀者可以自行開發一個COM Object後,自行去Registry中尋找相關的機碼值。,33,31-3. COM Object的應用,範例31-2:在Application中使用COM Object 範例說明 在範例31-2中我們將解釋該如何在程式中使用我們剛剛才發展出來的COM Object,所以在這個範例中,我們將改寫介紹TNMURL這個元件的範例程式,將這個程式改成去呼叫COM Obje
30、ct來做URL的Encode和Decode的工作。 Step 1: 建立新專案,並且完成介面設計,34,31-3. COM Object的應用,範例31-2:在Application中使用COM Object Step 2: Import Type Library 接下來要將剛剛發展的COM Object中的Type Library import到範例31-2中,如此我們才能在範例31-2中使用這個COM Object。 首先我們先選擇Project選單內的Import Type Library,接著就會跳出Import Type Library的對話視窗,我們可以在這個對話窗中找到CH31_
31、001這個Type Library,而且在選取這個Type Library之後,相關的訊息一併會出現在這個對話窗之內。接下來我們要替這個Type Library建立相關的Unit File,這時候我們要按下對話窗中間最下方的按鈕,將相關的Unit建立出來。,35,31-3. COM Object的應用,範例31-2:在Application中使用COM Object Step 2: Import Type Library (2) 在這邊各位讀者可以注意一下在這個對話窗中有一個Unit dir name的資料,這個就是指出,我們要將Unit File建立在這個目錄中,所以假設之前你已經Creat
32、e了這個Type Library的Unit,你就可以不用在Import一次,直接將這個資料夾內這個Type Library的cpp檔加入到Project中即可,不然BCB會出現一個詢問視窗要你確認是不是要覆蓋已經存在的Unit File。當我們將Type Library Import到Project中,BCB就會自動將這個Type Library的Unit File放到程式編輯器中。,36,31-3. COM Object的應用,範例31-2:在Application中使用COM Object Step 3: 在主程式中加入Type Library的header file,並撰寫主要程式碼 I
33、mport完Type Library後,接下來就是要將這個Type Library的標頭檔放到main.cpp中,接著就直接在main.cpp中將程式完成吧!詳細的程式碼將列在下方。 Step 4: 編譯以及執行程式 上面三個步驟都完成後,接下來就是編譯以及執行該範例了。直接按下F9執行吧!,37,31-3. COM Object的應用,範例31-2:主要程式碼(main.cpp),38,31-3. COM Object的應用,範例31-2:主要程式碼(main.cpp),39,31-3. COM Object的應用,範例31-2:在Application中使用COM Object 執行結果
34、當我們執行範例31-2的時候,並不需要先將COM Object執行,我們直接執行COM Client就好。 因為當我們按下Encode或是Decode的時候,COM Client會自動去系統中尋找他需要的COM Object來用,並且自動將該COM Object執行。,40,31-3. COM Object的應用,到這邊,我們已經將COM Object的基本設計以及如何使用COM Object稍微介紹過了,依照範例的執行模式是Out-of-process的模式,各位可以遵循這樣的範例繼續開發出另外兩種模式的COM Object出來使用。 在下一章,我們將提出另一種應用COM的方式,也就是下一章使用COM Object的方法跟我們範例31-2的方法有些出入,雖然兩種都是使用COM Object,但是呼叫方法並不一樣!,41,本章習題,修改NotePad範例,將部份Function改用COM的格式完成。 比較COM、DCOM、以及COM+之間的異同。 ActiveX、OLE等Object與COM的關係為何。,