• 混合语言编程:启用CLR(公共语言运行时编译)让C#调用C++


    前言

    关于混合C#和C++的编程方式,本人之前写过一篇博客(参见混合语言编程:C#使用原生的Directx和OpenGL),在之前的博客中,介绍了在C#的Winform和WPF下使用原生的Direct和OpenGL进行绘图,主要使用的方式是声明一个函数为导出函数,然后就可以在C#中使用这个函数。

    存在的问题

    之前的方式使C#调用C/C++成为可能,但是存在很多缺点,主要表现在以下几个方面:

    1. 使用extern "C" _declspec(dllexport) 的声明方式只能定义C函数,无法直接使用C++的类,功能不够强大。
    2. 参数传递很麻烦,尤其是传入数组时,经常会出现参数类型错误或者数组长度不正确,很不灵活。
    3. 需要写重复性的代码,在C#代码中需要重复声明C/C++写的DLL中的函数,如果在C/C++代码中定义了结构体,还需要在C#中重复声明,处理参数类型又是一个麻烦的事情。
    4. 需要手动拷贝DLL到C#程序的目录下,如果忘记拷贝了,程序在运行时会报DLL未找到的错误。
    5. 非常不利于调试,无法在C/C++代码中进行断点跟踪调试。同时对C/C++代码修改编译后,需要拷贝DLL到C#程序目录,否则C#程序调用的还是修改之前的DLL。

    前段时间开发的一个应用程序中需要控制两个数采卡(SP Divece 的ADQ和SDR),官方提供了C和C++的驱动,可以使用C/C++对数采卡进行控制。我最开始还是使用了之前声明导出函数的方式进行开发,用C语言实现,但是随着功能的复杂和代码的增加,上面一系列问题越来越严重。

    发现新大陆(公共语言运行时编译)

    在奋斗解决各种Bug的时候突然在一次搜索时找到了公共语言运行时编译。所谓公共语言运行时编译,就是允许应用程序和组件使用公共语言运行时 (CLR) 中的功能。找到MSDN上的相关文档:

    1. /clr(公共语言运行时编译)
    2. 混合(本机和托管)程序集
    3. 如何:使用 /clr 编译 MFC 和 ATL 代码

    有了公共语言运行时编译,在C#程序集中就可以引用C++开发的DLL,并且使用C++的类就和使用使用C#类是一样的,还可以直接断点调试,以上问题全部解决。

    很快,我就把之前用C写的代码改写成了C++的代码,启用CLR,并删掉了C#中重复的代码。

    指针问题

    使用C++开发就会经常使用到指针,但C#没有指针(一般情况,其实C#是有指针的,只不过默认被关闭了)。在C#中要传递一个指针至少有两种方式:

    1. 使用stackalloc在栈上分配内存块,这类似于C的malloc和C++的new(当然还是有区别的),详细信息可参考stackalloc(C# 参考)

    2. 使用fixed语句固定变量的指针,C#中之所以不让用指针,就是因为由于垃圾回收机制会导致变量重定位,变量重定位后,之前的指针也就不再指向这个变量了,所以C#在这种情况下是要禁止使用指针。而fixed 语句禁止垃圾回收器重定位可移动的变量,并在执行该语句期间“固定”此变量。固定变量的位置后就可以使用指针了,详细信息可参考fixed 语句(C# 参考)

    需要提醒的是,这两种方式都需要在不安全的上下文中使用,关于不安全上下文,可参考unsafe(C# 参考)

    结语

    本文主要记录我在做项目中发现的问题、解决问题所使用到相关的技术,有效地解决了C#调用C++的问题。当然,其中还有很多细节并没有深入研究,可能会存在更好的方式。

  • 相关阅读:
    python没有switch,可以用字典来替代
    Django1.8:403错误:CSRF verification failed. Request aborted.
    django重定向
    第九章 JSP标签——《跟我学Shiro》
    第八章 拦截器机制——《跟我学Shiro》
    第七章 与Web集成——《跟我学Shiro》
    第六章 Realm及相关对象——《跟我学Shiro》
    第五章 编码/加密——《跟我学Shiro》
    第四章 INI配置——《跟我学Shiro》
    第三章 授权——《跟我学Shiro》
  • 原文地址:https://www.cnblogs.com/5long/p/5251606.html
Copyright © 2020-2023  润新知