如何将vector 从C ++ dll编组到C#应用程序?

我有一个C ++函数,它产生一个有趣的矩形列表。 我希望能够从C ++库中获取该列表并返回到调用它的C#应用​​程序。

到目前为止,我正在编码矩形,如下所示:

struct ImagePatch{ int xmin, xmax, ymin, ymax; } 

然后编码一些向量:

 void MyFunc(..., std::vector& rectanglePoints){ std::vector patches; //this is filled with rectangles for(i = 0; i < patches.size(); i++){ rectanglePoints.push_back(patches[i].xmin); rectanglePoints.push_back(patches[i].xmax); rectanglePoints.push_back(patches[i].ymin); rectanglePoints.push_back(patches[i].ymax); } } 

用于与C#交互的标题看起来像(并且适用于许多其他函数):

 extern "C" { __declspec(dllexport) void __cdecl MyFunc(..., std::vector& rectanglePoints); } 

是否有一些关键字或其他我可以做的东西来取出那组矩形? 我发现这篇文章是用于在C#中编组对象,但它看起来太复杂了,太过于缺乏解释。 整数向量是正确的方法,还是有其他技巧或方法?

STL是一个特定于C ++的库,因此您无法直接将其作为一个对象传递给C#。

关于std :: vector的一件事是,&v [0]指向第一个元素,所有元素在内存中线性排列(换句话说,它就像内存布局方面的C数组一样)

所以作为int数组编组…这应该不难 – 网上有很多例子。

添加

假设您只将数据从C ++传递给C#:

C#无法处理C ++向量对象,所以不要尝试通过引用传递它:而是你的C ++代码必须返回一个指向int数组的指针…

如果您不打算从多个线程使用此函数,则可以使用静态存储:

 int *getRects(bool bClear) { static vector v; // This variable persists across invocations if(bClear) { v.swap(vector()); } else { v.clear(); // Fill v with data as you wish } return v.size() ? &v[0] : NULL; } 

如果返回的数据大小很大,则调用getRects(true),因此在v中释放内存。

为简单起见,不要传递矢量数据的大小,只需在末尾添加一个sentinel值(比如说-1),这样C#代码就可以检测数据的结束位置。

我很确定你不能这样做。 您必须能够将C ++代码直接转换为C#类,因此您至少必须复制vector类的内部以正确编组它。 我也很确定你无法跨越边界移动引用,你必须使用IntPtr(原始指针)。 我所知道的方法是对一组原始结构进行编组。

是。 您可以。 实际上,不仅仅是std::vectorstd::stringstd::wstring ,任何标准C ++类或您自己的类都可以编组或实例化并从C#/ .NET调用。

在C#中包装std::vector确实可以使用常规的P / Invoke Interop,但它很复杂。 甚至任何类型的std::map都可以在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="DestructorOfYourClass", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.ThisCall)] public extern static void SampleClassDestructor(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() { if (this.ptr != IntPtr.Zero) { // The following 2 calls equals to "delete object" in C++ // Calling the destructor of the C++ class will free the memory allocated by the native c++ class. SampleClassDestructor(this.ptr); // Free the memory allocated from .NET. Marshal.FreeHGlobal(this.ptr); this.ptr = IntPtr.Zero; } } } 

请参阅以下链接,

C#/。NET PInvoke Interop SDK

(我是SDK工具的作者)

一旦准备好了C ++类的C#包装类,就可以很容易地实现ICustomMarshaler这样就可以从.NET编组C ++对象了。

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx