将字节数组从C ++ DLL返回到C#

时间:2018-03-15 08:24:59

标签: c# c++ dllimport dllexport

我正在实现一个需要向串行线读/写数据的C ++ DLL。 此DLL的用法是在C#应用程序中。 目前,当我使用C ++读取代码时,我无法从C#应用程序中读取数据(没有C#包装器,读取功能正常工作)。

C ++代码:

extern "C" __declspec(dllexport) int Read(void *Buffer, unsigned int MaxNbBytes, unsigned int TimeOut_ms)
{
    return uart.Read(Buffer, MaxNbBytes, TimeOut_ms);
}

C#代码

[DllImport("RS232LIB.dll", CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern int Read(out byte[] bytesRead, int maxNbBytes, int timeOutMs);

var bytes = new byte[4];
Read(out bytes, 4, 10);

运行这些线后,我不断获得System.AccessViolationException。 我该如何解决这个问题?

备注:我不能使用C#Serial类。我的C ++串口功能运行良好。

uart.Read(void *Buffer, unsigned int MaxNbBytes, unsigned int TimeOut_ms)参考:

  

\ Buffer:从串行设备读取的字节数组
  \ MaxNbBytes:允许的最大字节数   \ TimeOut_ms:放弃阅读前的超时延迟

1 个答案:

答案 0 :(得分:5)

错误是您使用out关键字。如果您需要被调用者分配一个新数组并将其返回给您,那么将使用它。这是一个额外的间接层面。

所以你可以使用下面的p / invoke:

[DllImport("RS232LIB.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Read(byte[] bytesRead, uint maxNbBytes, uint timeOutMs);

这样称呼:

var bytes = new byte[4];
Read(bytes, (uint)bytes.Length, timeOutMs);

请注意,byte是blittable,因此byte[]是blittable。这意味着框架将简单地固定您的阵列。因此它整理为[In,Out]。如果你想更清楚你可以写的意图:

[DllImport("RS232LIB.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern int Read([Out] byte[] bytesRead, uint maxNbBytes, uint timeOutMs);

但这种行为不会有任何不同。该数组仍将固定,语义上该参数将为[In,Out]

我还删除了不必要的CharSet规范,并将其他两个参数更改为uint以匹配unsigned int。当然,使用uint可能会引入额外的演员阵容,这些演员阵容可能会令人厌烦。为方便起见,您可能会原谅在p / invoke声明中坚持int