Search Unity

C++ Native plugin, data marshalling always 0

Discussion in 'Editor & General Support' started by RyuMaster, Nov 1, 2016.

  1. RyuMaster

    RyuMaster

    Joined:
    Sep 13, 2010
    Posts:
    468
    Can not figure out, where is the problem for a whole day now.

    On the C++ side, I have this:
    Code (csharp):
    1.  
    2.     double* s;
    3.         bool GetLeftOutputData(double ** a, int * i)
    4.         {
    5.             s = new double[4]{ 25,24.0,33.0,57.0 };
    6.             *a = s;
    7.             *i = 4;
    8.             return true;
    9.         }
    10.  
    And on the C# side, I have:
    Code (csharp):
    1.  
    2.     [DllImport("MyDLL")]
    3.     private static extern bool GetLeftOutputData(out IntPtr ptrResultVerts, out int resultVertLength);
    4.  
    5.      void TestLeftOutputData()
    6.     {
    7.         IntPtr ptrNativeData;
    8.         int itemsLength;
    9.  
    10.         bool success = GetLeftOutputData(out ptrNativeData, out itemsLength);
    11.         if (!success)
    12.         {
    13.         Debug.Log("Faild to get left out data");
    14.         return;
    15.         }
    16.  
    17.         double[] SArray = new double[itemsLength];  // Where the final data will be stored.
    18.  
    19.         Debug.Log("Length: " + itemsLength);
    20.  
    21.         IntPtr p = ptrNativeData;
    22.         for (int i = 0; i < itemsLength; i++)
    23.         {
    24.             Marshal.PtrToStructure(p, SArray[i]);
    25.             p = new IntPtr(p.ToInt64() + Marshal.SizeOf(typeof(double)));
    26.         }
    27.     }
    28.  
    29.  
    Code gives no error, but for some reason, double[] array is always filled with 0, i.e. no data is being copied. Where is my mistake? ArrayLength proprly comes as 4, and loop is being run 4 times.
     
  2. larku

    larku

    Joined:
    Mar 14, 2013
    Posts:
    1,422
    You're not quite doing it right. You can't allocate the memory on the c++ side like you have (this will also create a memory leak doing a new there).

    The general idea is :

    For example (from head so likely won't compile):

    Code (CSharp):
    1. [DllImport ("MyDLL")]
    2. public static extern UInt32 getDataItemCount ();
    3.      
    4. [DllImport ("MyDLL")]
    5. public static extern void GetLeftOutputData ([In, Out] double[] data);
    6.  
    7. void TestLeftOutputData()
    8. {
    9.     UInt32 count = getDataItemCount();
    10.     double[] data = new double[count];
    11.     GetLeftOutputData(data);
    12. }
    The c code should look like:

    Code (csharp):
    1. extern "C" uint32_t getDataItemCount()
    2. {
    3.   return 4;
    4. }
    5.  
    6. extern "C" void GetLeftOutputData(double *data)
    7. {
    8.   data[0] = 25.0;
    9.   data[1] = 4.0;,
    10.   data[2] = 33.0;
    11.   data[3] = 57.0;
    12.  
    13. //
    14. // Or you can use memcpy() to copy the data into '*data'
    15. // or loop over your source data and copy each element, etc
    16. //
    17. }
    If you don't want to have to know the size of data prior then you'll need to pass a buffer that's large enough and pass back the number of elements used.

    Again, this is from my head so there could be errors, omissions and oversights, but it should give you the general idea.
     
  3. RyuMaster

    RyuMaster

    Joined:
    Sep 13, 2010
    Posts:
    468
    I see! Thank you, will try it this way