将struct从非托管C++传递到C#

mko*_*rek 9 c# c++ unmanaged

注意:最终的工作解决方案是在编辑之后!

我希望有人可以帮我解决过去几天我一直试图解决的问题.

我试图将结构从非托管C++ DLL传递给C#脚本.这是我到目前为止:

C++

EXPORT_API uchar *detectMarkers(...) {
    struct markerStruct {
            int id;
    } MarkerInfo;

    uchar *bytePtr = (uchar*) &MarkerInfo;

    ...

    MarkerInfo.id = 3;
    return bytePtr;
}
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

问题是,这是有效的,但打印的值完全关闭(有时它打印大约400,有时最大int值).

我猜我在C#中编组结构的方式有问题.有任何想法吗?

编辑:

这是使用ref的工作解决方案:

C++

struct markerStruct {
    int id;
};

...

EXPORT_API void detectMarkers( ... , markerStruct *MarkerInfo) {
    MarkerInfo->id = 3;
    return;
}
Run Code Online (Sandbox Code Playgroud)

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 );
Run Code Online (Sandbox Code Playgroud)

Ben*_*igt 6

您将返回一个指向本地变量的指针,该变量在.NET可以读取之前已经被销毁.这在纯C++中是一个坏主意,而p/invoke是个坏主意.

相反,让C#传递一个指向结构的指针(只需使用ref关键字),C++代码就可以填充它.