如何编组c#中的集合以传递给本机(C ++)代码

我正在进行企业应用程序开发。 整个应用程序是用c ++开发的,除了用c#开发的用户界面,现在是用c ++代码连接用户界面的时候了。 经过详细研究,我选择PInvoke才能这样做。 一切都很成功,我遇到的唯一情况就是如何将集合传递给C ++代码。 例如:

C#侧码

List lst = new List(); lst.Add("1"); lst.Add("2"); lst.Add("3"); lst.Add("4"); 

C ++边码

 std::vector vStr; 

现在我如何将lst传递给本机C ++代码

正如mzabsky所提到的,你不能编组这些类型。 但是,您可以编组数组:

理论上的C ++导出:

 extern "C" __declspec(dllexport) void __stdcall Foo(wchar_t const* const* values, int length) { // Check argument validity... // If you really need a vector std::vector vStr(values, values + length); //... } 

P / Invoke签名:

 [DllImport("foo.dll")] static extern void Foo([MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPWStr)] string[] values, int length); 

来自C#的电话:

 Foo(lst.ToArray(), lst.Count); 

请注意,我在这里使用std :: wstring; 你可以使用char而不是wchar_t,LPStr而不是LPWStr,而std :: string而不是std :: wstring。

请注意,这将从列表中分配一个数组,然后向量将复制数组的内容。 如果原始列表的大小很小,那么这应该是可以忽略不计的。

编辑:修复标记(<和>)。

你不能这样做,只能编组C类型。 您将不得不编写C ++ / CLI包装器(或围绕C ++向量的C包装器)。

看到这个答案。

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

在C#中包装std::vector确实可以使用常规的P / Invoke Interop,但它很复杂。 甚至任何类型的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工具的作者)