標籤:
傳送門
C#互操作系列文章:
- C# 互通性入門系列(一):C#中互通性介紹
- C# 互通性入門系列(二):使用平台叫用調用Win32 函數
- C# 互通性入門系列(三):平台叫用中的資料封送處理
- C# 互通性入門系列(四):在C#中調用COM組件
本專題概要:
- 引言
- 平台叫用
- C++ Interop(互操作)
- COM Interop(互操作)
一、引言
這個系列是在C#基礎知識中遺留下來的一個系列的,因為在C# 4.0中的一個新特性就是對COM互操作改進,然而COM互通性卻是.NET平台下其中一種互操作技術,為了協助大家更好的瞭解.NET平台下的互操作技術,所以才有了這個系列。然而有些朋友們可能會有這樣的疑問——“為什麼我們需要掌握互操作技術的呢?” 對於這個問題的解釋就是——掌握了.NET平台下的互通性技術可以協助我們在.NET中調用非託管的dll和COM組件。.NET是建立在作業系統的之上的一個開發架構,其中.NET 類庫中的類也是對Windows API的抽象封裝,然而.NET類庫不可能對所有Windows API進行封裝,當.NET中沒有實現某個功能的類,然而該功能在Windows API被實現了,此時我們完全沒必要去自己在.NET中自訂個類,這時候就可以調用Windows API 中的函數來實現,此時就涉及到Managed 程式碼與Unmanaged 程式碼的互動,此時就需要使用到互通性的技術來實現Managed 程式碼和Unmanaged 程式碼更好的互動。.NET 平台下提供了3種互通性的技術:
- Platform Invoke(P/Invoke),即平台叫用,主要用於調用C庫函數和Windows API
- C++ Introp, 主要用於Managed C++(託管C++)中調用C++類庫
- COM Interop, 主要用於在.NET中調用COM組件和在COM中使用.NET程式集。
下面就對這3種技術分別介紹下。
二、平台叫用
使用平台叫用的技術可以在Managed 程式碼中調用動態連結程式庫(Dll)中實現的非託管函數,如Win32 Dll和C/C++ 建立的dll。看到這裡,有些朋友們應該會有疑問——在怎樣的場合我們可以使用平台叫用技術來調用動態連結程式庫中的非託管函數呢?
這個問題就如前面引言中說講到的一樣,當在開發過程中,.NET類庫中沒有提供相關API然而Win32 API 中提供了相關的函數實現時,此時就可以考慮使用平台叫用的技術在.NET開發的應用程式中調用Win32 API中的函數;
然而還有一個使用情境就是——由於Managed 程式碼的效率不如Unmanaged 程式碼,為了提高效率,此時也可以考慮Managed 程式碼中調用C庫函數。
2.1 在Managed 程式碼中通過平台叫用來調用Unmanaged 程式碼的步驟
(1). 獲得非託管函數的資訊,即dll的名稱,需要調用的非託管函數名等資訊
(2). 在Managed 程式碼中對非託管函數進行聲明,並且附加平台叫用所需要屬性
(3). 在Managed 程式碼中直接調用第二步中聲明的託管函數
2.2 平台叫用的調用過程
(1) 尋找包含該函數的DLL,當需要調用某個函數時,當然第一步就需要知道包含該函數的DLL的位置,所以平台叫用的第一步也就是尋找DLL,其實在Managed 程式碼中調用Unmanaged 程式碼的調用過程可以想象成叫某個人做事情,首先我們要找到那個人在哪裡(即尋找函數的DLL過程),找到那個人之後需要把要做的事情告訴他(相當於載入DLL到記憶體中和傳入參數),最後讓他去完成需要完成的事情(相當於讓非託管函數去執行任務)。
(2) 將找到的DLL載入到記憶體中。
(3) 尋找函數在記憶體中的地址並把其參數推入堆棧,來封送所需的資料。CLR只會在第一次調用函數時,才會去尋找和載入DLL,並尋找函數在記憶體中的地址。當函數被調用過一次之後,CLR會將函數的地址緩衝起來,CLR這種機制可以提高平台叫用的效率。在應用程式定義域被卸載之前,找到的DLL都一直存在於記憶體中。
(4) 執行非託管函數。
平台叫用的過程可以通過更好地理解:
三、C++ Interop
第二部分主要向大家介紹了第一種互通性技術,然後我們也可以使用C++ Interop技術來實現與Unmanaged 程式碼進行互動。然而C++ Interop 方式有一個與平台叫用不一樣的地方,就是C++ Interop 允許Managed 程式碼和Unmanaged 程式碼存在於一個程式集中,甚至同一個檔案中。C++ Interop 是在原始碼上直接連結和編譯Unmanaged 程式碼來實現與Unmanaged 程式碼進行互操作的,而平台叫用是載入編譯後產生的非託管DLL並尋找函數的入口地址來實現與非託管函數進行互操作的。C++ Interop使用託管C++來封裝非託管C++代碼,然後編譯產生程式集,然後再Managed 程式碼中引用該程式集,從而來實現與Unmanaged 程式碼的互操作。 關於具體的使用和與平台叫用的比較,這裡就不多介紹,我將會在後面的專題中具體介紹。
四、COM Interop
COM(Component Object Model,元件物件模型)是微軟之前推薦的一個開發技術,由於微軟過去十多年裡面開發了大量的COM組件,然而不可能在使用.NET技術重寫這些COM組件實現的功能,所以為瞭解決在.NET中的Managed 程式碼能夠調用COM組件的問題,.NET 平台下提供了COM Interop,即COM互操作技術,COM Interop不僅支援在Managed 程式碼中使用COM組件,而且還支援想CMO組件功能託管對象。下面就這兩種支援分別做一個介紹。
4.1 在.NET中使用COM組件
在.NET中使用COM對象,主要有3種方法:
-
-
- 使用TlbImp工具為COM組件建立一個Interop 組件來綁定早期的COM對象,這樣就可以在程式中添加Interop 組件來調用COM對象
- 通過反射來後期綁定COM對象
- 通過P/Invoke建立COM對象或使用C++ Interop為COM對象編寫封裝類
但是我們經常使用的都是方法一,下面介紹下使用方法一在.NET 中使用COM對象的步驟:
- 找到要使用的COM 組件並註冊它。使用 regsvr32.exe 註冊或登出 COM DLL。
- 在項目中添加對 COM 組件或類型庫的引用。
添加引用時,Visual Studio 會用到Tlbimp.exe(類型庫匯入程式),Tlbimp.exe程式將產生一個 .NET Framework Interop 組件。該程式集又稱為運行時可調用封裝 (RCW),其中包含了封裝COM組件中的類和介面。Visual Studio 將產生組件的引用添加至項目。
3. 建立RCW中類的執行個體,這樣就可以使用託管對象一樣來使用COM對象。
下面通過一個圖更好地說明在.NET中使用COM組件的過程:
4.2 在COM中使用.NET程式集
.NET 通用語言執行平台通過COM可調用封裝(COM Callable Wrapper,即CCW)來完成與COM類型庫的互動。CCW可以使COM用戶端認為是在與普通的COM類型互動,同時使.NET組件認為它正在與託管應用程式互動。在這裡CCW是非託管COM用戶端與託管對象之間的一個代理。 CCW既可以維護託管對象的生命週期,也負責資料類型在COM和.NET之間的相互轉換。實現在COM使用.NET 類型的基本步驟如:
1. 在C#項目中添加互操作特性
可以修改C#項目屬性使程式集對COM可見。右鍵解決方案選擇屬性,在“應用程式標籤”中選擇“程式集資訊”按鈕,在彈出的對話方塊中選擇 “使程式集COM可見” 選項,如所示:
2. 產生COM類型庫並對它進行註冊以供COM用戶端使用
在“產生”標籤中,選中 “為COM互操作註冊”選項,如:
勾選“為COM互操作註冊”選項後,Visual Studio會調用類型庫匯出工具(Tlbexp.exe)為.NET程式集產生COM類型庫再使用程式集註冊工具(Regasm.exe)來完成對.NET程式集和產生的COM類型庫進行註冊,這樣COM用戶端可以使用CCW服務來對.NET對象進行調用了。
五、總結
介紹到這裡,本專題的內容就結束,本專題主要對.NET 提供的互操作的技術做了一個總的概括,在後面的專題中將會對具體的技術進行詳細的介紹和給出一些簡單的使用例子。
[轉]C# 互通性入門系列(一):C#中互通性介紹