我如何编组一个指向指针数组结构?数组、指针、结构

2023-09-03 16:04:35 作者:人心易碎i

我有以下签名的C函数:

I have a C function with the following signature:

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

播放器是一个指向数组的指针,以结构球员的对象。 N 是数组中指针的个数。该函数不修改数组,也不是结构的内容,并返回后,不保留任何指针。

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.

我试过如下:

[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.

推荐答案

我相信你将不得不做一些手工的封送处理。函数的声明应该是这样的:

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.