(想直接看結果的直接翻到最後)c++
以前對C++接觸很少,最近工做須要,第三方給了一個C++的lib庫,咱們須要把它封裝一下在C#中調用。對方要是直接給Dll就省事了。。。c#
研究了一下,基本有三個方向:app
1. 創建CLI類型的,或者叫Managed的基於.NET的dll,這樣c#能夠直接進行引用。函數
2. 創建native的c++ dll,而後在C#用 dllimport的方式調用。ui
3. 創建com組件。debug
一開始感受第一種很美好。直接加到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/orm
基本上就是建立一個CLI類型的工程。注意工程的屬性,選擇一下CLR,以及Framework的版本。blog
在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
轉載請註明出處!!