Com Interop 的簡單介紹

  • 6131
  • 0

本文簡單介紹COM以及.Net之間的差異性

 

 

 


我不得不說,中文版的「使用Microsoft.NET 做COM程式設計」一書真的翻譯的很xx,看都看不懂,因此,我特別買了英文原文書回來,看過一遍後,覺得還比中文版翻譯書更容易理解。因此我將我理解的語意,按照原文的排版方式,重新整理了一遍,方便我日後閱讀,如果你也是對Com Interop有興趣,建議你購買原文書回來參照,我想這樣會讓你在學習Com Interop的過程中更容易上手。

 

 ==========================================================================================

COM.NET就好像二個不同的種族,彼此之間並不相容。而微軟提供一種叫做Com Interop的技術,來做到Com.NET之間的互通性。

 

換句話說,透過Com Interop,我們可以在.NET的應用程式中使用Com元件,同樣的也可以在Com的元件中,使用由.NET程式開發的組件。

 

當然,要做到上述能力,並沒有想像中那麼簡單,首先,我們必須先了解什麼叫做RCWCCW這二個名詞。

 

RCW全文叫做Runtime Callable Wrapper,你可以把它視為「COM元件喬裝的.NET 類別」,而相對的,CCW(Com Callable Wrapper)就是「.NET組件喬裝的COM介面」了。

 

上面我們已經簡單介紹了Com Interop需求了,接下來,我們先來分析COM.NET之間的差異性,知已知彼才能百戰百勝嘛~了解二者之間文化上的差異性,使我們更容易了解當我們在二個平台中互用時,該去注意到哪些地方,以必免不必要的種族衝突

 

存放位置的差異

COM元件與其「描述資訊」被放在二個不同的地方;COM元件可以放在任何地方,而其描述資訊則一定是被放在Windows Registry中。

.NET組件一般放在GAC中,但較為不同的是,其「描述資訊」永遠緊跟著它。

 

COM使用Windows Registry來存放描述資訊有幾個比較嚴重的問題:

1.Windows Registry維護不易,不管是透過程式,還是人為操作,都不是一件簡單的事。

2.Windows Registry如果不小心動到,可能會導致COM元件無法正常運作。

3.由於「描述資訊」與COM元件分隔二地,因此,可能更新了COM 元件,忘了同步更新描述資訊,導致描述資訊過期而無從得知。

 

再來看看.NET組件怎麼做,首先要犛清的問題是:「這個.NET組件是要自用?還是公用?」。

如果.NET組件是我們自已的程式要用到的,那麼只要跟我們的程式放在相同路徑下面就好。如果是想開放給大家使用,那麼就可以考慮放在GAC中。GAC 的路徑是C:Windwos\Assembly

 

識別系統

COM統一使用GUID來識別介面、介面方法等等,而.NET不使用 GUID來做識別,而改用「領域名稱」來識別;這二者的差別有點像一個使用IP,一個使用DomainName

.NET組件的識別系統,不僅僅只靠「領域名稱」來解決,它還可以包括組件的名稱、版本、語系等等資訊,因此,.NET組件的彈性相對來說就比COM元件來的高得許多。

 

元件的生命週期

COM元件透過「參考計數」的方式來管理元件自已的生命週期,Client程式在使用COM元件時,要記得去增加或減少計數,當然這種機制對Client程式來說,無疑多了一個麻煩事。而.NET就相對簡單許多了,Client 程式完全不管組件的存活期,組件的生死統一由GC,也就是Runtime的垃圾收集機制來做管理。

 

例外處理

COM使用HRESULT這個結構來傳送錯誤資訊給Client程式,而.NET 則使用Exception機制來傳送錯誤資訊。Exception.NET中也是一種類別,因此它可以被繼承改寫,相對於HRESULT來說,Exception顯得彈性許多。

 

型別資訊

元件要讓別人使用,一定要有自我解釋能力,要做到如此,不管是.NETCOM都必須設法公開其型別資訊。

COM的型別資訊包括COM Coclass以及一整組的介面方法。型別資訊是編譯過的二元資料檔,因此無法被人為辨識出來。

(COM型別資料檔叫做MIDL,其編譯前的檔案叫做IDL)

.NET透過Metadata來公開其型別資訊,Metadata永遠緊跟著.NET組件。因此只要你拿到某個組件,就可以很簡單透過.NET所提供的Refection機制來讀取其型別資訊。

 

能見度

COM元件是透過Interface的方式來實做的,Interface內的方法基本上都是公開的, 因此沒有能見度的問題。

.NET的開發環境中,我們是透過CCW機制將.NET組件偽裝COM元件,而預設一個COM Wrapper類別內的所有方法、屬性、欄位(Field)、事件等都時必須設為public。如果類別裏面某些方法,屬性等不想公開給Client程式碼看到,雖然不可避免的,我們還是要將其設為public,但透過C#Attribute機制,我們可以告知編譯器隱藏某一類別、或方法不給Client程式知道,程式碼如下:

[ComVisible(false)]

Public class MyClass

{

        [ComVisible(false)]

Public void foo()

{
}

}

 

資料的傳遞

COM元件有許多特別的型別,例如BSTRSAFEARRAY,因此要在.NET COM之間傳送資料並不是一件簡單的事。

.Net Interop提供了一種名叫 “.Net Interop馬歇爾機制,這個機制可以做到在不同的Process中傳送資料。這個機制也可以在拖管記憶體推疊非拖管記憶體推疊中進行資料傳遞。

 

COM Client中使用 .NET

如果一個.NET類別,打算在COM中使用,那麼就要注意這個Com類別必須是Thread-Safe,也就是這說,當這個類別實例被配置出來時,能夠支援多執行緒的存取。

 

.NET 中使用COM元件

在使用Com Interop技術時,預設.NET應用程式的記憶體配置機制是支援多執行緒執行環境的(MTA)。如果程式想改為單一執行緒記憶體配置(STA),可以在程式的進入點上宣告STAThread Attribute,如下所示

Class Class1

{

[STAThread]

Static void Main(string [] args)

{
}

}

此外,這個Attribute的宣告並不會引響一般的.NET應用程式。

 事件處理

 

COM.NET都支援事件驅動,但二者的做法有很大的差異。

COM透過connection points,而.NET使用delegate