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

之前对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

转载请注明出处!!

可能是最简单的把C++Lib包装成C#可用dll的方法的更多相关文章

  1. .h(头文件) .lib(库文件) .dll(动态链接库文件) 之间的关系和作用的区分

    .h头文件是编译时必须的,lib是链接时需要的,dll是运行时需要的.附加依赖项的是.lib不是.dll,若生成了DLL,则肯定也生成 LIB文件.如果要完成源代码的编译和链接,有头文件和lib就够了 ...

  2. lib静态链接库,dll动态链接库,h文件

    最近在弄摄像头,发现我在调用摄像头自带的函数的时候,库没连接上,于是经过高人指点,学习了一下lib静态链接库,dll动态链接库来补充一下自己的基础知识. 一.首先我们来介绍一下lib静态链接库. li ...

  3. 用python写个简单的小程序,编译成exe跑在win10上

    每天的工作其实很无聊,早知道应该去IT公司闯荡的.最近的工作内容是每逢一个整点,从早7点到晚11点,去查一次客流数据,整理到表格中,上交给素未蒙面的上线,由他呈交领导查阅. 人的精力毕竟是有限的,所以 ...

  4. Qt5.9一个简单的多线程实例(类QThread)(第一种方法)

    Qt开启多线程,主要用到类QThread.有两种方法,第一种用一个类继承QThread,然后重新改写虚函数run().当要开启新线程时,只需要实例该类,然后调用函数start(),就可以开启一条多线程 ...

  5. “无法获得锁 /var/lib/dpkg/lock -open (11:资源暂时不可用)”的方法

    另外的ubuntu 问题 在更新的时候有时候会出现 “无法获得锁 /var/lib/dpkg/lock -open (11:资源暂时不可用)”的方法 解决办法: 在ubuntu系统的termial下, ...

  6. 用java将简单的word文档换成pdf文档

    用java将简单的word文档换成pdf文档的方式很多,因为很多都没有实际测试过,所以这里就先泛泛的说一下 整体上来看分两种: 1.纯java代码实现,有很多优秀的开源软件可以用,比如poi,itex ...

  7. VC连接mysql数据库错误:libmysql.lib : fatal error LNK1113: invalid machine 解决方法

    VC连接MySQL的配置过程在上一篇博文中,不过当你设置好,以为万事大吉的时候,运行却出现这个错误:libmysql.lib : fatal error LNK1113: invalid machin ...

  8. c++引用lib和dll的方法总结

    C++ 调用.lib的方法: 一: 隐式的加载时链接,有三种方法 1  LIB文件直接加入到工程文件列表中 在VC中打开File View一页,选中工程名,单击鼠标右键,然后选中"Add F ...

  9. 解决eclipse中maven web工程打包成war(发布到tomcar)时lib中没有jar包的解决方法

    可能有两个原因:1.maven中某些jar包下载不下来 从其他地方下载jar文件放到相应maven本地库的.m2里2..classpath文件中缺少(下面代码的作用是制定maven的jar发布路径)& ...

随机推荐

  1. 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

    前言 来源:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会 ...

  2. elasticsearch5.5.3 源码学习 idea下源码编译

    1.学习elasticsearch 源码,通过搜索“elasticsearch源码”,进行相关搜索.   2.因源码gradle编译,选择gradle-3.5可以编译通过,对应elasticsearc ...

  3. [转] Java程序员学C#基本语法两个小时搞定(对比学习)

    Java程序员学C#基本语法两个小时搞定(对比学习)   对于学习一门新的语言,关键是学习新语言和以前掌握的语言的区别,但是也不要让以前语言的东西,固定了自己的思维模式,多看一下新的语言的编程思想. ...

  4. helm-chart6,子chart 和全局值

    chart可以有称为子chart的依赖关系 关于子chart 1,子chart认为是"独立的",即子chart不能明确依赖于其父chart. 2,子chart无法访问其父项的值. ...

  5. Java HotSpot(TM) 64-Bit Server VM warning

    Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x00000007e4200000, 467140608, 0) ...

  6. CSS入门介绍(二)CSS选择器

    css选择器 什么是选择器? 选择器是你构造好网页的结构,需要给这些结构赋予样式,这时候就需要用到选择器,利用选择器将元素与样式一一对应:两者的对应关系可以是一对一,一对多,多对一. 选择器的分类: ...

  7. Vue使用vue-echarts图表

    vue-echarts和echarts的区别: vue-echarts是封装后的vue插件, 基于 ECharts v4.0.1+ 开发,依赖 Vue.js v2.2.6+,功能一样的只是把它封装成v ...

  8. CSS3_盒子背景

    盒子背景 盒子背景:content    padding    特殊的 boder 背景 背景绘制 从 padding 开始绘制 背景裁剪 background-clip(默认值 border-box ...

  9. Solve Error: "errcode": 48001, "errmsg": "api unauthorized hint"

    当你想给微信公众号(不是测试账号)自定义菜单创建接口,遇到如下错误: OK Connection: keep-alive Date: Sat, 01 Dec 2018 05:02:08 GMT Con ...

  10. Java课后作业之石家庄地铁系统PSP表格20190403

    PSP2.1 Personal Software Process Stages Time Planning 计划 36 hours · Estimate · 估计这个任务需要多少时间 36 hours ...