混合语言编程:启用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的话, 在运行例程时需 ...
随机推荐
- Sharepoint学习笔记—习题系列--70-573习题解析 -(Q81-Q84)
Question 81You need to create a Web Part that creates a copy of the out-of-the-box Contribute permis ...
- android XMl 解析神奇xstream 三: 把复杂对象转换成 xml
前言:对xstream不理解的请看: android XMl 解析神奇xstream 一: 解析android项目中 asset 文件夹 下的 aa.xml 文件 android XMl 解析神奇xs ...
- C标准库<ctype.h>实现
本文地址:http://www.cnblogs.com/archimedes/p/c-library-ctype.html,转载请注明源地址. 1.背景知识 ctype.h是C标准函数库中的头文件,定 ...
- 带删除的EditText
在安卓开发中EditText是比较常用的控件之一,那我们平常看到EditText填写了内容之后右边会出现一个删除的按钮,这样可以方便用户对其中文本清空操作,是非常人性化的,我们可以重写EditText ...
- UVa 103 - Stacking Boxes(dp求解)
题目来源:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&pa ...
- js 字符串转 数字
<html> <body> <script language="javascript"> var a = "0.11"; v ...
- Openstack python api 学习文档 api创建虚拟机
Openstack python api 学习文档 转载请注明http://www.cnblogs.com/juandx/p/4953191.html 因为需要学习使用api接口调用openstack ...
- informatica 厂商培训资料
1.informatica中domain与node的理解: domain 类似于局域网,node就是局域网中的节点或者计算机. node应与repository在数据库中存储在不同的scheme中,此 ...
- Effective Java 36 Consistently use the Override annotation
Principle Use the Override annotation on every method declaration that you believe to override a sup ...
- PowerVault TL4000 Tape Library 告警:“Media Attention”
Dell PowerVault TL4000 磁带库机的指示灯告警,从Web管理平台登录后,在菜单"Library Status"下发现如下告警信息: Library Sta ...