当结构包含数组时如何为结构分配GCHandle?

时间:2018-06-22 09:00:41

标签: c# dllimport

我有一个结构:

public struct ResultOfStrategy
{
    ......
    public double[] param;
    public IntPtr ptr;
}

我将此结构放入DLL中,有必要在该结构中返回数组的值

result = new ResultOfStrategy[(int)length];

for(int i = 0; i < (int)length; i++)
{
    result[i].param = new double[10];
}

// try... finally trick to be sure that the code isn't interrupted by asynchronous exceptions
try
{

}
finally
{
    handle = GCHandle.Alloc(result, GCHandleType.Pinned);
}

return handle.AddrOfPinnedObject();

我得到一个错误-该对象包含的数据不是原始数据或需要转换的数据。如何解决此问题?

P.s。我想从C#中以C ++形式传递一个结构数组,其中将包含普通变量和1个类型为double的数组。

1 个答案:

答案 0 :(得分:0)

我不完全知道您想做什么,但是,只有一件事:您无法轻松固定ResultOfStrategy结构。因此,您必须创建该struct ...

的副本
public struct ResultOfStrategy
{
    public IntPtr ptr;
    public double[] param;
}

public struct ResultOfStrategyImpl
{
    public IntPtr ptr;
    public IntPtr param;
}

public static IntPtr Test(int length, out GCHandle[] handlesToBeFreed)
{
    var result = new ResultOfStrategy[(int)length];

    for (int i = 0; i < (int)length; i++)
    {
        result[i].param = new double[10];
    }

    // Copy to new blittable object
    var result2 = new ResultOfStrategyImpl[result.Length];

    for (int i = 0; i < result.Length; i++)
    {
        result2[i].ptr = result[i].ptr;
    }

    handlesToBeFreed = new GCHandle[length + 1];

    GCHandle handle;

    // try... finally trick to be sure that the code isn't interrupted by asynchronous exceptions
    try
    {
    }
    finally
    {
        for (int i = 0; i < result.Length; i++)
        {
            handle = GCHandle.Alloc(result2[i], GCHandleType.Pinned);
            handlesToBeFreed[i] = handle;
            result2[i].param = handle.AddrOfPinnedObject();
        }

        handle = GCHandle.Alloc(result2, GCHandleType.Pinned);
        handlesToBeFreed[result.Length] = handle;
    }

    return handle.AddrOfPinnedObject();
}

public static void FreeHandles(GCHandle[] handles)
{
    if (handles != null)
    {
        for (int i = 0; i < handles.Length; i++)
        {
            handles[i].Free();
        }
    }
}

使用方式:

GCHandle[] handlesToBeFreed = null;

try
{
    IntPtr ptr = Test(10, out handlesToBeFreed);

    // Work with ptr
}
finally
{
    FreeHandles(handlesToBeFreed);
}