从 C# 导入C++类方法

Import C++ Class Method from C#

本文关键字:类方法 C++ 导入      更新时间:2023-10-16

我可以通过以下方式从 C# 调用C++包装类

[DllImport("SomeDll.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void M();

我在C++代码中的位置

extern "C" { __declspec(dllexport) BSTR GroupTerm(); }
void M() { /* Do Stuff */ }

这很好用,但是由于多种原因,我想将方法M包含在类中

class SomeClass {
public: 
    void M();
}

我试过做

class SomeClass {
public:
   void __declspec(dllexport) M();
}

哪里

void __declspec(dllexport) SomeClass::M() { /* Do Stuff */ }

但是 C# 代码(使用上面声明的 C# 代码进行导入)找不到入口点并引发异常。那么我的问题是,如何将此方法导出M()[它是SomeClass的公共成员,以便与 C# 中的互操作/pinvoke 一起使用?

谢谢你的时间。

嗯,有几种方法,都有不同的快乐。

其中一个更简单的方法是为你的C++类做一个C包装器(我懒得放装饰品,你应该自己做)。

class SomeClass {
public: 
  void M();
};
void* MakeSomeClass() {return new SomeClass();}
void DestroySomeClassHandle(void* handle) { delete (SomeClass*)handle;}
void M(void* handle) { ((SomeClass*)handle)->M();}

然后像往常一样导入 C 函数。

这样做的好处是你不必做任何你目前不熟悉的事情。更多的东西(Matlab,Python等)具有类似于PInvoke的东西,所以这使得你的代码更容易跨语言使用。

缺点是这非常容易出错,并且您丢弃了很多类型安全性。

更好的方法(恕我直言)是为类制作 C++/CLI 包装器

public ref class ManageSomeClass
{
public:
  ManageSomeClass() {myclass_ = new SomeClass();}
  !ManageSomeClass() { if (myclass) {delete myclass; myclass_ = NULL;} }
  ~ManageSomeClass() { this->!ManageSomeClass(); }
  void M() { myclass_->M();}
private:
  SomeClass* myclass_;
};

我使用 SomeClass 作为指针来显示析构函数终结器,但它不需要是指针。它可能是一个完整的实例。最重要的是,这将编译成一个 .NET 类(在 dll 中),你可以将其导入到 C# 代码中。然后调用是:

//c# code
ManageSomeClass msc = new ManageSomeClass();
msc.M();

好处是可以灵活地从托管到非托管。缺点是您突然维护另一个界面。如果您有继承/多态性,您的包装器必须镜像该结构。这也是一场噩梦。

编辑:另一个缺点是你必须学习C++/CLI,这是C++的(有点)和扩展,也是(有点)一种完全不同的语言。

最后一种方法是通过COM接口。 http://msdn.microsoft.com/en-us/library/aa645736%28v=vs.71%29.aspx。可以使用在 C# 中的 C++ 中使用的相同 COM 导入调用(有一些细微差异)来实例化和调用 COM 类。但是你需要学习COM(我从来没有做过),然后以COM抱怨的方式实现你的类。但是你有一个COM界面,可以在Windows上导入。

假设方法是静态的,您有以下几种选择:

  1. 使用依赖关系查看器等工具查找导入函数的名称。使用 DllImportEntryPoint 参数进行定位。
  2. 使用 .def 文件导出函数。然后,您可以完全控制导出的名称。
  3. 将方法包装在非成员函数中并将其导出。

坦率地说,选项 3 是我会选择的选项。

当您使用成员函数时,您需要导出接受实例指针作为其第一个参数的函数。而且您可能必须导出实例化对象的函数。

也就是说,并回应您的评论,其他可能更好的解决方案是:

  1. 早期绑定 COM,或
  2. C++/CLI 包装器。

另一种方法(除了@MadScienceDreams和@DavidHeffernan所说的)是将C++代码转换为Windows运行时DLL,然后可以在C#代码中使用。有关详细信息和示例,请参阅此处:在 C++ 中创建 Windows 运行时组件

摘自链接:

文章介绍如何使用 C++ 创建 Windows 运行时组件, 这是一个可从构建的 Windows 应用商店应用调用的 DLL 通过使用 JavaScript 或 C#、Visual Basic 或 C++

通常,在对C++组件进行编码时,请使用常规C++ 库和内置类型,抽象二进制接口除外 (ABI) 边界,其中在另一个代码中将数据传入和传出代码 .winmd 包。在那里,使用 Windows 运行时类型和特殊的 Visual C++ 支持的用于创建和操作这些语法的语法 类型。此外,在可视C++代码中,使用诸如 委托和事件,以实现可从 组件,并在 JavaScript、Visual Basic 或 C# 中处理。

下面是"在C++中创建 Windows 运行时组件"的示例代码。