在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中的类和方法了。