我正在实现一个需要向串行线读/写数据的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:放弃阅读前的超时延迟
答案 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
。