注意:最终有效的解决方案在编辑后面!
我希望有人能够帮助我解决我已经尝试了几天的问题。
我正在尝试从一个非托管的C++ DLL传递一个结构体到一个C#脚本。目前为止,我已经完成以下内容:
C++
EXPORT_API uchar *detectMarkers(...) {
struct markerStruct {
int id;
} MarkerInfo;
uchar *bytePtr = (uchar*) &MarkerInfo;
...
MarkerInfo.id = 3;
return bytePtr;
}
C#
[DllImport ("UnmanagedDll")]
public static extern byte[] detectMarkers(...);
...
[StructLayout(LayoutKind.Explicit, Size = 16, Pack = 1)]
public struct markerStruct
{
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0)]
public int Id;
}
...
markerStruct ByteArrayToNewStuff(byte[] bytes){
GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
markerStruct stuff = (markerStruct)Marshal.PtrToStructure(
handle.AddrOfPinnedObject(), typeof(markerStruct));
handle.Free();
return stuff;
}
...
print(ByteArrayToNewStuff (detectMarkers(d, W, H, d.Length) ).Id);
问题在于这个代码可以运行,但打印的值完全偏离预期(有时打印大约为400,有时打印最大整数值)。
我猜测可能是我在C#中序列化结构体的方式有误。有什么想法吗?
编辑:
这是使用ref的可行解决方案:
C++
struct markerStruct {
int id;
};
...
EXPORT_API void detectMarkers( ... , markerStruct *MarkerInfo) {
MarkerInfo->id = 3;
return;
}
C#
[DllImport ("ArucoUnity")]
public static extern void detectMarkers( ... ,
[MarshalAs(UnmanagedType.Struct)] ref MarkerStruct markerStruct);
...
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public struct MarkerStruct
{
public int Id;
}
...
detectMarkers (d, W, H, d.Length, ref markerInfo);
print( markerInfo.Id );
ref
或out
关键字时,C#实际上会传递一个指针。因此,在C++端使用void detectMarkers( /*...*/ markerStruct* MarkerInfo)
,然后MarkerInfo->id = 3;
。另外,在p/invoke签名中去掉In
属性,这意味着不从C++获取数据,这显然与你想要的相反。 - Ben Voigt