在C#调用C++的DLL方法(二)生成托管的DLL
写操作之前,还是扼要的说一下托管与非托管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的更多相关文章
- eclipse 中main()函数中的String[] args如何使用?通过String[] args验证账号密码的登录类?静态的主方法怎样才能调用非static的方法——通过生成对象?在类中制作一个方法——能够修改对象的属性值?
eclipse 中main()函数中的String[] args如何使用? 右击你的项目,选择run as中选择 run configuration,选择arguments总的program argu ...
- c# 调用c++DLL方法及注意事项
引用命名空间 using System.Runtime.InteropServices 调用方法: 一.静态加载 用DllImprot方式来加载c++DLL.如下格式: //对应c++方法 //voi ...
- QT 调用 DLL 方法(三种方法)
Qt调用DLL方法一:使用Win32 API 在显式链接下,应用程序必须进行函数 调用以在运行时显式加载 DLL.为显式链接到 DLL,应用程序必须:? 调用 LoadLibrary(或相似的函 数) ...
- VC2008如何生成及使用DLL(图文并茂,完整版)
博客分类: Dot net VC2008 DLL Dot net 生成.使用DLL看起来简单,但做起来才发现还是有一些地方需要注意的. 1. 打开VS2008,新建一个VC工程,选择Win32类型 ...
- C#调用Matlab生成的dll方法
其实整个过程比较简单,但是需要心细一点. 需要的工具:VS2005及以上版本,MATLAB2008B及以上版本,另外非常重要的需要安装一个MATLAB Compiler Runtime,这个文件(MC ...
- C# 调用 C++ DLL方法
在C# 中,可以通过 DllImport 调用C++ 的非托管DLL程序. VS2010中C#调用C++的DLL示例: 一.新建C++ DLL程序 1.新建 C++ Win32项目,类型为DLL. 生 ...
- python调用dll方法
在python中调用dll文件中的接口比较简单,实例代码如下: 如我们有一个test.dll文件,内部定义如下: extern "C"{ int __stdcall test( v ...
- Delphi 调用C# 编写的DLL方法
近来,因工作需要,必须解决Delphi写的主程序调用C#写的dll的问题.在网上一番搜索,又经过种种试验,最终证明有以下两种方法可行: 编写C#dll的方法都一样,首先在vs2005中创建一个“ ...
- C++调用DLL方法
调用的原理: 调用DLL,首先需要将DLL文件映像到用户进程的地址空间中,然后才能进行函数调用,这个函数和进程内部一般函数的调用方法相同.Windows提供了两种将DLL映像到进程地址空间的方法:隐式 ...
随机推荐
- Android 模拟系统事件(三)
简介 Android系统是基于Linux内核的,而Linux内核继承和兼容了丰富的Unix系统进程间通信(IPC)机制.Binder其实也不是Android提出来的一套新的进程间通信机制,它是基于Op ...
- 面向对象程序设计-C++_课时24多态的实现
所有带virtual的类的对象,里面最上面有一个隐藏的指针vptr,指向一张表vtable #include <iostream> using namespace std; class A ...
- 【MongoDB数据库】MongoDB 命令入门初探
MongoDB是一款NoSql数据库,使用了"面向集合"(Collection-Oriented)原理,意思是数据被分组存储在数据集中,被称为一个集合(Collection).每一 ...
- 奔五的人,准备学习iOS开发
这些年一直在java/web/android方面折腾,去年最终换成了apple的设备,本想就開始折腾iOS,却始终没能进入状态. 从今天開始,本人宣布:正式进入iOS/xcode 5的编程学习中,也希 ...
- spring NotWritablePropertyException异常
Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property 'userDao' of bea ...
- 编码神器 Sublime Text 包管理工具及扩展大全
Sublime Text 是程序员们公认的编码神奇,拥有漂亮的用户界面和强大的功能,例如代码缩略图,多重选择,快捷命令等.还可自定义键绑定,菜单和工具栏.Sublime Text 的主要功能包括:拼写 ...
- 【Java并发编程】并发编程大合集-值得收藏
http://blog.csdn.net/ns_code/article/details/17539599这个博主的关于java并发编程系列很不错,值得收藏. 为了方便各位网友学习以及方便自己复习之用 ...
- jQuery获取Select选择的Text(非表单元素)和 Value(表单元素)(转)
jQuery获取Select选择的Text和Value: 语法解释: . $("#select_id").change(function(){//code...}); //为Sel ...
- NSURLSessionConfiguration的简单实用
NSURLSessionConfiguration 基于前面学习了NSURLSession的知识,这边文章就讲下NSURLSessionConfiguration相关应用,(这名字可真长). 简而言之 ...
- Csharp多态的实现(虚方法)
1.什么是抽象类 1.1虚方法是用virtual修饰,在子类中用override进行重写 1.2虚方法是一个方法,放在类里面(可以再下面的代码中看到) 1.3虚方法可以 重写,也可以不重写(这个可以再 ...