公用語言執行平台 (CLR) 會透過稱為運行階段可呼叫包裝器 (RCW) 的代理程式公開 COM 物件。 雖然 RCW 對 .NET 用戶端來說似乎是一個普通的物件,但其主要功能是封送處理 .NET 用戶端與 COM 物件之間的呼叫。
運行時間會為每個 COM 物件建立一個 RCW,而不論該物件上存在的參考數目為何。 執行階段會針對每個物件,在每個程序中維護單一的 RCW。 如果您在一個應用程式域或 Apartment 中建立 RCW,然後將參考傳遞至另一個應用程式域或 Apartment,則會使用第一個物件的 Proxy。 請注意,此 Proxy 是新的 Managed 物件,與初始 RCW 不同;這表示兩個 Managed 物件不相等,但確實代表相同的 COM 物件。 如下圖所示,任何數目的受管理的用戶端都可以保存公開 INew 介面和 INewer 介面之 COM 物件的參考。
下圖顯示透過執行時間可呼叫包裝函式存取 COM 物件的程式:
使用從類型函式庫衍生的中繼資料,執行階段會建立所呼叫的 COM 物件以及該物件的包裝函式。 每個 RCW 都會在它包裝的 COM 物件上維護介面指標的快取,並在不再需要 RCW 時,在 COM 物件上釋放其參考。 運行時間會在 RCW 上執行垃圾收集。
除了其他活動之外,RCW 會代表包裝的物件,封送處理 Managed 和 Unmanaged 程式代碼之間的數據。 具體來說,當用戶端和伺服器之間傳遞的數據表示法有差異時,RCW 會為方法參數和方法傳回值提供封送處理。
標準包裝函式會強制執行內建封送處理規則。 例如,當 .NET 用戶端將類型作為引數的一部分傳遞到非受控制的物件時,包裝函式會將 string 類型轉換為 string 類型。 如果 COM 物件傳回 BSTR 至其 Managed 呼叫端,呼叫端會收到 string。 用戶端和伺服器都會傳送和接收熟悉的數據。 其他類型不需要轉換。 例如,標準包裝函式一律會在Managed和Unmanaged程式碼之間傳遞4位元組整數,而不需要轉換類型。
封送處理選取的介面
執行階段可呼叫包裝器(RCW)的主要目標是隱藏受控和非受控程式設計模型之間的差異。 若要建立無縫轉換,RCW 會取用選取的 COM 介面,而不需將其公開至 .NET 用戶端,如下圖所示。
下圖顯示 COM 介面和執行階段可呼叫封裝器。
建立為早期綁定物件時,RCW 是特定類型。 它會實作 COM 物件所實作的介面,並從物件的介面公開方法、屬性和事件。 在圖例中,RCW 會公開 INew 介面,但會取用 IUnknown 和 IDispatch 介面。 此外,RCW 會將 INew 介面的所有成員公開給 .NET 用戶端。
RCW 會使用下表所列的介面,這些介面是由其包裝的物件所公開。
| 介面 | 說明 |
|---|---|
| IDispatch | 要使用反射對 COM 物件進行延遲繫結。 |
| IErrorInfo | 提供錯誤的文字描述、其來源、說明檔案、說明上下文,以及定義錯誤之介面的 GUID(對 .NET 類別始終為 GUID_NULL)。 |
| IProvideClassInfo | 如果包裝的 COM 物件實作 IProvideClassInfo,RCW 會從這個介面擷取類型資訊,以提供更好的類型識別。 |
| IUnknown | 針對物件識別、型別轉換和生命週期管理: - 對象識別 運行時間會比較每個物件的 IUnknown 介面值,以區分 COM 物件。 - 類型強制 RCW 會辨識 QueryInterface 方法所執行的動態類型探索。 - 生命週期管理 使用 QueryInterface 方法,RCW 會取得並保存 Unmanaged 對象的參考,直到運行時間對包裝函式執行垃圾收集為止,該包裝函式會釋放 Unmanaged 物件。 |
RCW 會選擇性地取用下表所列的介面,這些介面會由它包裝的對象公開。
| 介面 | 說明 |
|---|---|
| IConnectionPoint 和 IConnectionPointContainer | RCW 會將公開連接點事件樣式的物件轉換成委派型事件。 |
| IDispatchEx (僅限.NET Framework) | 如果類別實作 IDispatchEx,RCW 會實作 IExpando。 IDispatchEx 介面是 IDispatch 介面的延伸模組,不同於 IDispatch,可啟用成員的列舉、新增、刪除和區分大小寫呼叫。 |
| IEnumVARIANT | 啟用支援列舉的 COM 類型,可視為集合。 |