混合语言编程:启用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的话, 在运行例程时需 ...
随机推荐
- android 浏览器开发实例
android app需要通过手机显示网页信息还是比较常用的,比如我最近业余开发的 抢商铺游戏,需要对游戏规则做说明,规则会比较多,而且要经常变动,就想到用网页来展示,更新起来方便,不像应用,一旦发布 ...
- android res文件夹下面的 values-v11 、 values-v14
values-v11代表在API 11+的设备上,用该目录下的styles.xml代替res/values/styles.xml values-v14代表在API 14+的设备上,用该目录下的styl ...
- Android项目实战(三):实现第一次进入软件的引导页
最近做的APP接近尾声了,就是些优化工作了, 我们都知道现在的APP都会有引导页,就是安装之后第一次打开才显示的引导页面(介绍这个软件的几张可以切换的图) 自己做了一下,结合之前学过的 慕课网_Vie ...
- 关于一个软件ipa包的其他图片资源
有时候 当你打开一个ipa包内容的时候 可能会找不到全部的资源 所以你需要在github上下载一个插件 下载下来以后 运行一下 然后会出来这个 把ipa 文件 拖到里面 ...
- 【转】IOS开发资源汇总
转自:http://blog.csdn.net/favormm/article/details/6664970 如何用Facebook graphic api上传视频: http://develope ...
- C语言-02-基本运算
一.算术运算 种类 1> 加(+),同时可以表示正号 2> 减(-),同时可以表示负号 3> 乘(*) 4>除(/) 5>取余(%) 关于类型转换 1>自动类型转换 ...
- Swift 中的函数(下)
学习来自<极客学院:Swift中的函数> 工具:Xcode6.4 直接上基础的示例代码,多敲多体会就会有收获:百看不如一敲,一敲就会 import Foundation /******** ...
- FFT教你做乘法(FFT傅里叶变换)
题目来源:https://biancheng.love/contest/41/problem/C/index FFT教你做乘法 题目描述 给定两个8进制正整数A和B(A和B均小于10000位),请利用 ...
- javascript对象模型和function对象
javascript中,函数就是对象 <html> <head> <script type="text/javascript"> functio ...
- javascript 全局变量 局部变量 var 与不加var的区别
一.外部的为全局,内部的为局部变量. 二.加var为局部变量(在方法内),不加var为全局变量(当方法内有一次使用后) <script type="text/javascrip ...