我有来自第三方的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#函数中使用指针一样使用它,或者它是另一种方式(编组),还是我完全错了?
请原谅我糟糕的英语,感谢您的回复。
答案 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);
}