How to correctly marshal this C struct with pointer to array and pointer to pointer members in C# for use with 3rd party dll?
C:
typedef struct SomeStruct {
uint8_t *data[8];
int size[8];
uint8_t **extended_data;
};
Is it all just IntPtr
and then you need to allocate the un-mamaged memory, copy data into it, and pin it? How would you do this if it's the case? The struct gets initialized through a function inside dll.
In python this is how I'd wrap and use this struct:
Python:
class SomeStruct(Structure):
_fields_ = [
('data', POINTER(c_uint8) * 8),
('size', c_int * 8),
('extended_data', POINTER(POINTER(c_uint8)))
]
# example use 1
dll = ctypes.CDLL("lib.dll")
some_struct = SomeStruct()
dll.init_struct(ctypes.byref(some_struct))
# or example 2
alloc_struct_fce = dll.alloc_struct
alloc_struct_fce.restype = ctypes.POINTER(SomeStruct) # specify return type
some_struct_ptr = alloc_struct_fce() # this gets passed to other dll functions
dll.some_processing(some_struct_ptr)
some_struct = some_struct_ptr.contents # dereference the pointer
Trying to find a C# equivalent of this code.
extended_data
is a bonus if you know how to deal with it, it's dynamic size and I am not sure how I'd get its size.
A real example would be
The.dll provides methods to allocate and free these structures.
Given your struct, we could:
struct SomeStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public IntPtr[] data;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] size;
public IntPtr extended_data;
}
// I don't know the calling convention of your C method... You didn't show
// us its signature. It could be cdecl or stdcall
[DllImport(@"somedll.dll", CallingConvention = CallingConvention.Cdecl /* or StdCall */)]
public static extern void SomeStructMethod(out SomeStruct someStruct);
Then:
SomeStruct someStruct;
SomeStructMethod(out someStruct);
for (int i = 0; i < someStruct.data.Length; i++)
{
var array = new byte[someStruct.size[i]];
Marshal.Copy(someStruct.data[i], array, 0, array.Length);
Console.Write("> ");
for (int j = 0; j < array.Length; j++)
{
Console.Write($"{array[j]} ");
}
Console.WriteLine();
}
Note that at the end you should call some C method to free the memory allocated in someStruct
otherwise you'll have a memory leak!
I can't help you about extended_data
, because you haven't told us what it should be,
I woul use following code which is based on xanatos code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
class Program
{
[DllImport(@"somedll.dll", CallingConvention = CallingConvention.Cdecl /* or StdCall */)]
public static extern void SomeStructMethod(out SomeStruct someStruct);
static void Main(string[] args)
{
SomeStruct someStruct;
SomeStructMethod(out someStruct);
byte[] data = new byte[8];
Marshal.Copy(someStruct.data, data, 0, 8);
byte[][] extendedData = new byte[8][];
for(int i = 0; i < 8; i++)
{
extendedData[i] = new byte[someStruct.size[i]];
Marshal.Copy(someStruct.extended_data[i], extendedData[i], 0, someStruct.size[i]);
}
}
}
struct SomeStruct
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public IntPtr data;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public int[] size;
public IntPtr[] extended_data;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.