简体   繁体   English

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

[英]Passing struct array pointer from c# to c++

I have a c++ dll from a third party, I can't modify. 我有来自第三方的c ++ dll,我无法修改。 I've made a c++ wrapper to call the functions inside that c++ dll. 我已经制作了一个c ++包装器来调用c ++ dll中的函数。 That wrapper is called from a C# class with IJW. 该包装器是从带有IJW的C#类调用的。

It works well with natives types, but I ran into a struct array problem. 它适用于本机类型,但我遇到了一个struct array问题。

This is the c++ wrapper class : 这是c ++包装类:

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

And the C# call : 而C#调用:

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

Do I need to redefine the "cameraStruct" in c# like this ? 我是否需要在c#中重新定义“cameraStruct”?

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

To use it like with a pointer in the C# function, or is it another way of doing it (mashalling), or am I completly wrong ? 要像在C#函数中使用指针一样使用它,还是以另一种方式(编组),或者我是完全错误的?

Forgive my bad english and thanks for your response. 原谅我的英语不好,谢谢你的回复。

The primary reason to use IJW is to avoid all the hassle of trying to define parallel structures in your C# code using StructLayout and calling all that stuff in the Marshal class. 使用IJW的主要原因是避免使用StructLayout尝试在C#代码中定义并行结构并调用Marshal类中的所有内容时的所有麻烦。 If you are going to go to that trouble, you may as well do everything using P/Invoke. 如果你要解决这个问题,你也可以使用P / Invoke做所有事情。

One approach would be to define, in your C# assembly, an interface that will be implemented by the c++/clr assembly and a managed class containing properties corresponding to the interesting fields of the cameraStruct structure. 一种方法是在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; }
}

The Helper class in your c++/clr assembly would implement the IHelper interface. c ++ / clr程序集中的Helper类将实现IHelper接口。 The implementation of the GetCameras method would call originalDLL_getCameraList with a locally allocated array of cameraStruct. GetCameras方法的实现将使用本地分配的cameraStruct数组调用originalDLL_getCameraList。 It would then iterate over the returned cameras and gcnew a Camera object for each one. 然后它将遍历返回的摄像机并为每个摄像机gcnew一个Camera对象。 It would copy the information from the cameraStruct to the Camera object and then add the Camera object to the cameras list. 它会将信息从cameraStruct复制到Camera对象,然后将Camera对象添加到摄像机列表中。 The locally allocated cameraStruct array can then be freed. 然后可以释放本地分配的cameraStruct数组。

One issue is that the c++/clr project must have a build dependency (reference) to the C# project. 一个问题是c ++ / clr项目必须具有对C#项目的构建依赖性(引用)。 The C# project cannot have a reference to the c++/clr project. C#项目不能引用c ++ / clr项目。 For your C# code to get a Helper object, you could dynamically load the c++/clr assembly from the C# assembly and use reflection to create a Helper object that you cast to an IHelper. 要获取Helper对象的C#代码,可以从C#程序集动态加载c ++ / clr程序集,并使用反射创建一个将其强制转换为IHelper的Helper对象。

You can turn that relationship around, but that means defining more in c++/clr and less in C#. 你可以改变这种关系,但这意味着在c ++ / clr中定义更多,在C#中定义更少。 (For example, you would need to define the Camera class in the c++/clr assembly.) I prefer to define things using C# when practical. (例如,您需要在c ++ / clr程序集中定义Camera类。)我更喜欢在实际使用C#定义内容。

You need to allocate unmanaged memory for the array that you can pass to the API. 您需要为可以传递给API的阵列分配非托管内存。

This is how I would do that: 我就是这样做的:

// 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;
}

After calling the C++ API you might need to free the array (unless the C++ part does that): 在调用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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM