代码之家  ›  专栏  ›  技术社区  ›  gr1d3r

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

  •  3
  • gr1d3r  · 技术社区  · 6 年前

    我正在实现一个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) 参考号:

    \缓冲区:从串行设备读取的字节数组
    \MaxNbBytes:允许读取的最大字节数
    \TimeOut\u ms:放弃读取之前的超时延迟

    1 回复  |  直到 6 年前
        1
  •  6
  •   David Heffernan    6 年前

    错误在于您使用 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 是可飞行的,等等 byte[] 是可飞行的。这意味着该框架将简单地固定您的阵列。因此,它编组为 [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 。当然,使用 无符号整型 可能会引入额外的演员阵容,您可能会感到厌烦。你可能会因为坚持而被原谅 int 为了方便起见,在p/invoke声明中。