天天看點

成功實作C++調用C#寫的庫(CLR),我的個人心得與總結

一、先說說我的個人心得

我建立了C++ win32動态庫工程,準備調用C#類庫。

//使用CLR的方式,成功實作C++調用C#類庫,注意事項:

//1.

//不要嘗試在DllMain或映像初始化函數内運作托管代碼,這樣做會導緻應用程式挂起。

//解決辦法:

//注釋掉dllmain.cpp檔案裡的主函數BOOL APIENTRY DllMain

//2.

//本人在實踐工程中遇到兩個難點:

//(1)CLR/CLI連結器失敗,錯誤LNK2022 - 自定義屬性不一緻

//(2)軟體釋出,Windows7 64位純淨版,軟體啟動時,出現KERNELBASE.dll錯誤

//問題原因及解決方法:

//.NET版本不比對,請安裝需要的.NET版本,詳情見第3點說明

//3.

//visual studio如何修改c++項目的.net framework架構版本

//修改項目檔案

//在 Visual Studio 的“解決方案資料總管”中,打開項目的快捷菜單,然後選擇“解除安裝項目”。

//這将為你的項目解除安裝項目檔案(.vcxproj)。

//在菜單欄上,依次選擇“檔案”、“打開”、“檔案”。 在“打開檔案”對話框中,導航到項目檔案夾,

//然後打開項目檔案(.vcxproj)。在項目檔案中,找到目标 Framework 版本的條目。

//例如,如果你的項目設計為使用.NET Framework 4.5,<PropertyGroup Label = "Globals">元素中找到

//請在<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>元素

//如果 <TargetFrameworkVersion> 元素不存在,則新增之,并修改相應版本号。

//4.

//VC++的平台工具集如果是MSVC2015,則.NET架構至少要4.0版本

//VC++的平台工具集如果是MSVC2013,則.NET架構可以是3.5版本

//考慮到純淨版的Windows 7作業系統自帶的.NET版本是3.5,是以建議C++工程使用MSVC2013編譯;

//因為客戶的Win7電腦不一定會有.NET4.0,這樣我們自己可以省得每次裝置出貨時安裝.NET4.0架構

二、再來看網上摘錄的經驗總結

C++編寫的程式為非托管代碼,C#編寫的程式為托管代碼。托管代碼雖然提供了其他開發平台沒有的許多優勢,但由于前期系統及曆史版本很多使用的是非托管代碼編寫的程式,是以CLR提供了一些機制,允許在應用程式中同時包含托管和非托管代碼。具體說分為以下三種:

1、托管代碼能調用DLL中的非托管函數。通過P/Invoke(Platform Invoke)機制調用DLL中的函數,如Kernel32.dll等。

2、托管代碼可以使用現有COM元件(伺服器)。許多公司都已經實作了大量非托管COM元件。利用來自這些元件的類型庫,可建立一個托管程式集來描述COM元件。托管代碼可像通路其他任何類型一樣通路托管程式集中的類型。

3、非托管代碼可以使用托管類型(伺服器)。許多現有的非托管代碼要求提供COM元件來確定代碼正确工作。使用托管代碼可以更簡單地實作這些元件,避免所有代碼都不得不和引用計數和接口打交道。比如C++調用C#開發的dll。

那C++如何調用C#寫的庫?查了網上的資料,目前知道兩種情況,一種是用C++/CLI(通用語言接口),另一種則是使用COM組建。

總結:

1)用C#寫任何的類庫

2)C++ 中要引用此類庫,使用#using引用C#編寫的DLL,而不是#include,引用C#的DLL後,還需要添加該DLL的命名空間using namespace MathDLL

3)建立C#對象時要用gcnew ;

4) C++ 編譯設定一定設定為:支援公共語言運作時支援(/clr),使用C++/clr文法,采用正确的方式通路托管對象,即:使用帽子“^”,而不是“*”

5) 自身的C++類要用 ref class 定義。

6)#using "..\\TestDLL\\bin\\Debug\\TestDLL.dll"  這是VC++托管代碼中調用.net DLL的方法,如果是原生C++代碼,不能這麼調用,要用COM方式,但是被調用的必須是public static方法。

7)CSDN趙4老師的建議是:

不要做A語言代碼修改為B語言代碼的無用功。

