从 C++ dll 编组导出的字符串向量
Posted
技术标签:
【中文标题】从 C++ dll 编组导出的字符串向量【英文标题】:Marshaling exported string vector from C++ dll 【发布时间】:2011-10-25 01:36:30 【问题描述】:如何编组从 C++ dll 导出的字符串向量?我希望在我的 C# 程序中使用它们之前将它们分开。你能帮帮我吗?
【问题讨论】:
不能,C++ 对象不能直接在 C# 程序中使用。它们甚至不能在用不同编译器编译的另一个 C++ 程序中使用。 C++ 没有二进制标准。您需要使用 C++/CLI 语言编写的胶水代码来转换它们。一种知道如何编译本机 C++ 和托管代码的语言。 或者你可以导出一个使用char*
数组而不是向量的函数。
这里的问题类似:***.com/questions/5102436/…
@Hans C# 有MarshallAsAttribute
...
@ColeJohnson:很多结构都可以——至少 C++11 有一些关于所谓的“标准布局”结构的规则,这使得编组和编组更简单一些。使用结构/类的内容。但是,为了应用这些规则,您必须避免使类变得有用的许多因素,而不仅仅是原始数据的分组。如果您的类型使用virtual
,具有引用类型或非标准布局类型字段,在继承链中的多个类中定义了成员,或者具有与其他字段不同的访问控制,那么您就是回到 IB 领域(或更糟)。
【参考方案1】:
是的。你可以。实际上,不仅仅是std::vector
、std::string
、std::wstring
,任何标准的 C++ 类或您自己的类都可以被编组或实例化并从 C#/.NET 调用。
在 C# 中包装 std::vector<any_type>
确实可以使用常规 P/Invoke 互操作,但它很复杂。甚至任何类型的 std::map 都可以在 C#/.NET 中完成。
从 .NET 世界中实例化 C++ 对象的基本思想是从 .NET 中分配 C++ 对象的确切大小,然后调用从 C++ DLL 导出的构造函数来初始化对象,然后您就可以调用任何函数来访问该 C++ 对象,如果任何方法涉及其他 C++ 类,您还需要将它们包装在 C# 类中,对于具有原始类型的方法,您可以简单地 P/Invoke 它们。如果你只有几个方法可以调用,那会很简单,手动编码不会花很长时间。完成 C++ 对象后,调用 C++ 对象的析构函数方法,这也是一个导出函数。如果它没有,那么你只需要从 .NET 中释放你的内存。
这是一个例子。
public class SampleClass : IDisposable
[DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void SampleClassConstructor(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject);
[DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)]
public extern static void DoSomething(IntPtr thisObject, int x);
IntPtr ptr;
public SampleClass(int sizeOfYourCppClass)
this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass);
SampleClassConstructor(this.ptr);
public void DoSomething()
DoSomething(this.ptr);
public void DoSomethingElse(int x)
DoSomethingElse(this.ptr, x);
public void Dispose()
Marshal.FreeHGlobal(this.ptr);
详情请看以下链接,
C#/.NET PInvoke Interop SDK
(我是SDK工具的作者)
【讨论】:
如果您担心那些“根本不知道该怎么做” 的人的反对意见,那么您应该提供一个示例。如果你不解释怎么做,那么你就没有回答问题 非常感谢。我将举一个简单的例子来说明如何做到这一点。 刚刚添加了一个简单的例子。谢谢! 几个问题: (1) 编译器不需要导出使对象有用的成员函数;在构建 DLL 时,您必须以某种方式告诉它导出它们。如果 DLL 是第三方库……嗯。你被它提供的任何 API 困住了。 (2) C和C++的调用约定不一样,尤其是调用成员函数的时候。只是它们如何不同,是特定于实现的。有些人希望*cx
中的 this
,有些人可能希望它在堆栈上,等等。如果您的 DLL 是用 VS 编写的,这可能会起作用。还有其他编译器吗?嗯。
感谢您的评论。对于(1),不是这样,如果是模板类,所有实现都在头文件里面,即使没有在原始C++ DLL中导出,如果是C++类的实现,仍然可以在补充中导出在 CPP 文件中并且类没有被导出,即使从 C 或 C++ 中也无法正常访问它,对吧?对于 (2),这就是调用约定发挥作用的地方,您需要使用正确的调用约定来装饰 P/Invoke,它不仅适用于 C++ 函数,C 风格的函数也需要它。以上是关于从 C++ dll 编组导出的字符串向量的主要内容,如果未能解决你的问题,请参考以下文章