tags:

views:

196

answers:

2

From safe, managed code in C#, I would like to call a function in a C API that receives an array of pointers (void**).

I have the corresponding managed array of IntPtr objects, but the Marshal methods advertised in the documentation at MSDN do not seem sufficient to provide an IntPtr to an unmanaged block of memory with the correct content.

I had hoped to obtain an IntPtr with 'Marshal.AllocHGlobal' and then assign the correct content using 'Marshal.Copy', but it seems the function has not been overloaded for an array of IntPtr.

Any thoughts on the best way to do this?

Thanks in advance.

+2  A: 

The P/Invoke marshaller already does this, you don't have to help. Just declare the function argument as an array:

[DllImport("blah.dll")]
private static extern void SomeFunction(IntPtr[] array);

Just in case: although you don't have to use the unsafe keyword here, there isn't anything safe about it. The C code can easily corrupt the heap when it writes past the end of the block you allocated.

Hans Passant
+1  A: 

Pass the array as an IntPtr[], IntPtr are by default marshaled as void*. No need for unsafe.

[DllImport("containingFoo.dll")]
public static extern void foo( IntPtr[] ptr);

...

// some floats
float[] fpa = {7.2F, 2.3F, 3.3F, 4.5F, 6.5F};
// allocate unmanaged for float[] fpa and int (length of array)
IntPtr fptr = Marshal.AllocHGlobal(fpa.Length *
Marshal.SizeOf(typeof(float)));
IntPtr iptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(int)));
// set length of array
Marshal.WriteInt32(iptr, fpa.Length);
// copy the array
Marshal.Copy(fpa, 0, fptr, fpa.Length);
// strore both pointers in IntPtr[]
IntPtr[] pptr = {fptr, iptr};
// call foo passing the IntPtr[] to C
foo(pptr);

//C/C++ // note that stdcall is the default calling convention when using PInvoke!!!!

void __stdcall foo(void** data)
{
float * fa = (float*)*data; // first element points to float array
int *ip = (int*)data + 1; // pointer to next element in void array
int *pp = (int*)*ip; // get pointer to int
for (int i = 0; i < *pp ; i++)
{
printf("\t: %f\n", *fa++);
}
}
Sebastian Marcet