如何将struct从C#传递给C ++ DLL?

时间:2018-05-02 13:47:09

标签: c# c++ dll interop dllimport

好了我的激光设备控制器的一系列问题继续......我想从我的C#代码中调用DLL中的以下C ++函数:

extern "C" _declspec(dllimport) int SendFrame(DWORD deviceIndex, byte* pData, DWORD numOfPoints, DWORD scanrate);

指针pData指向C ++头文件中定义的激光点数组,如下所示:

#pragma pack (1)
struct LaserPoint {
    WORD x;
    WORD y;
    byte colors[6];
};

在C#端,我按如下方式定义了函数import:

[DllImport("..\\..\\dll\\StclDevices.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int SendFrame(UInt32 deviceIndex, ref byte[] pData, UInt32 numOfPoints, UInt32 scanrate);

...和这样的LaserPoint结构:

[StructLayout(LayoutKind.Sequential, Pack=1)]
public struct LaserPoint {
    public UInt16 x;
    public UInt16 y;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
    public byte[] colors;
}

然后我像这样调用SendFrame函数:

LaserPoint point = new LaserPoint();
point.x = 16384;
point.y = 32768;
point.colors = new byte[] {255, 0, 0, 0, 0, 0};

byte[] arr = point2array(points);
SendFrame(0, ref arr, 1, 30000);

这是我将LaserPoint struct实例转换为字节数组的函数:

private static byte[] point2array(object obj) {
    int len = Marshal.SizeOf(obj);
    byte[] arr = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(obj, ptr, true);
    Marshal.Copy(ptr, arr, 0, len);
    Marshal.FreeHGlobal(ptr);
    return arr;
}

但是我的激光设备没有接收到正确的输入,因为激光表现得非常奇怪。在C ++项目中使用相同的代码可以正常工作。所以这个bug就在这个C#互操作性代码的某个地方。

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

数组已经是引用类型,因此ref byte[]是双重间接,类似于byte** - 丢失ref

答案 1 :(得分:1)

如果您只打算在此处使用LaserPoint结构,则可以将该函数定义为

presenter.present((state as Load<T>).presentable) 

摆脱复制,让运行时为你做这件事。

否则正如ildjarn所说,摆脱ref应该有效,因为字节数组已经是引用(指针)类型。

有关如何执行此操作的示例,PInvoke wiki已获得大多数Windows API的结构和签名,因此虽然您的呼叫不会存在,但有许多类似的示例。< / p>