混合语言编程:启用CLR(公共语言运行时编译)让C#调用C++
前言
关于混合C#和C++的编程方式,本人之前写过一篇博客(参见混合语言编程:C#使用原生的Directx和OpenGL),在之前的博客中,介绍了在C#的Winform和WPF下使用原生的Direct和OpenGL进行绘图,主要使用的方式是声明一个函数为导出函数,然后就可以在C#中使用这个函数。
存在的问题
之前的方式使C#调用C/C++成为可能,但是存在很多缺点,主要表现在以下几个方面:
- 使用
extern "C" _declspec(dllexport)的声明方式只能定义C函数,无法直接使用C++的类,功能不够强大。 - 参数传递很麻烦,尤其是传入数组时,经常会出现参数类型错误或者数组长度不正确,很不灵活。
- 需要写重复性的代码,在C#代码中需要重复声明C/C++写的DLL中的函数,如果在C/C++代码中定义了结构体,还需要在C#中重复声明,处理参数类型又是一个麻烦的事情。
- 需要手动拷贝DLL到C#程序的目录下,如果忘记拷贝了,程序在运行时会报DLL未找到的错误。
- 非常不利于调试,无法在C/C++代码中进行断点跟踪调试。同时对C/C++代码修改编译后,需要拷贝DLL到C#程序目录,否则C#程序调用的还是修改之前的DLL。
前段时间开发的一个应用程序中需要控制两个数采卡(SP Divece 的ADQ和SDR),官方提供了C和C++的驱动,可以使用C/C++对数采卡进行控制。我最开始还是使用了之前声明导出函数的方式进行开发,用C语言实现,但是随着功能的复杂和代码的增加,上面一系列问题越来越严重。
发现新大陆(公共语言运行时编译)
在奋斗解决各种Bug的时候突然在一次搜索时找到了公共语言运行时编译。所谓公共语言运行时编译,就是允许应用程序和组件使用公共语言运行时 (CLR) 中的功能。找到MSDN上的相关文档:
有了公共语言运行时编译,在C#程序集中就可以引用C++开发的DLL,并且使用C++的类就和使用使用C#类是一样的,还可以直接断点调试,以上问题全部解决。
很快,我就把之前用C写的代码改写成了C++的代码,启用CLR,并删掉了C#中重复的代码。
指针问题
使用C++开发就会经常使用到指针,但C#没有指针(一般情况,其实C#是有指针的,只不过默认被关闭了)。在C#中要传递一个指针至少有两种方式:
使用
stackalloc在栈上分配内存块,这类似于C的malloc和C++的new(当然还是有区别的),详细信息可参考stackalloc(C# 参考)。使用
fixed语句固定变量的指针,C#中之所以不让用指针,就是因为由于垃圾回收机制会导致变量重定位,变量重定位后,之前的指针也就不再指向这个变量了,所以C#在这种情况下是要禁止使用指针。而fixed 语句禁止垃圾回收器重定位可移动的变量,并在执行该语句期间“固定”此变量。固定变量的位置后就可以使用指针了,详细信息可参考fixed 语句(C# 参考)。
需要提醒的是,这两种方式都需要在不安全的上下文中使用,关于不安全上下文,可参考unsafe(C# 参考)。
结语
本文主要记录我在做项目中发现的问题、解决问题所使用到相关的技术,有效地解决了C#调用C++的问题。当然,其中还有很多细节并没有深入研究,可能会存在更好的方式。
混合语言编程:启用CLR(公共语言运行时编译)让C#调用C++的更多相关文章
- 公共语言运行时支持(/clr)
项目属性 -> 配置属性 -> “常规”里开启“公共语言运行时支持(/clr)
- clr(Windows 运行时和公共语言运行时)
Windows 运行时 编译器使用 COM 引用计数机制来确定对象是否不再使用并可以删除. 因为从 Windows 运行时接口派生的对象实际上是 COM 对象,所以这是可行的. 在创建或复制对象时 ...
- CLR 公共语言运行库
1..支持多语言..只是语言是面向CLR的..均可以在此基础上运行. 2..程序集加载..程序打包之后的Dll文件由CLR(公共语言运行库)来编译并加载到可以执行状态..由CLR(公共语言运行库)加载 ...
- [bug]”System.InvalidProgramException:公共语言运行时检测到无效程序“解决方案
Visual Studio 2017版本15.8.x运行某些程序会报这样的错误:“System.InvalidProgramException:公共语言运行时检测到无效程序” 此问题的临时解决方案: ...
- ASP.NET Core3.0 中的运行时编译
运行时编译 通过 Razor 文件的运行时编译补充生成时编译. 当 .cshtml 文件的内容发生更改时,ASP.NET Core MVC 将重新编译 Razor 文件 . 通过 Razor 文件的运 ...
- 自己动手实现springboot运行时执行java源码(运行时编译、加载、注册bean、调用)
看来断点.单步调试还不够硬核,根本没多少人看,这次再来个硬核的.依然是由于apaas平台越来越流行了,如果apaas平台选择了java语言作为平台内的业务代码,那么不仅仅面临着IDE外的断点.单步调试 ...
- c#中运行时编译时 多态
c#中运行时编译时 多态 public class aa { } public class bb:aa { } public class cc { public static void Main( ...
- 在Asp.Net Core MVC 3.0 视图运行时编译
在正常情况下,视图在生成的时候就会变为 xxx.Views.dll,在开发的时候,这样很不方便,因为很多的时候,我们只是修改一个样式,调整一些JavaScript代码,这个时候要把项目调试暂停下来,生 ...
- C语言版kafka消费者代码运行时异常kafka receive failed disconnected
https://github.com/edenhill/librdkafka/wiki/Broker-version-compatibility如果使用了broker版本是0.8的话, 在运行例程时需 ...
随机推荐
- Ubuntu 14.04下安装JDK8
本文地址:http://www.cnblogs.com/archimedes/p/ubuntu-jdk8.html,转载请注明源地址. 欢迎关注我的个人博客:www.wuyudong.com, 更多云 ...
- Mac 下使用sourcetree操作git教程
SourceTree 是 Windows 和Mac OS X 下免费的 Git 和 Hg 客户端,同时也是Mercurial和Subversion版本控制系统工具.支持创建.克隆.提交.push.pu ...
- iOS开发笔记3:XML/JSON数据解析
这篇主要总结在iOS开发中XML/JSON数据解析过程用到的方法.XML数据解析主要使用SAX方式的NSXMLParser以及DOM方式的GDataXML,JSON数据解析主要使用NSJSONSeri ...
- window平台下的MySQL快速安装。(不好意思,未完成待续,请飘过)
MySQL安装方式 MSI安装(Windows Installer) ZIP安装 最好选择ZIP安装,比较干净,也快速搞好. 下载链接:http://pan.baidu.com/s/1sjFZZul ...
- Tomcat服务器性能优化
在这篇文章里分以下的七个步骤,按照这些步骤走,Tomcat服务器的性能就能改善哦. 增加JVM堆(heap) 解决内存泄漏问题 线程池(thread pool)的设置 压缩 调节数据库性能 Tomca ...
- delete_old_backup.bat
在前面forfiles命令批量删除N天前文件 这篇文章里面讲述了如何在SQL Server 2000中使用forfile删除N天前备份文件,但是现在又有新需求: 需求描述:通过数据库维护计划将备份生成 ...
- cmd常用命令 和 sql server相关基础
在Java开发中 ms sql server 接触算是比较少的,本文记录一些ms sql server的基础知识. 1. 为表字段增加索引:create index user_openid on us ...
- c#,关于Big Endian 和 Little Endian,以及转换类
Big Endian:最高字节在地址最低位,最低字节在地址最高位,依次排列. Little Endian:最低字节在最低位,最高字节在最高位,反序排列. 当在本地主机上,无需注意机器用的是Big En ...
- nginx根据IP限制访问
nginx有两个模块可以控制访问 HttpLimitZoneModule 限制同时并发访问的数量 HttpLimitReqModule 限制访问数据,每秒内最多几个请求 http{ ## ...
- Oracle错误日志:ORA-00257
今天下午刚启动程序,就报以下错误: Caused by: java.sql.SQLException: ORA-00257: 归档程序错误.在释放之前仅限于内部连接. 经查,是oracle数据库日志满 ...