# C# 互操作性入門系列(一):C#中互操作性介紹
**C#互操作系列文章:**
1. [**C# 互操作性入門系列(一):C#中互操作性介紹**](http://www.cnblogs.com/zhili/archive/2013/01/14/NetInterop.html)
2. [**C# 互操作性入門系列(二):使用平臺調用調用Win32 函數**](http://www.cnblogs.com/zhili/archive/2013/01/21/PInvoke.html)
3. [**C# 互操作性入門系列(三):平臺調用中的數據封送處理**](http://www.cnblogs.com/zhili/archive/2013/01/23/DataSend.html)
4. [**C# 互操作性入門系列(四):在C#中調用COM組件**](http://www.cnblogs.com/zhili/archive/2013/01/27/COMInterop.html)
**本專題概要:**
* **引言**
* **平臺調用**
* **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 中的函數來實現,此時就涉及到托管代碼與非托管代碼的交互,此時就需要使用到互操作性的技術來實現托管代碼和非托管代碼更好的交互。.NET 平臺下提供了3種互操作性的技術:
1. Platform Invoke(P/Invoke),即平臺調用,主要用于調用C庫函數和Windows API
2. C++ Introp, 主要用于Managed C++(托管C++)中調用C++類庫
3. COM Interop, 主要用于在.NET中調用COM組件和在COM中使用.NET程序集。
下面就對這3種技術分別介紹下。
**二、平臺調用**
使用平臺調用的技術可以在托管代碼中調用動態鏈接庫(Dll)中實現的非托管函數,如Win32 Dll和C/C++ 創建的dll。看到這里,有些朋友們應該會有疑問——在怎樣的場合我們可以使用平臺調用技術來調用動態鏈接庫中的非托管函數呢?
這個問題就如前面引言中說講到的一樣,當在開發過程中,.NET類庫中沒有提供相關API然而Win32 API 中提供了相關的函數實現時,此時就可以考慮使用平臺調用的技術在.NET開發的應用程序中調用Win32 API中的函數;
然而還有一個使用場景就是——由于托管代碼的效率不如非托管代碼,為了提高效率,此時也可以考慮托管代碼中調用C庫函數。
**2.1 在托管代碼中通過平臺調用來調用非托管代碼的步驟**
(1). 獲得非托管函數的信息,即dll的名稱,需要調用的非托管函數名等信息
(2). 在托管代碼中對非托管函數進行聲明,并且附加平臺調用所需要屬性
(3). 在托管代碼中直接調用第二步中聲明的托管函數
**2.2 平臺調用的調用過程**
(1) 查找包含該函數的DLL,當需要調用某個函數時,當然第一步就需要知道包含該函數的DLL的位置,所以平臺調用的第一步也就是查找DLL,**其實在托管代碼中調用非托管代碼的調用過程可以想象成叫某個人做事情,首先我們要找到那個人在哪里(即查找函數的DLL過程),找到那個人之后需要把要做的事情告訴他(相當于加載DLL到內存中和傳入參數),最后讓他去完成需要完成的事情(相當于讓非托管函數去執行任務)。**
(2) 將找到的DLL加載到內存中。
(3) 查找函數在內存中的地址并把其參數推入堆棧,來封送所需的數據。CLR只會在第一次調用函數時,才會去查找和加載DLL,并查找函數在內存中的地址。當函數被調用過一次之后,CLR會將函數的地址緩存起來,CLR這種機制可以提高平臺調用的效率。在應用程序域被卸載之前,找到的DLL都一直存在于內存中。
(4) 執行非托管函數。
平臺調用的過程可以通過下圖更好地理解:

**三、C++ Interop**
第二部分主要向大家介紹了第一種互操作性技術,然后我們也可以使用C++ Interop技術來實現與非托管代碼進行交互。然而C++ Interop 方式有一個與平臺調用不一樣的地方,就是C++ Interop 允許托管代碼和非托管代碼存在于一個程序集中,甚至同一個文件中。C++ Interop 是在源代碼上直接鏈接和編譯非托管代碼來實現與非托管代碼進行互操作的,而平臺調用是加載編譯后生成的非托管DLL并查找函數的入口地址來實現與非托管函數進行互操作的。**C++ Interop使用托管C++來包裝非托管C++代碼,然后編譯生成程序集,然后再托管代碼中引用該程序集,從而來實現與非托管代碼的互操作**。 關于具體的使用和與平臺調用的比較,這里就不多介紹,我將會在后面的專題中具體介紹。
**四、COM Interop**
COM(Component Object Model,組件對象模型)是微軟之前推薦的一個開發技術,由于微軟過去十多年里面開發了大量的COM組件,然而不可能在使用.NET技術重寫這些COM組件實現的功能,所以為了解決在.NET中的托管代碼能夠調用COM組件的問題,.NET 平臺下提供了COM Interop,即COM互操作技術,COM Interop不僅支持在托管代碼中使用COM組件,而且還支持想CMO組件功能托管對象。下面就這兩種支持分別做一個介紹。
**4.1 在.NET中使用COM組件**
在.NET中使用COM對象,主要有3種方法:
1. 1. 1. 使用TlbImp工具為COM組件創建一個互操作程序集來綁定早期的COM對象,這樣就可以在程序中添加互操作程序集來調用COM對象
2. 通過反射來后期綁定COM對象
3. 通過P/Invoke創建COM對象或使用C++ Interop為COM對象編寫包裝類
但是我們經常使用的都是方法一,下面介紹下使用方法一在.NET 中使用COM對象的步驟:
1. 找到要使用的COM 組件并注冊它。使用 regsvr32.exe 注冊或注銷 COM DLL。
2. 在項目中添加對 COM 組件或類型庫的引用。
**Tlbimp.exe (Type Library Importer), which takes a type library as input, to output a .NET Framework interop assembly." data-guid="e48b737e46c03f731589e3d6eae713c7">添加引用時,Visual Studio 會用到Tlbimp.exe(類型庫導入程序),Tlbimp.exe程序將生成一個 .NET Framework 互操作程序集。****該程序集又稱為運行時可調用包裝 (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# 基礎知識系列 專題一:深入解析委托——C#中為什么要引入委托
- C# 基礎知識系列 專題二:委托的本質論
- C# 基礎知識系列 專題三:如何用委托包裝多個方法——委托鏈
- C# 基礎知識系列 專題四:事件揭秘
- C# 基礎知識系列 專題五:當點擊按鈕時觸發Click事件背后發生的事情
- C# 基礎知識系列 專題六:泛型基礎篇——為什么引入泛型
- C# 基礎知識系列 專題七: 泛型深入理解(一)
- C# 基礎知識系列 專題八: 深入理解泛型(二)
- C# 基礎知識系列 專題九: 深入理解泛型可變性
- C#基礎知識系列 專題十:全面解析可空類型
- C# 基礎知識系列 專題十一:匿名方法解析
- C#基礎知識系列 專題十二:迭代器
- C#基礎知識 專題十三:全面解析對象集合初始化器、匿名類型和隱式類型
- C# 基礎知識系列 專題十四:深入理解Lambda表達式
- C# 基礎知識系列 專題十五:全面解析擴展方法
- C# 基礎知識系列 專題十六:Linq介紹
- C#基礎知識系列 專題十七:深入理解動態類型
- 你必須知道的異步編程 C# 5.0 新特性——Async和Await使異步編程更簡單
- 全面解析C#中參數傳遞
- C#基礎知識系列 全面解析C#中靜態與非靜態
- C# 基礎知識系列 C#中易混淆的知識點
- C#進階系列
- C#進階系列 專題一:深入解析深拷貝和淺拷貝
- C#進階系列 專題二:你知道Dictionary查找速度為什么快嗎?
- C# 開發技巧系列
- C# 開發技巧系列 使用C#操作Word和Excel程序
- C# 開發技巧系列 使用C#操作幻燈片
- C# 開發技巧系列 如何動態設置屏幕分辨率
- C# 開發技巧系列 C#如何實現圖片查看器
- C# 開發技巧 如何防止程序多次運行
- C# 開發技巧 實現屬于自己的截圖工具
- C# 開發技巧 如何使不符合要求的元素等于離它最近的一個元素
- C# 線程處理系列
- C# 線程處理系列 專題一:線程基礎
- C# 線程處理系列 專題二:線程池中的工作者線程
- C# 線程處理系列 專題三:線程池中的I/O線程
- C# 線程處理系列 專題四:線程同步
- C# 線程處理系列 專題五:線程同步——事件構造
- C# 線程處理系列 專題六:線程同步——信號量和互斥體
- C# 多線程處理系列專題七——對多線程的補充
- C#網絡編程系列
- C# 網絡編程系列 專題一:網絡協議簡介
- C# 網絡編程系列 專題二:HTTP協議詳解
- C# 網絡編程系列 專題三:自定義Web服務器
- C# 網絡編程系列 專題四:自定義Web瀏覽器
- C# 網絡編程系列 專題五:TCP編程
- C# 網絡編程系列 專題六:UDP編程
- C# 網絡編程系列 專題七:UDP編程補充——UDP廣播程序的實現
- C# 網絡編程系列 專題八:P2P編程
- C# 網絡編程系列 專題九:實現類似QQ的即時通信程序
- C# 網絡編程系列 專題十:實現簡單的郵件收發器
- C# 網絡編程系列 專題十一:實現一個基于FTP協議的程序——文件上傳下載器
- C# 網絡編程系列 專題十二:實現一個簡單的FTP服務器
- C# 互操作性入門系列
- C# 互操作性入門系列(一):C#中互操作性介紹
- C# 互操作性入門系列(二):使用平臺調用調用Win32 函數
- C# 互操作性入門系列(三):平臺調用中的數據封送處理
- C# 互操作性入門系列(四):在C# 中調用COM組件
- CLR
- 談談: String 和StringBuilder區別和選擇
- 談談:程序集加載和反射
- 利用反射獲得委托和事件以及創建委托實例和添加事件處理程序
- 談談:.Net中的序列化和反序列化
- C#設計模式
- UML類圖符號 各種關系說明以及舉例
- C#設計模式(1)——單例模式
- C#設計模式(2)——簡單工廠模式
- C#設計模式(3)——工廠方法模式
- C#設計模式(4)——抽象工廠模式
- C#設計模式(5)——建造者模式(Builder Pattern)
- C#設計模式(6)——原型模式(Prototype Pattern)
- C#設計模式(7)——適配器模式(Adapter Pattern)
- C#設計模式(8)——橋接模式(Bridge Pattern)
- C#設計模式(9)——裝飾者模式(Decorator Pattern)
- C#設計模式(10)——組合模式(Composite Pattern)
- C#設計模式(11)——外觀模式(Facade Pattern)
- C#設計模式(12)——享元模式(Flyweight Pattern)
- C#設計模式(13)——代理模式(Proxy Pattern)
- C#設計模式(14)——模板方法模式(Template Method)
- C#設計模式(15)——命令模式(Command Pattern)
- C#設計模式(16)——迭代器模式(Iterator Pattern)
- C#設計模式(17)——觀察者模式(Observer Pattern)
- C#設計模式(18)——中介者模式(Mediator Pattern)
- C#設計模式(19)——狀態者模式(State Pattern)
- C#設計模式(20)——策略者模式(Stragety Pattern)
- C#設計模式(21)——責任鏈模式
- C#設計模式(22)——訪問者模式(Vistor Pattern)
- C#設計模式(23)——備忘錄模式(Memento Pattern)
- C#設計模式總結
- WPF快速入門系列
- WPF快速入門系列(1)——WPF布局概覽
- WPF快速入門系列(2)——深入解析依賴屬性
- WPF快速入門系列(3)——深入解析WPF事件機制
- WPF快速入門系列(4)——深入解析WPF綁定
- WPF快速入門系列(5)——深入解析WPF命令
- WPF快速入門系列(6)——WPF資源和樣式
- WPF快速入門系列(7)——深入解析WPF模板
- WPF快速入門系列(8)——MVVM快速入門
- WPF快速入門系列(9)——WPF任務管理工具實現
- ASP.NET 開發
- ASP.NET 開發必備知識點(1):如何讓Asp.net網站運行在自定義的Web服務器上
- ASP.NET 開發必備知識點(2):那些年追過的ASP.NET權限管理
- ASP.NET中實現回調
- 跟我一起學WCF
- 跟我一起學WCF(1)——MSMQ消息隊列
- 跟我一起學WCF(2)——利用.NET Remoting技術開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(4)——第一個WCF程序
- 跟我一起學WCF(5)——深入解析服務契約 上篇
- 跟我一起學WCF(6)——深入解析服務契約 下篇
- 跟我一起學WCF(7)——WCF數據契約與序列化詳解
- 跟我一起學WCF(8)——WCF中Session、實例管理詳解
- 跟我一起學WCF(9)——WCF回調操作的實現
- 跟我一起學WCF(10)——WCF中事務處理
- 跟我一起學WCF(11)——WCF中隊列服務詳解
- 跟我一起學WCF(12)——WCF中Rest服務入門
- 跟我一起學WCF(13)——WCF系列總結
- .NET領域驅動設計實戰系列
- .NET領域驅動設計實戰系列 專題一:前期準備之EF CodeFirst
- .NET領域驅動設計實戰系列 專題二:結合領域驅動設計的面向服務架構來搭建網上書店
- .NET領域驅動設計實戰系列 專題三:前期準備之規約模式(Specification Pattern)
- .NET領域驅動設計實戰系列 專題四:前期準備之工作單元模式(Unit Of Work)
- .NET領域驅動設計實戰系列 專題五:網上書店規約模式、工作單元模式的引入以及購物車的實現
- .NET領域驅動設計實戰系列 專題六:DDD實踐案例:網上書店訂單功能的實現
- .NET領域驅動設計實戰系列 專題七:DDD實踐案例:引入事件驅動與中間件機制來實現后臺管理功能
- .NET領域驅動設計實戰系列 專題八:DDD案例:網上書店分布式消息隊列和分布式緩存的實現
- .NET領域驅動設計實戰系列 專題九:DDD案例:網上書店AOP和站點地圖的實現
- .NET領域驅動設計實戰系列 專題十:DDD擴展內容:全面剖析CQRS模式實現
- .NET領域驅動設計實戰系列 專題十一:.NET 領域驅動設計實戰系列總結