如何在托管C#和非托管C ++代码之间来回传递数组内容

问题描述

我正在尝试将浮点数数组从C#传递到C ++ dll,该函数将对该数组进行一些工作,然后以浮点数数组的形式(不一定长度相同)返回答案。

我有将通过该数组,对其进行修改然后返回的代码,但是该数组中的值与预期不符,尽管该数组看上去格式正确。 下面的示例采用一个浮点数组,并将其传递给C ++。在C ++中,将2的值添加到数组的每个元素以模拟完成的工作,并使用回调将结果返回给C#。
每次都会返回一组不同的值。
典型的一组返回值是: 81.58881,2,75.75787,4

任何想法都会被感激。.
干杯
格雷厄姆

C#

public delegate void CallBack1(IntPtr param,int len);
[DllImport("TestDll.dll",CallingConvention = CallingConvention.Cdecl)]
public static extern void testCPlusSide(CallBack1 cb,IntPtr arr,int len);

private void button_Click(object sender,EventArgs e)
{
    float[] dataIn = new float[] { 0,0.5f,7.79f,46 };
    GCHandle gch = GCHandle.Alloc(dataIn);

    CallBack1 testCB = new CallBack1(TestCallBack);

    testCPlusSide(testCB,GCHandle.ToIntPtr(gch),dataIn.Length);

    gch.Free();
}

void TestCallBack(IntPtr param,int len)
{
    float[] vals = new float[len];
    GCHandle gch = GCHandle.FromIntPtr(param);
    Marshal.copy(param,vals,len);
    StringBuilder sb = new StringBuilder();
    foreach (float item in vals)
    {
        sb.Append(item.ToString() + "\n");
    }
    MessageBox.Show(sb.ToString());
}

C ++

typedef void(__stdcall * CallBack1)(float * arr,int len);
__declspec(dllexport) void testCPlusSide(CallBack1 cb,float* arr,int len)
{
    for (int i = 0; i < len; i++)
    {
        arr[i] += 2;
    }
    cb(arr,len);
}

更新
添加一个临时float来在C ++端读取数组的内容,但我发现C ++数组的内容与传递的值没有任何关系-我不知道为什么....

解决方法

我设法使事情顺利进行。
我更改了GCHandle.Alloc方法,使之成为了固定对象指针,并且一切正常。
我还删除了TestCallBackFunction中不必要的GCHandle调用 更改后的完整代码为:-

C#

public delegate void CallBack1(IntPtr param,int len);
[DllImport("TestDll.dll",CallingConvention = CallingConvention.Cdecl)]  

public static extern void testCPlusSide(CallBack1 cb,IntPtr arr,int len);
    
private void button_Click(object sender,EventArgs e)
{
    float[] dataIn = new float[] { 0,0.5f,7.79f,46 };
    GCHandle gch = GCHandle.Alloc(dataIn,GCHandleType.Pinned);

    CallBack1 testCB = new CallBack1(TestCallBack);

    testCPlusSide(testCB,gch.AddrOfPinnedObject(),dataIn.Length);
    
    gch.Free();
}
    
void TestCallBack(IntPtr param,int len)
{
    float[] vals = new float[len];
    Marshal.Copy(param,vals,len);
    StringBuilder sb = new StringBuilder();
    foreach (float item in vals)
    {
        sb.Append(item.ToString() + "\n");
    }
    MessageBox.Show(sb.ToString());
}

C ++

typedef void(__stdcall * CallBack1)(float * arr,int len);

__declspec(dllexport) void testCPlusSide(CallBack1 cb,float* arr,int len)
{
    for (int i = 0; i < len; i++)
    {
        arr[i] += 2;
    }
    cb(arr,len);
}

感谢卡洛斯和修士的帮助
干杯
格雷厄姆