如何在c#中使用DLL创建结构数组(用C编写)

本文关键字:数组 结构 编写 创建 DLL | 更新日期: 2023-09-27 18:12:36

我想用数据填充一个结构,这样我就可以把它传递给我的DLL函数。c#和C实现中的结构是相似的。例如(在C中):

typedef struct{
    apple[] apples;
    leaf[] leaves;
} tree;
typedef struct{
    int taste;
} apple;
typedef struct{
    int color;
} leaf;

我想在c#上创建一个树形结构,用苹果和树叶填充它,然后将它发送给我在DLL上的函数。

如何?

如何在c#中使用DLL创建结构数组(用C编写)

首先,我认为你应该稍微改变一下C结构体:

typedef struct{
    UINT cApples;
    const apple *pApples;
    UINT cLeaves;
    const leaf *pLeaves;
} tree;

c#端:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct Tree
{
    internal uint cApples;
    internal IntPtr pApples;
    internal uint cLeaves;
    internal IntPtr pLeaves;
}

您可以类似地定义LeafApple。然后你可以在c#端像这样填充它们:

private Tree CreateTree(Leaf[] leaves, Apple[] apples)
{
    var result = new Tree();
    result.cLeaves = (uint)leaves.Length;
    result.cApples = (uint)apples.Length;
    result.pLeaves = AllocateNativeMemory(leaves);
    result.pApples = AllocateNativeMemory(apples);
    return result;
}
private IntPtr AllocateNativeMemory<T>(T[] elements) where T : struct
{
    int elementSize = Marshal.SizeOf(typeof(T));
    IntPtr result = Marshal.AllocHGlobal(elements.Length * elementSize);
    for (int i = 0; i < elements.Length; i++)
    {
        Marshal.StructureToPtr(
            elements[i], new IntPtr((long)result + i * elementSize), false);
    }
    return result;
}

现在你可以把CreateTree方法的结果传递给调用C端的外部方法。

备注:分配的内存应该被释放;否则,您的应用程序将泄漏。如果你决定c#端负责释放分配的内存,你应该在代码末尾这样做:

private static void FreeTree(Tree tree)
{
    FreeNativeMemory<Leaf>(tree.pLeaves, tree.cLeaves);
    FreeNativeMemory<Apple>(tree.pApples, tree.cApples);
}
private static void FreeNativeMemory<T>(IntPtr arrayPtr, uint arrayLen) where T : struct
{
    int elementSize = Marshal.SizeOf(typeof(T));
    for (uint i = 0; i < arrayLen; i++)
    {
        Marshal.DestroyStructure(new IntPtr((long)arrayPtr + i * elementSize), typeof(T));
    }
    Marshal.FreeHGlobal(arrayPtr);
}