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

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


下面直接方法步骤:

一、建立CLR类库工程


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

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

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

NativeClass.h代码:

#pragma once 

class NativeClass
{
private:
int nCount; public:
NativeClass(void);
~NativeClass(void);
int GetCount(void);
void Increase(void);
void Clear(void);
};

NativeClass.cpp代码:

#include "stdafx.h"
#include "NativeClass.h" NativeClass::NativeClass(void)
{
this->nCount = ;
}
NativeClass::~NativeClass(void)
{
}
int NativeClass::GetCount(void)
{
return this->nCount;
}
void NativeClass::Increase(void)
{
this->nCount++;
}
void NativeClass::Clear(void)
{
this->nCount = ;
}

非托管C++的类很简单。


三、封装成托管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,请诸位自力更生了。

在C#调用C++的DLL方法(二)生成托管的DLL的更多相关文章

  1. eclipse 中main()函数中的String[] args如何使用?通过String[] args验证账号密码的登录类?静态的主方法怎样才能调用非static的方法——通过生成对象?在类中制作一个方法——能够修改对象的属性值?

    eclipse 中main()函数中的String[] args如何使用? 右击你的项目,选择run as中选择 run configuration,选择arguments总的program argu ...

  2. c# 调用c++DLL方法及注意事项

    引用命名空间 using System.Runtime.InteropServices 调用方法: 一.静态加载 用DllImprot方式来加载c++DLL.如下格式: //对应c++方法 //voi ...

  3. QT 调用 DLL 方法(三种方法)

    Qt调用DLL方法一:使用Win32 API 在显式链接下,应用程序必须进行函数 调用以在运行时显式加载 DLL.为显式链接到 DLL,应用程序必须:? 调用 LoadLibrary(或相似的函 数) ...

  4. VC2008如何生成及使用DLL(图文并茂,完整版)

    博客分类: Dot net VC2008 DLL Dot net   生成.使用DLL看起来简单,但做起来才发现还是有一些地方需要注意的. 1. 打开VS2008,新建一个VC工程,选择Win32类型 ...

  5. C#调用Matlab生成的dll方法

    其实整个过程比较简单,但是需要心细一点. 需要的工具:VS2005及以上版本,MATLAB2008B及以上版本,另外非常重要的需要安装一个MATLAB Compiler Runtime,这个文件(MC ...

  6. C# 调用 C++ DLL方法

    在C# 中,可以通过 DllImport 调用C++ 的非托管DLL程序. VS2010中C#调用C++的DLL示例: 一.新建C++ DLL程序 1.新建 C++ Win32项目,类型为DLL. 生 ...

  7. python调用dll方法

    在python中调用dll文件中的接口比较简单,实例代码如下: 如我们有一个test.dll文件,内部定义如下: extern "C"{ int __stdcall test( v ...

  8. Delphi 调用C# 编写的DLL方法

    近来,因工作需要,必须解决Delphi写的主程序调用C#写的dll的问题.在网上一番搜索,又经过种种试验,最终证明有以下两种方法可行:    编写C#dll的方法都一样,首先在vs2005中创建一个“ ...

  9. C++调用DLL方法

    调用的原理: 调用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同.Windows提供了两种将DLL映像到进程地址空间的方法:隐式 ...

随机推荐

  1. 传智播客C/C++学院年薪24-50万招聘C/C++讲师

    C/C++技术讲师 6名 (北京,年薪:24-50万) 传智播客C/C++课程培训体系如下: 1.C语言,世界五百强C语言面试训练 2.C++语言,世界五百强C++语言面试训练 3.数据结构与算法,世 ...

  2. HDU 5972 Regular Number(ShiftAnd+读入优化)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5972 [题目大意] 给出一个字符串,找出其中所有的符合特定模式的子串位置,符合特定模式是指,该子串 ...

  3. 织梦DEDECMS 首页列表页内容也时间日期调用标签

    DEDECMS利用strftime()函数格式化时间的所有参数详解,包括年份日期进制.小时格式等,大家收藏吧,呵. 日期时间格式 (利用strftime()函数格式化时间)0 dedecms首页时间标 ...

  4. C - 字符识别?

    C - 字符识别? Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Submit Sta ...

  5. ROS服务的理解

    服务是节点之间通信的另一种方式,服务允许节点发起一个请求和接收一个响应. 打开终端在里面输入: roscore 查看当前的运行节点: rosnode list 返回结果: /rosout 查看当前的运 ...

  6. xhprof failed to execute cmd: " dot -Tpng". stderr: `sh: dot: command not found '

    wget http://www.graphviz.org/pub/graphviz/ARCHIVE/graphviz-2.28.0.tar.gz tar xzvf graphviz-2.28.0.ta ...

  7. Cortex-M3动态加载三(模块调用系统函数)

    在我的arm动态加载实验中需要解决一个模块调用系统函数的问题,可以使用以下的一个方法.将系统函数固定在某一段地址空间,然后导出这一块的符号表到符号文件中,要记载的模块link的时候使用这个符号表文件, ...

  8. ubuntu中查找软件的安装位置

    ubuntu中的软件可通过图形界面的软件中心安装,也可以通过命令行apt-get install安装.但是安装后的软件在哪个位置呢?这点跟windows环境下安装软件的路径选择不一样.ubuntu中可 ...

  9. html字符实体对照表

  10. 5_Navigation Bar

    5 // // ViewController.swift // Navigation Bar // // Created by ZC on 16/1/9. // Copyright © 2016年 Z ...