Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I marshal a pointer to an array of pointers to structures?

I have a C function with the following signature:

int my_function(int n, struct player **players)

players is a pointer to an array of pointers to struct player objects. n is the number of pointers in the array. The function does not modify the array nor the contents of the structures, and it does not retain any pointers after returning.

I tried the following:

[DllImport("mylibary.dll")]
static extern int my_function(int n, 
    [In, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] 
     player_in []players);

However, that marshals the data as a pointer to an array of structures, not a pointer to an array of pointers to structures.

like image 632
Daniel Stutzbach Avatar asked Mar 26 '10 21:03

Daniel Stutzbach


1 Answers

I believe you'll have to do some of the marshaling manually. The function declaration should look like this:

[DllImport("mylibary.dll")]
private static extern int my_function(int n, IntPtr players);

We'll need to allocate some native memory and marshal the structures to it before passing it in to the native function:

private static void CallFunction(Player[] players)
{
    var allocatedMemory = new List<IntPtr>();

    int intPtrSize = Marshal.SizeOf(typeof(IntPtr));
    IntPtr nativeArray = Marshal.AllocHGlobal(intPtrSize * players.Length);
    for (int i = 0; i < players.Length; i++)
    {
        IntPtr nativePlayer = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Player)));
        allocatedMemory.Add(nativePlayer);
        Marshal.StructureToPtr(players[i], nativePlayer, false);

        Marshal.WriteIntPtr(nativeArray, i * intPtrSize, nativePlayer);
    }

    my_function(players.Length, nativeArray);

    Marshal.FreeHGlobal(nativeArray);

    foreach (IntPtr ptr in allocatedMemory)
    {
        Marshal.FreeHGlobal(ptr);
    }
}

If your native function is going to hold on to and re-use these memory locations, this won't work. If this is the case, either hold off on freeing the memory until you think it's not being used anymore or in the native method copy the data passed in and let the managed side clean up its memory immediately after the call.

like image 154
RandomEngy Avatar answered Oct 05 '22 23:10

RandomEngy