(想直接看结果的直接翻到最后)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
转载请注明出处!!