在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 = 0;
}
NativeClass::~NativeClass(void)
{
}
int NativeClass::GetCount(void)
{
    return this->nCount;
}
void NativeClass::Increase(void)
{
    this->nCount++;
}
void NativeClass::Clear(void)
{
    this->nCount = 0;
}

非托管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,请诸位自力更生了。

时间: 2024-10-23 17:42:58

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

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

引用命名空间 using System.Runtime.InteropServices 调用方法: 一.静态加载 用DllImprot方式来加载c++DLL.如下格式: //对应c++方法 //void DogInit(WORD*,HWND) //错误返回值,窗口句柄 [DllImport("DOG.dll", EntryPoint = "DogInit", CallingConvention = CallingConvention.Cdecl)] public s

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

Qt调用DLL方法一:使用Win32 API 在显式链接下,应用程序必须进行函数 调用以在运行时显式加载 DLL.为显式链接到 DLL,应用程序必须:? 调用 LoadLibrary(或相似的函 数)以加载 DLL 和获取模块句柄.? 调用 GetProcAddress,以获 取指向应用程序要调用的每个导出函数的函数指针.由于应用程序是通过指针调用 DLL 的函数,编译器不生成外部引 用,故无需与导入库链接.? 使用完 DLL 后调用 FreeLibrary.例如:typedef UINT (C

C#调用非托管C++DLL的两种方法

C#编写的代码属于跨平台的托管代码,C++语言可以编写托管(managed)和非托管(native)代码.在C#与C++的混合编程中,经常会使用C#来调用native C++的DLL,下面有两种常用的调用方法供大家参考. 使用P/Invoke直接调用native C++ Dll里面的函数.(注:此方法只能调用函数,不能调用class). C#通过C++ CLR(托管的C++)来调用nativeC++ DLL, C++ CLR作为链接C#与native之间的纽带. 方法一的详细过程如下: (1)打

C# 调用 C++ DLL方法

在C# 中,可以通过 DllImport 调用C++ 的非托管DLL程序. VS2010中C#调用C++的DLL示例: 一.新建C++ DLL程序 1.新建 C++ Win32项目,类型为DLL. 生成的文件结构如图: 其中,“MyDLLFun.cpp”文件为此项目主要源文件. 2.在源文件中添加需要被外部调用的方法. 这里仅仅是添加两个示例方法: 方法“Add”返回两个整数的和:方法Pow计算X 的 Y 次方,并以指针的形式修改参数 x 地址处的值. 修饰符 extern "C" 包

C#如何静态调用C++中的方法(静态调用dll)

当我们想要在C#中使用C++项目的方法时,这个时候就可以通过调用C++项目的dll来实现,它有静态和动态调用两种方法. DLL(Dynamic Link Library)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型.在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中.当我们执行某一个程序时,相应的DLL文件就会被调用.一个应用程序可使用多个DLL文件,一个DLL文件也可能被不同的应用程序使用,这样的DLL文件

VC6.0编译DLL,使用VS2010调用问题及解决方法

1.做驱动的时候,做应用程序需要和驱动通信,必须建立一个DLL. 2.因为客户使用版本太低,需要使用到VC6.0编写DLL 3.在VC6.0上编写DLL的时候,导出的函数名会出现和原函数名不对,导致调用失败 4.解决办法, 找到VC6.0工程下面的文件   ***.DEF. 把里面的   LIBRARY  后面输入要导出的DLL的文件名.如: LIBRARY      "pc104dll" 在EXPORTS后面输入要导出的函数名,整个文件内容入下: LIBRARY      "

在C#调用C++的DLL方法(一)生成非托管dll

C#与C/C++相比,前者的优势在于UI,后者的优势在于算法,C++下的指针虽然恶心,若使用得当还是相当方便的,最重要的问题是,市面上很多流行的开发工具库,几乎没有不支持C++的,但全面支持C#只能说是难得.在CPU发展到今天,若说C#的执行效率跟C++相比有很大的差距,并不是那么靠谱,若非万不得已我还是宁愿用C#来写代码,调试什么的也很方便. 不得已的情况下,要在C#下使用C++的函数或类,最好的方式就是使用动态链接库(dll),至于COM什么的我是至今没弄明白其原理,也许主要是因为使用起来太

LoadRunner 调用dll方法

本文主要介绍简单DLL的编写方法及在LoadRunner中局部调用与全局调用DLL方法. 1.动态链接库的编写 在Visual C++6.0开发环境下,打开FileNewProject选项,可以选择Win32 Dynamic-Link Library建立一个空的DLL工程. DLL必须有一个入口点,这就象C语言MAIN函数一样.在Non-MFC DLL中DllMain是一个缺省的入口函数,你不需要编写自己的DLL入口函数,用这个缺省的入口函数就能使动态链接库被调用时得到正确的初始化.如果应用程序

Golang通过syscall调用windows dll方法

本用例在GO 1.4.2 上编译执行通过,直接上CODE: package main import (     "fmt"     "syscall"     "time"     "unsafe" ) const (     MB_OK                = 0x00000000     MB_OKCANCEL          = 0x00000001     MB_ABORTRETRYIGNORE  = 0x