在C 功能执行后,使用GCHANDLE CRALSES将大型结构从C#Unity脚本传递到C DLL

Pass large arrays of structs from C# unity script to C++ dll using GCHandle crashes after C++ function execution

本文关键字:C#Unity 结构 脚本 DLL 大型 执行 功能 使用 CRALSES GCHANDLE      更新时间:2023-10-16

我想从C#Unity脚本传递一个结构数组到C 本机插件。我这样做了,我可以访问数据,但是执行C 功能后,我的应用程序崩溃了,我不确定为什么。

c#侧:

[StructLayout(LayoutKind.Sequential)]
     public struct SimpleVector3
     {
         public float Vx, Vy, Vz, Nx, Ny, Nz;
         public SimpleVector3(float x, float y, float z, float xx, float yy, float zz)
         {
             Vx = x;
             Vy = y;
             Vz = z;
             Nx = xx;
             Ny = yy;
             Nz = zz;
         }
     }
     [DllImport(DLL)]
         public static extern int getSomeInt();
     [DllImport(DLL, CallingConvention = CallingConvention.Cdecl)]
         public static extern bool PopulateVerts([In] IntPtr verts, int numOfVertices);
 void Start () {
         Vector3 sceneOrigin = Camera.main.transform.position;
         Debug.Log("SX " + sceneOrigin.x + " SY " +  sceneOrigin.y + " SZ "+  sceneOrigin.z);
         SimpleVector3[] trial = new SimpleVector3[2];
         SimpleVector3 v2 = new SimpleVector3(sceneOrigin.x, sceneOrigin.y, sceneOrigin.z, sceneOrigin.x + 10, sceneOrigin.y + 10, sceneOrigin.z + 10);
         SimpleVector3 v1 = new SimpleVector3(15,10,3,5,10,6);
         trial[0] = v1;
         trial[1] = v2;
         testing(trial);
     }
     void testing(SimpleVector3[] theList)
         {
             Debug.Log("the number is " + getSomeInt());
             GCHandle pinnedArray = GCHandle.Alloc(theList, GCHandleType.Pinned);
             IntPtr ptr = pinnedArray.AddrOfPinnedObject();
             // call function passing r
             bool x = PopulateVerts(ptr, theList.Length);
             Debug.Log("after call " + x);
             pinnedArray.Free();
         }

c 方面:

extern "C" EXPORT_API int getSomeInt()
 {
     return 42;
 }
 extern "C" EXPORT_API bool PopulateVerts(SimpleVector3* verts, int numofVert) {
     char buffer[50];
     for (int i = 0; i < numofVert; i++) {
         sprintf(buffer, "x %f , y %f , z %f n nx %f , ny %f , nz %f ", (verts->Vx), 
             (verts->Vy), (verts->Vz), (verts->Nx), (verts->Ny), (verts->Nz));
         Debug(buffer);
         if(i < (numofVert-1)){
             verts++;
         }
     }
     return true;
 }

getomeint((工作正常并返回数字,但是当它调用populatevert时,它会显示数据然后崩溃。

输出:

 the number is 42
 (Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
 CallBack : x 15.000000 , y 10.000000 , z 3.000000 
  nx 5.000000 , ny 10.000000 , nz 6.000000 
 (Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
 CallBack : x -0.011494 , y 0.069487 , z 0.090230 
  nx 9.988506 , ny 10.069487 , nz 10.090230 
 (Filename: C:/buildslave/unity/build/artifacts/generated/Metro/runtime/DebugBindings.gen.cpp Line: 51)
 The program '[2640] dllimporttrial.exe' has exited with code -1073740791 (0xc0000409).

这是在Hololens上运行的。我不确定我在做什么错,错误到底是错误的。

谢谢。

问题可能在返回类型bool中... C bool是1个字节,C#bool是4个字节。

尝试:

[DllImport(DLL, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool PopulateVerts([In] IntPtr verts, int numOfVertices);

然后 buffer的长度存在问题:

extern "C" EXPORT_API bool PopulateVerts(SimpleVector3* verts, int numofVert) {
    char buffer[250];
    for (int i = 0; i < numofVert; i++) {
        _snprintf(buffer, 250, "x %f , y %f , z %f n nx %f , ny %f , nz %f ", (verts->Vx), 
            (verts->Vy), (verts->Vz), (verts->Nx), (verts->Ny), (verts->Nz));
        // See the security note at https://msdn.microsoft.com/en-us/library/2ts7cx93(v=vs.71).aspx
        buffer[sizeof(buffer) - 1] = '';
        Debug(buffer);
        if(i < (numofVert-1)){
            verts++;
        }
    }
    return true;
}