可能是最簡單的把C++Lib包裝成C#可用dll的方法


(想直接看結果的直接翻到最后)

之前對C++接觸不多,最近工作需要,第三方給了一個C++的lib庫,我們需要把它封裝一下在C#中調用。對方要是直接給Dll就省事了。。。

研究了一下,基本有三個方向:

1. 建立CLI類型的,或者叫Managed的基於.NET的dll,這樣c#可以直接進行引用。

2. 建立native的c++ dll,然后在C#用 dllimport的方式調用。

3. 建立com組件。

一開始感覺第一種很美好。直接加到reference中就能像引用一個C#的dll一樣使用了。而且有一個好處是,我可以把這個dll工程和我的調用的C#工程放在一個solution中,然后在調試的時候,斷點能直接進入到這個C++的工程中。這點要調試起來是很美好的哦。

方法可以參考這個:https://docs.microsoft.com/en-us/cpp/dotnet/how-to-wrap-native-class-for-use-by-csharp?view=vs-2017

一個不錯的C#使用CLI/CLR 調用native C++ 的例子:http://www.dorodnic.com/blog/2014/12/10/calling-cpp-by-example/

基本上就是創建一個CLI類型的工程。注意工程的屬性,選擇一下CLR,以及Framework的版本。

 

在Header中引入頭文件,在Resources中引入Lib文件。

 

這樣在GoWrapper.cpp中就可以把需要的函數封裝一下了。

 

 

這里可以選擇更好的封裝方式,比如對於原有的C++函數使用指針來返回結果的方式,我們可以使用一個自定義的類來返回之類的。但是考慮到要包裝很多的函數,為了簡便,最好讓包裝好的函數看起來和原有的函數差不多,對於指針可以通過ref或者out的方式來調用。

這樣在調用的時候,就可以像下面這樣調用:

 

注意如果想要用ref的方式調用的話,用下面這種來聲明:

 

到現在,CLI的Managed dll方式基本已經完成了。可是想想如果要包裝的時候,這一百多個函數的類型轉換也將會是很大的一個工作量。我決定再嘗試一下native dll的方式,雖然不能在同一個solution中debug,但是畢竟包裝起來方便一些,只好忍忍了。

參考文檔:https://msdn.microsoft.com/en-us/library/ms235636.aspx

主要就是要在native dll的函數前面加上 __declspec(dllexport) int __stdcall 的聲明(__stdcall非必須),它就可以export了。

MSDN的關於dllexport和dllimport的說明:https://msdn.microsoft.com/zh-cn/library/3y1sfaz2.aspx

還有下面這個也不錯:

https://docs.microsoft.com/zh-cn/cpp/build/importing-into-an-application-using-declspec-dllimport?view=vs-2017

為什么要寫成 ifdef 就 export, 如果不,就import的方式,主要是為了便於同一個頭文件可以同時應用於客戶端和提供端。

根據上面那個walkthrough,native 的dll還是很好創建的。要記得在工程屬性里面,CLR不要選擇,就是native 的dll,或者記得要在創建project的時候的模板就選擇native的。

不過,這樣生成的dll,我在import的時候遇到了問題。import的代碼如下:

 

 

這里我必須使用一個EntryPoint=“#1”來指定我這個函數的entrypoint,因為生成的dll里面,export的函數的entrypoint的名稱后面有一串 @xxxx 的東西。這個entrypoint 可以使用depends打開查看,可以使用名稱或者序號。這樣很不方便對不對,我用過的dllimport沒有哪個是要這么搞的。為了解決這個問題,我們需要用到一個DEF文件。在properties中可以指定所使用的DEF文件,不過如果你自己添加一個DEF文件的話,它會被自動添加到Properties的設置中的,其實你不需要手動去指定它。

 

Def文件的作用就是告訴編譯程序,我要把哪個函數用來export,用什么樣的名稱來export。當然,有了這個DEF文件,就可以不需要__declspec(dllexport) int的聲明了。

修改之后的頭文件:

 

修改之后的def文件:

 

調用方:

 

到現在,應該還比較圓滿了。雖然我么有了調試C++庫的便利,但是包裝幾百個函數也容易一些。只要直接把那個函數return回去就好了。

正當這時,凝望着我可愛的頭文件。我忽然想起,當用depends查看生成的dll的時候。在依賴中是可以看到第三方的函數的。它們貌似也都加過 __declspec的前綴。那么既然它都加過了。那我還再Wrap一遍干啥???試了一下。把DEF文件刪掉,把我加的Wrapper刪掉,把我加的頭文件也刪掉。試了一下,可以用!!!

最終,其實就只是創建了一個native的dll,在resources里面加上了第三方的lib文件而已。別的自己的頭文件和cpp文件一個都不用加的。有一種“慕然回首,那人卻在燈火闌珊處”的感覺。雖然轉了一圈,但是也算對於各種DLL的知識都有了了解,也算是有很多的收獲了。而且這個方法適用的前提在於第三方已經把自己的函數都添加了 declspec的前綴。如果沒有的話,可以簡單的通過添加 DEF文件的方式來export出想要的方法。

附一個DEF文件的文檔:https://docs.microsoft.com/zh-cn/cpp/build/reference/module-definition-dot-def-files?view=vs-2017

轉載請注明出處!!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM