写操作之前,还是扼要的说一下托管与非托管C++的区别好了,其实我也并没有深入了解过托管C++的特点所在,其最大的特征就是可以由系统来调试回收相关的代码资源,跟C#的特性一样,只是编程风格跟C++类似而已,因此,这决定了C#与托管C++是可以完美结合在一起的。托管C++生成的dll跟C#生成的dll应该说是没区别的,之所以产生托管C++这种怪物,完全是因为微软在极力推崇C#,必须要兼顾不同语言间交互。

好吧,接下来正经的写一下过程。先摆出目的:我手上有一个C++写的类(ClassA),想在C#下调用这个类,可是C#是没有简单的像dllimport这样的方法获取非托管C++ dll里的类。我的解决方法是,生成一个托管C++的dll,因为托管代码与非托管代码是不能在一个文件里混编的,所以我必须将ClassA用托管C++的手段封装一下,然后生成一个dll,以供C#调用。

也许我这里说得很绕,请看下面的教程,会很明了的。

一、建立CLR类库工程

其实,我挺想忽略类似这些步骤的,一幅图能说明的问题我就不多说,反正建立一个CLR类库工程,其命名暂定为ManageClass,这是工程名,请勿混淆,如下图,没什么注意事项可言的。(抱怨一下,为啥51CTO没法在编辑里缩小图片的,PS好麻烦)

二、一个非托管C++的例子

我手上有一个用非托管C++写的类NativeClass,它本身是属于另外一个非托管C++工程,现在我直接将这个类文件拷贝到本工程的目录下去,简单起见,这个类我内联在一个头文件里,如果是其他比较大型的类,必要将NativeClass.h里#include到的其他文件也一并拷贝到本新建工程目录下,然后将这些文件添加到VS的资源管理器下,如下图所示:

上图中,除了NativeClass.h文件是我添加进去的,其他都是工程自带的东西,其中ManageClass.h及ManageClass.cpp是要生成dll所动用到的东西,暂时先不管,我们看一下NativeClass.h里的内容:

#pragma once
class _declspec(dllexport) NativeClass
{
private:int nCount;
public:NativeClass(void){this->nCount = 0;}~NativeClass(void){}int GetCount(void){return this->nCount;}void Increase(void){this->nCount++;}void Clear(void){this->nCount = 0;}
};

类的内容简单到我不忍直视,像类头的_declspec(dllexport)字段其实可要可不要的,只是我懒得删除而已。

三、非装成托管C++的内容

这一步是很关键的,之所以有这么一步,是因为托管C++与非托管C++没法混编,于是乎我将托管代码将上面的NativeClass类封装了一下,本来按规范而言我应该将函数声明与实现分开写,但我承认我又偷懒了,只在ManageClass.h里作修改,虽然没有用到ManageClass.cpp,但无论如何也别将这个文件删除,否则是没法生成dll的。我的封装代码如下:

// ManageClass.h
#pragma once
#include "NativeClass.h"
using namespace System;
namespace ManageClass {public ref class NativeClassEx{// TODO: 在此处添加此类的方法。private:NativeClass * m_pnClass;public:NativeClassEx(void){this->m_pnClass = new NativeClass();}~NativeClassEx(void){delete this->m_pnClass;}int GetCount(void){return this->m_pnClass->GetCount();}void Increase(void){this->m_pnClass->Increase();}void Clear(void){this->m_pnClass->Clear();}protected:!NativeClassEx(void){delete this->m_pnClass;}};
}

别告诉我上面的代码你没看懂,我会建议你找块豆腐撞脑袋的。

四、生成托管C++的dll

其实到了这一步就结了,你直接点编译,就会在工程外的Debug文件夹里生成ManageClass.dll了,务必要看清,经过封装后,我新的类名是叫NativeClassEx,请在使用时注意一下。

五、项目测试dll

调用托管C++的dll跟调用C#的dll没任何区别,新建一个测试工程(我用的是WinForm的窗体工程),名字叫DllTest,在解决方案资源管理器里将刚刚生成的那个ManageClass.dll添加到引用里,使用using ManageClass,然后你就可以用了,其测试代码就几句话:

NativeClassEx testCalss = new NativeClassEx();
Debug.WriteLine("GetCount : " + testCalss.GetCount().ToString());
testCalss.Increase();
testCalss.Increase();
testCalss.Increase();
Debug.WriteLine("GetCount : " + testCalss.GetCount().ToString());
testCalss.Clear();
Debug.WriteLine("GetCount : " + testCalss.GetCount().ToString());

编译一下,看输出窗口,类还是完美运行得了的。

六、注意事项

1、尽管C#与托管C++很大程度上兼容,但还是要注意基本类型外的对齐问题,像结构体、string类这些,最好入口参数除了基本类型其他都别用,这点请参考我上一篇文章;

2、我尝试用托管C++封装我写OpenCV类,类里再调用了OpenCV的dll(即C#调用托管dll,托管dll调用非托管dll),编译通过,但实际运行不行,里面有什么问题暂时不清楚;

3、建议,没什么事别用这种方法来调用类,C#中调用dll的函数才是最具保障的。

4、示例工程请在这里下载,用前记得先编译好dll,并确保添加了引用,可能会有一些关于CPU类型选择的warning,请诸位自力更生了。

转载于:https://blog.51cto.com/joeyliu/1297961

在C#调用C++的DLL简析(二)—— 生成托管dll相关推荐

  1. 关于Dll、Com组件、托管dll和非托管dll的理解

    Com组件和dll区别: 1.普通dll不能通过regsvr32.exe来注册,而Com组件能通过regsvr32.exe注册. 2.Com组件是微软的一个协议,满足com组件协议的dll文件就是co ...

  2. Linux Hugetlbfs内核源码简析-----(二)Hugetlbfs挂载

    本文只讨论执行"mount none /mnt/huge -t hugetlbfs"命令后,mount系统调用的执行过程(基于Linux-3.4.51),不涉及进程相关的细节. m ...

  3. C#调C++生成的dll报0x800736B1错误

    2019独角兽企业重金招聘Python工程师标准>>> 这个错误看上去好像是 C++ DLL库本身的问题,其实并不尽然.由于使用了混合模式编译托管 DLL ,所以该 DLL 又会用到 ...

  4. 静态库调用_静态链接和动态链接对比简析

    0. 简介 在Linux环境下进行开发工作,代码要经过编译链接生成二进制可执行文件,才能被CPU识别并执行:程序的编译过程可以参考另外一篇文章<linux程序编译过程简析>:链接过程分为两 ...

  5. 匿名函数自我调用_Python中的匿名函数及递归思想简析

    匿名函数 前言 上次咱们基本说了一下函数的定义及简单使用,Python中的基本函数及其常用用法简析,现在咱们整点进阶一些的.同样都是小白,咱也不知道实际需要不,但是对于函数的执行顺序以及装饰器的理解还 ...

  6. 简析Visual C++中的活动数据对象

    简析Visual C++中的活动数据对象 程序运行效果截图: 摘 要: 本文简要介绍了微软的活动数据对象(ADO)模型,结合实例阐述了在Visual C++环境下使用ADO操纵数据库的基本步骤,分析A ...

  7. 浅谈跨网站脚本攻击(XSS)的手段与防范(简析新浪微博XSS攻击事件)

    本文主要涉及内容: 什么是XSS XSS攻击手段和目的 XSS的防范 新浪微博攻击事件 什么是XSS 跨网站脚本(Cross-sitescripting,通常简称为XSS或跨站脚本或跨站脚本攻击)是一 ...

  8. Unity 之 UGUI Dropdown组件使用简析

    Unity 之 UGUI Dropdown组件使用简析 官方释义 示例展示 代码操作 官方源码 官方释义 官方文档:https://docs.unity3d.com/Manual/script-Dro ...

  9. 【Golang源码分析】Go Web常用程序包gorilla/mux的使用与源码简析

    目录[阅读时间:约10分钟] 一.概述 二.对比: gorilla/mux与net/http DefaultServeMux 三.简单使用 四.源码简析 1.NewRouter函数 2.HandleF ...

最新文章

  1. java 得到checkbox_【JavaWeb】获得选中的checkbox的value
  2. ios怎样在一个UIImageButton的里面加一些自己定义的箭头
  3. html下拉框设置默认值_如何设置HTML select下拉框的默认值?
  4. 高德地图定位精度多少米_中美俄卫星定位精度分别是多少?美0.1米,俄10米,中国呢?...
  5. MySQL中通过结构化文本倒腾数据
  6. 将所有行复制到剪贴板
  7. 《CLR via C#》精髓:静态类
  8. pxe结合kickstart文件实现全自动化安装
  9. 数字图像处理 冈萨雷斯(第四版)图像配准
  10. mac抓包工具charles破解版安装及简单使用
  11. 微信公众平台的php文件的,php版微信公众平台入门教程之开发者认证的方法
  12. LaTeX数学表达式
  13. 鸿蒙熔炉是真实存在的吗,古董局中局父辛爵是真的吗 父辛爵真实存在国内仅有两件...
  14. kubernetes指南--弹性伸缩
  15. Eclipse 照亮Java众生
  16. 区块链数据服务 - BDS
  17. java中scanner关于hasnext等的问题
  18. 如何搜索百度云盘里的文件
  19. 浅析PageRank算法
  20. SAP中国研究院总裁芮祥麟:从千里马到伯乐

热门文章

  1. 360的驱动(qutmdrv.sys)分页内存泄露
  2. JS 判断URL中是否含有 http:// 如果没有则自动为URL加上
  3. ML numpy、pandas、matplotlib的使用
  4. “stdafx.h”: No such file or directory
  5. HDU 2255 二分图最佳匹配 模板题
  6. (转)JAVA正则表达式语法大全
  7. 详细解读Spring2.5 +Struts1.3 框架(使用Spring声明式事物管理和springjjdbc模板)
  8. HDU 3646 DP + 二分
  9. sqlserver数据库大型应用解决方案总结 数据库负载均衡
  10. XCTF-高手进阶区:unserialize3