Marshal a C struct containing a variable length array

前端 未结 2 1357
执念已碎
执念已碎 2020-12-20 16:09

I would like to marshal a C struct with a variable-length array back to C# but so far I can\'t get anything better than a pointer-to-struct representation and a pointer to f

相关标签:
2条回答
  • 2020-12-20 16:29

    short answer you can't marshal variable length array as an array , because Without knowing the size, the interop marshalling service cannot marshal the array elements

    but if you know the size it will be like below:

    int arr[15]
    

    you will be able to marshal it like this:

    [MarshalAs(UnmanagedType.LPArray, SizeConst=15)] int[] arr
    

    if you don't know the length of the array and this is what you want you can convert it to intprt and deal with inptr but first you need to create 2 structs

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct fvec_t1
    {
        public uint whatever;
    
        public int[] data;
    }
    

    the other one like below:

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct fvec_t2{
        public uint whatever;
    }
    

    create a function to initialize the array like below

    private static int[] ReturnIntArray()
    {
        int [] myInt = new int[30];
    
        for (int i = 0; i < myInt.length; i++)
        {
            myInt[i] = i + 1;
        }
    
        return myInt;
    }
    

    instantiate the first struct

    fvec_t1 instance = new fvec_t1();
    instance.whatever=10;
    instance.data= ReturnIntArray();
    

    instantiate the second struct

    fvec_t2 instance1 = new fvec_t2();
    
    instance1.whatever = instance.whatever
    

    dynamically allocate space for fvec_t2 struct with extended space for data array

    IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(fvec_t2)) + Instance.data.Length);
    

    Transfer the existing field values of fvec_t2 to memory space pointed to by ptr

    Marshal.StructureToPtr(instance1, ptr, true);
    

    Calculate the offset of data array field which should be at the end of an fvec_t2 struct

    int offset = Marshal.SizeOf(typeof(fvec_t2));
    

    get memory address of data array field based on the offset.

    IntPtr address = new IntPtr(ptr.ToInt32() + offset);
    

    copy data to ptr

    Marshal.Copy(instance.data, 0, address, instance.data.Length);
    

    do the call

    bool success = dllfunction(ptr);
    
    Marshal.FreeHGlobal(ptr);
    ptr = IntPtr.Zero;
    
    0 讨论(0)
  • 2020-12-20 16:35

    In the above case I'd definitely use the SizeParamIndex.

    [StructLayout(LayoutKind.Sequential)]
    public struct fvec_t1
    {
        uint length;
        [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] float[] data;
    }
    

    Good luck.

    0 讨论(0)
提交回复
热议问题