将struct数组指针从c#传递给c ++

时间:2018-02-23 15:57:56

标签: c# c++

我有来自第三方的c ++ dll,我无法修改。 我已经制作了一个c ++包装器来调用c ++ dll中的函数。 该包装器是从带有IJW的C#类调用的。

它适用于本机类型,但我遇到了结构数组问题。

这是c ++包装类:

int Helper::GetCameras(cameraStruct * cameraArray, size_t * size)
    {
        return originalC++Dll_getCameraList(cameraArray, size);
    }

C#致电:

var ret = m_Helper.GetCameras(pointer, size);

我是否需要在c#中重新定义“cameraStruct”?

   [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
   public class aivusdk_cameraInfo
     {
      public int blabla;
     }

要像在C#函数中使用指针一样使用它,或者它是另一种方式(编组),还是我完全错了?

请原谅我糟糕的英语,感谢您的回复。

2 个答案:

答案 0 :(得分:2)

使用IJW的主要原因是避免使用StructLayout尝试在C#代码中定义并行结构并调用Marshal类中的所有内容时的所有麻烦。如果你要解决这个问题,你也可以使用P / Invoke来做所有事情。

一种方法是在C#程序集中定义一个将由c ++ / clr程序集实现的接口,以及一个包含与cameraStruct结构的有趣字段对应的属性的托管类。

public interface IHelper
{
    public void GetCameras(IList<Camera> cameras);
    public Picture TakePicture(Camera camera);
    public void LoseCamera(Camera camera);
}

public class Camera
{
    public string Name { get; set; }
    public int BlaBla { get; set; }
}

c ++ / clr程序集中的Helper类将实现IHelper接口。 GetCameras方法的实现将使用本地分配的cameraStruct数组调用originalDLL_getCameraList。然后它将遍历返回的摄像机并为每个摄像机gcnew一个Camera对象。它会将信息从cameraStruct复制到Camera对象,然后将Camera对象添加到摄像机列表中。然后可以释放本地分配的cameraStruct数组。

一个问题是c ++ / clr项目必须具有对C#项目的构建依赖性(引用)。 C#项目不能引用c ++ / clr项目。要获取Helper对象的C#代码,可以从C#程序集动态加载c ++ / clr程序集,并使用反射创建一个将其强制转换为IHelper的Helper对象。

你可以改变这种关系,但这意味着在c ++ / clr中定义更多,在C#中定义更少。 (例如,您需要在c ++ / clr程序集中定义Camera类。)我更喜欢在实际使用C#定义内容。

答案 1 :(得分:0)

您需要为可以传递给API的数组分配非托管内存。

我就是这样做的:

// the input here is a managed C# array
public IntPtr AllocateNativeArray(CameraInfo[] myArray)
{
    if (myArray == null || myArray.Count == 0)
        return IntPtr.Zero;

    // building native structures
    var nativeArray = new Aivusdk_CameraInfo[myArray.Length];
    for (int i = 0; i < myArray.Length; i++)
    {
        // TODO: fill properties
    }

    // allocating unmanaged memory and marshaling elements
    int elementSize = Marshal.SizeOf(typeof(Aivusdk_CameraInfo));
    IntPtr result = Marshal.AllocHGlobal(nativeArray.Length * elementSize);
    for (int i = 0; i < nativeArray.Length; i++)
    {
        Marshal.StructureToPtr(nativeArray[i], new IntPtr((long)result + i * elementSize), false);
    }

    return result;
}

在调用C ++ API之后,您可能需要释放该数组(除非C ++部分执行此操作):

private static void FreeNativeArray(IntPtr address, uint length)
{
    if (address== IntPtr.Zero)
        return;

    int elementSize = Marshal.SizeOf(typeof(Aivusdk_CameraInfo));
    for (int i = 0; i < count; i++)
    {
        Marshal.DestroyStructure(new IntPtr((long)address + i * elementSize), typeof(Aivusdk_CameraInfo));
    }

    Marshal.FreeHGlobal(address);
}