也不要做用A語言代碼直接調用B語言代碼庫這樣複雜、這樣容易出錯的傻事。

隻需讓A、B語言代碼的輸入輸出重定向到文本檔案,或修改A、B語言代碼讓其通過文本檔案輸入輸出。

即可很友善地讓A、B兩種語言之間協調工作。

比如:

A将請求資料寫到檔案a.txt,寫完後改名為aa.txt

B發現aa.txt存在時,讀取其内容,調用相應功能,将結果寫到檔案b.txt,寫完後删除aa.txt,再将b.txt改名為bb.txt

A發現bb.txt存在時,讀取其内容,讀完後删除bb.txt

以上A可以替換為任何一種開發語言或開發環境,B可以替換為任何一種與A不同的開發語言或開發環境。

除非A或B不支援判斷檔案是否存在、檔案讀寫和檔案更名。

但是誰又能舉出不支援判斷檔案是否存在、檔案讀寫和檔案更名的開發語言或開發環境呢?

可以将臨時檔案放在RamDisk上提高效率減少磨損磁盤。

資料的結構很複雜的話,文本檔案的格式問題可參考json或xml

共享臨時文本檔案這種程序之間的通訊方法相比其它方法的優點有很多,下面僅列出我現在能想到的:

·程序之間松耦合

·程序可在同一台機器上,也可跨機,跨作業系統,跨硬體平台,甚至跨國。

·友善調試和監視,隻需讓第三方或人工檢視該臨時文本檔案即可。

·友善線上開關服務,隻需删除或建立該臨時文本檔案即可。

·友善實作分布式和負載均衡。

·友善隊列化提供服務,而且幾乎不可能發生隊列滿的情況(除非硬碟空間滿)

·……

“跨語言、跨機,跨作業系統,跨硬體平台,跨國,跨*.*的”苦海無邊,

回頭是“使用共享純文字檔案進行資訊交流”的岸!

三、轉載網上文章《N種方法使用C++調用C#.NET庫》

正常方法1:COM

使用C#把托管類注冊成COM,用regasm.exe注冊output assembly,然後用C++像調用COM一樣調用assembly裡面的type。

優點:編寫代碼簡單,調用友善

缺點:需要注冊output,釋出不夠簡單

參考:http://www.codeproject.com/KB/cs/ManagedCOM.aspx

正常方法2:CLR

C#正常編寫類,生産assembly,C++使用CLR編譯既可直接引用托管類。

缺點:需要了解C++ CLR文法(既不像C++,又不像C#,總之很奇怪)

參考:http://www.codeproject.com/KB/mcpp/cppcliintro01.aspx

http://msdn.microsoft.com/en-us/library/k8d11d4s.aspx

正常方法3:API

C#正常編寫類,生産assembly,C++使用SDK提供的CLR非托管接口(CLRCreateInstance)進行調用。

優點:傳統C#程式設計,傳統C++程式設計

缺點:要求.Net Framework 4.0以上版本

參考:http://nport.codeplex.com/SourceControl/changeset/view/45681#903468

http://msdn.microsoft.com/en-us/library/dd537633.aspx

變通方法:

1. 使用C#/VB包裝現有托管類,注冊成Windows服務,暴露SOAP web service。VC2005可以使用非托管代碼添加引用Web service。

2. 使用C#/VB包裝現有托管類,注冊成Windows服務。C++利用Windows message和服務通訊。

3. 使用C#/VB包裝現有托管類,注冊成Windows服務。C++利用Windows共享記憶體和服務通訊。

其實利用雙程序通訊的方法,可以演變出各種各樣調用的思路。聰明的你可以充分發揮想象力,寫出自己獨有的調用模式。

---

參考文獻:

https://www.cnblogs.com/bylikai/p/4695317.html

CLR

https://www.cnblogs.com/huangmianwu/p/6145044.html

COM

https://blog.csdn.net/shq886258963/article/details/59057797

兩種都有

https://blog.csdn.net/sudazf/article/details/52160514

這個好

從C++到C++/CLI 科普

https://docs.microsoft.com/zh-cn/previous-versions/dotnet/netframework-4.0/ms172271(v=vs.100) https://docs.microsoft.com/en-us/previous-versions/ms235289(v=vs.140) https://docs.microsoft.com/zh-cn/cpp/dotnet/initialization-of-mixed-assemblies?view=vs-2019