Как маршалировать указатель на массив указателей на структуры? - PullRequest
11 голосов
/ 27 марта 2010

У меня есть функция C со следующей подписью:

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

players - указатель на массив указателей на struct player объектов. n - количество указателей в массиве. Функция не изменяет массив или содержимое структур и не сохраняет никаких указателей после возврата.

Я попробовал следующее:

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

Однако это маршаллизирует данные как указатель на массив структур, а не указатель на массив указателей на структуры.

1 Ответ

11 голосов
/ 03 апреля 2010

Полагаю, вам придется выполнить маршалинг вручную. Объявление функции должно выглядеть так:

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

Нам нужно выделить некоторую собственную память и упорядочить структуры перед тем, как передать ее в собственную функцию:

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);
    }
}

Если ваша нативная функция будет удерживать и повторно использовать эти области памяти, это не сработает. Если это так, либо задержите освобождение памяти, пока вы не решите, что она больше не используется, либо в нативном методе скопируйте переданные данные и дайте управляемой стороне очистить память сразу после вызова.

...