简体   繁体   中英

Return byte array from C++ DLL to C#

I'm implementing a C++ DLL that needs to read/write data to the serial line. The usage of this DLL is in a C# application. Currently I can't manage to read data from the C# application while i'm using the C++ read code (without the C# wrapper the read function works properly).

C++ code:

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

C# Code

[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);

After running those line i keeps getting the System.AccessViolationException . How can I solve this issue?

Remark: I can't use the C# Serial class. My C++ serial function works well.

The uart.Read(void *Buffer, unsigned int MaxNbBytes, unsigned int TimeOut_ms) reference:

\\Buffer : array of bytes read from the serial device
\\MaxNbBytes : maximum allowed number of bytes read
\\TimeOut_ms : delay of timeout before giving up the reading

The mistake is your use of the out keyword. That would be used if you needed the callee to allocate a new array and return it to you. That is an extra level of indirection.

So you can use the following p/invoke:

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

Call it like this:

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

Note that byte is blittable, and so byte[] is blittable. This means that the framework will simply pin your array. Consequently it marshals as [In,Out ]. If you wanted to be more explicit about the intent you could write:

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

But the behaviour would not be any different. The array will still be pinned and semantically the argument will be [In,Out] .

I also removed the needless CharSet specification and changed the other two arguments to uint to match unsigned int . Of course, using uint may introduce extra casts that you may find irksome. You would likely be forgiven for sticking to int in the p/invoke declaration for the sake of convenience.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM