C# Wrap C++ 项目中遇到Unity(C#)层调用C++实现的算法,下面记录实现方法 1. 简单接口-传入struct C++实现接口: #define JNAAPI extern "C" __declspec(dllexport) // C方式导出函数 //传递的实际的struct struct CCtest { int id; int x; }; //nLen 传入的可写大小 //return: 实际的写入的数目 JNAAPI int getValue(CCtest * test, int nLen); int gloabl_id = 10; //全局变量,测试结果:常驻内存 // 实际的实现 int getValue(CCtest * test, int nLen) { int tag_num = 5; tag_num = tag_num > nLen ? nLen : tag_num; for (int i = 0; i < tag_num; i++) { test[i].id = gloabl_id; test[i].x = 100; gloabl_id++; } return tag_num; } C#的调用: // 需定义完全对应于C++的struct [StructLayout(LayoutKind.Sequential)] public struct CCtest { public int id; public int x; } // 将上述C++编译成dll后放到C#工程,命名为getValue.dll // EntryPoint是函数名称 [DllImport("getValue.dll", EntryPoint = "getValue")] public static extern int getValue(IntPtr p, int nLen); static void Main(string[] args) { // 调用中,先分配了10个的长度 IntPtr pt = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CCtest)) * 10); int tag_num = getValue(pt, 10); for (int i = 0; i < tag_num; i++) { CCtest res = new CCtest(); res = (CCtest)Marshal.PtrToStructure( // 按照偏移量取C++返回的struct (IntPtr)(pt.ToInt64() + i * Marshal.SizeOf(typeof(CCtest))), typeof(CCtest)); Console.WriteLine("{0} {1}\n", res.id, res.x); } Marshal.FreeHGlobal(pt); } 2. 复杂接口-传入二维数组 上述的实现是在C#中分配内存,给C++中写。 若C#事先不知道会返回struct的数目,将分配空间的任务交给C++,则需要传递二维指针: JNAAPI int getValue(CCtest** tags) { if (!tags) return 0; m.lock(); size_t size = results.size(); if (size > 0) { *tags = new CCtest[size]; // 需要另外的函数releaseTags delete tags std::copy(results.begin(), results.end(), *tags); } m.unlock(); return size; } // release memory created in getTags防止内存泄漏 JNAAPI void releaseTags(CCtest* tags) { delete tags; } C#的调用: [DllImport("apriltag.dll")] private static extern int getValue(out IntPtr p); // C#函数调用上述接口 public static List<CCtest> getValue() { IntPtr arrayValue; var size = getValue(out arrayValue); // out代表二维指针 var list = new List<CCtest>(); if (size <= 0) return list; var ptr = arrayValue; var structSize = Marshal.SizeOf(typeof(CCtest)); for (var i = 0; i < size; i++) { var cur = (CCtest)Marshal.PtrToStructure(ptr, typeof(CCtest)); list.Add(cur); ptr = new IntPtr(ptr.ToInt64() + structSize); // 往后便宜指针 } releaseTags(arrayValue); // 释放C++中的内存 return list; } 3. 其他-return bool 若C++中返回bool类型,由于其为1byte,而C#默认接受的是4byte,因此会始终返回true,解决: [DllImport("a.dll")] [return: MarshalAs(UnmanagedType.I1)] // 指示返回的是1byte,以便正确解析 public static extern bool start();