C#调用C++ DLL简析(二)—— 生成托管dll

本文出自 “几缕萧雨锁清秋” 博客,转载自 http://joeyliu.blog.51cto.com/3647812/1297961


写操作之前,还是扼要的说一下托管与非托管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里的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#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的。我的封装代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 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,然后你就可以用了,其测试代码就几句话:

1
2
3
4
5
6
7
8
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,请诸位自力更生了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值