从 C# 导入C++类方法
本文关键字:类方法 C++ 导入 | 更新日期: 2023-09-27 17:56:18
我可以通过以下方式从 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上导入。
假设方法是静态的,您有以下几种选择:
- 使用依赖关系查看器等工具查找导入函数的名称。使用
DllImport
的EntryPoint
参数进行定位。 - 使用 .def 文件导出函数。然后,您可以完全控制导出的名称。
- 将方法包装在非成员函数中并将其导出。
坦率地说,选项 3 是我会选择的选项。
当您使用成员函数时,您需要导出接受实例指针作为其第一个参数的函数。而且您可能必须导出实例化对象的函数。
也就是说,并回应您的评论,其他可能更好的解决方案是:
- 早期绑定 COM,或
- 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 运行时组件"的示例代码。