简体   繁体   中英

Marshalling/DllImport of Binary/Hex Data from C++ to C#

I have a C++ Header File that gives me access to two functions that, after cutting stuff that is not necessary, are this:

extern __declspec (dllimport) bool __cdecl GetBinary(unsigned short* _allocatedBufferSizeBufferLength, char* _receiveBuffer);

The _data and _receiveBuffer parameters are supposed to be binary information, not the strings as char* would initially suggest.

The reference C++ implementation I have would use the functions like this:

char output;
unsigned short allocatedBufferLength = 1;
GetBinary(&allocatedBufferLength,&output);

My Import Declaration for these two right now looks like this:

[DllImport( "MyDriver.dll", EntryPoint = "GetBinary", CharSet = CharSet.Ansi, SetLastError = true, CallingConvention = CallingConvention.Cdecl )]
public static extern bool GetBinary( out ushort allocatedBufferSizeBufferLength, StringBuilder receiveBuffer );

With this in mind, what I try to get as a result are byte[] binary arrays. This works well in most cases. However, I have byte arrays with "0" bytes right in the middle. With the StringBuilder this will result in me only getting the first part of the array. How would I be able to reliably get the entire binary array/blob?

Edit: This is how I use it in my C# Method, normally I can extract the binary data from the string inside the StringBuilder:

StringBuilder outVar = new StringBuilder( 30 );
allocatedBufferLength = (ushort)(outVar.Length - 1);
UnsafeNativeMethods.GetBinary( out allocatedBufferLength, outVar );

The protocol for this function appears to be that the caller allocates the buffer, and passes the length of the allocated buffer to the function by reference. I assume that the function modifies the length on return to contain the number of bytes copied.

You want to change the signature to return a byte array so that you can deal with text that contains null characters. So the C# would look like this:

[DllImport("MyDriver.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.I1)]
public static extern bool GetBinary(
    ref ushort allocatedBufferSizeBufferLength, 
    [In, Out] byte[] receiveBuffer
);

Note that there is no need for CharSet since we have switched to a byte array. There are no text parameters. And note also that SetLastError is for use with functions that call the SetLastError Windows API function. I see no evidence that yours does so. Your function returns a C++ bool and so we marshal it as UnmanagedType.I1 .

To call the function we must allocate a byte array for the function to populate. For instance:

ushort len = 256;
byte[] buffer = new byte[len];
bool retval = GetBinary(ref len, buffer);
if (!retval)
    // handle error
// process buffer

Presumably the length is passed by ref to allow the function to tell the caller how many bytes were actually copied.

Either you can use IntPtr instead of char* _receiveBuffer and search the memory pointer then for the string blocks terminated by a NULL terminator. Or you could try it with char[] as type for _receiveBuffer and walk through the array of chars.

Walking through the memory when using IntPtr would be something like:

        for (var i = 0; i < _allocatedBufferSizeBufferLength; i++)
        {
            var b = Marshal.ReadByte(ptr, i);
            // do something here with the byte just read
        }

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