在C++中创建一个可以被C#调用的动态库,并包含类对象

在C++中创建动态库(DLL),并在C#中调用该库,特别是当动态库包含类对象时,涉及到几个关键步骤和技术。这里我将详细介绍整个过程,包括如何在C++中创建类,编译为DLL,以及如何在C#中调用这些DLL。

1.在C++中创建一个类,并编写导出函数以允许C#创建和使用该类的实例。
2.使用extern "C"确保函数名不会在编译时被改变。
3.使用__declspec(dllexport)来标记导出函数。
4.在C#中使用DllImport属性来导入动态库中的函数。****

第一步:在C++中创建类并编写DLL

假设有一个C++类,比如MyClass,需要从C#中调用它。首先,你需要在C++中定义这个类,并确保它可以被C#调用。由于C#无法直接调用C++的类(因为C#是面向对象的,但C++ DLL的接口通常基于C风格),你需要通过C接口暴露函数。

MyClass.h

#ifdef MYCLASSLIBRARY_EXPORTS  
#define MYCLASS_API __declspec(dllexport)  
#else  
#define MYCLASS_API __declspec(dllimport)  
#endif  
  
class MyClass {  
public:  
    MyClass();  
    ~MyClass();  
    void DoSomething();  
};  
  
extern "C" {  
    MYCLASS_API MyClass* CreateMyClass();  
    MYCLASS_API void DeleteMyClass(MyClass* instance);  
    MYCLASS_API void MyClass_DoSomething(MyClass* instance);  
}

MyClass.cpp

#include "MyClass.h"  
  
MyClass::MyClass() {  
    // 构造函数实现  
}  
  
MyClass::~MyClass() {  
    // 析构函数实现  
}  
  
void MyClass::DoSomething() {  
    // 方法实现  
}  
  
extern "C" {  
    MYCLASS_API MyClass* CreateMyClass() {  
        return new MyClass();  
    }  
  
    MYCLASS_API void DeleteMyClass(MyClass* instance) {  
        delete instance;  
    }  
  
    MYCLASS_API void MyClass_DoSomething(MyClass* instance) {  
        instance->DoSomething();  
    }  
}

注意:
· 使用extern "C"来避免C++的名称修饰(name mangling),这样C#就可以更容易地通过P/Invoke调用这些函数。

· 定义了MYCLASS_API宏,根据是否定义MYCLASSLIBRARY_EXPORTS来切换为dllexport或dllimport。

· 在C++代码中,CreateMyClass函数创建MyClass的实例,并返回一个指向它的指针。MyClass_DoSomething函数接受一个void*指针,并调用对象的DoSomething方法。DeleteMyClass函数释放分配的内存。

第二步:编译DLL

确保在编译DLL时定义了MYCLASSLIBRARY_EXPORTS。这通常在项目设置中设置,或者通过命令行参数传递。

第三步:在C#中调用DLL

在C#代码中,DllImport属性用来导入C++动态库中的函数,并使用IntPtr类型来处理对象指针。Main方法创建对象,使用它,然后释放内存。

方式1

// Caller.cs
using System;
using System.Runtime.InteropServices;
 
class Program {
    [DllImport("MyLibrary.dll")]
    private static extern IntPtr CreateMyClass();
 
    [DllImport("MyLibrary.dll")]
    private static extern void MyClass_DoSomething(IntPtr obj);
 
    [DllImport("MyLibrary.dll")]
    private static extern void DeleteMyClass(IntPtr obj);
 
    static void Main() {
        IntPtr obj = CreateMyClass();
        MyClass_DoSomething(obj);
        DeleteMyClass(obj);
    }
}

方式2

using System;  
using System.Runtime.InteropServices;  
  
class Program  
{  
    [DllImport("MyClassLibrary.dll", CallingConvention = CallingConvention.Cdecl)]  
    private static extern IntPtr CreateMyClass();  
  
    [DllImport("MyClassLibrary.dll", CallingConvention = CallingConvention.Cdecl)]  
    private static extern void DeleteMyClass(IntPtr instance);  
  
    [DllImport("MyClassLibrary.dll", CallingConvention = CallingConvention.Cdecl)]  
    private static extern void MyClass_DoSomething(IntPtr instance);  
  
    class MyClassWrapper  
    {  
        public IntPtr Instance { get; private set; }  
  
        public MyClassWrapper()  
        {  
            Instance = CreateMyClass();  
        }  
  
        ~MyClassWrapper()  
        {  
            DeleteMyClass(Instance);  
        }  
  
        public void DoSomething()  
        {  
            MyClass_DoSomething(Instance);  
        }  
    }  
  
    static void Main(string[] args)  
    {  
        MyClassWrapper wrapper = new MyClassWrapper();  
        wrapper.DoSomething();  
    }  
}


注意:

· 使用IntPtr来持有C++对象的引用。
· 确保在C#中正确管理C++对象的生命周期,避免内存泄漏。
· 这样,你就可以在C#中通过封装类来安全地调用C++ DLL中的类和方法了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值