简体   繁体   English

从C ++到C#的二进制/十六进制数据的编组/ DLL导入

[英]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: 我有一个C ++头文件,该文件使我可以访问两个函数,这些函数在切掉不必要的内容之后是:

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. _data和_receiveBuffer参数应该是二进制信息,而不是char *最初建议的字符串。

The reference C++ implementation I have would use the functions like this: 我拥有的参考C ++实现将使用如下功能:

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. 考虑到这一点,我试图得到的结果是byte []二进制数组。 This works well in most cases. 在大多数情况下,此方法效果很好。 However, I have byte arrays with "0" bytes right in the middle. 但是,我在中间有个字节数组,字节数为“ 0”。 With the StringBuilder this will result in me only getting the first part of the array. 使用StringBuilder,这将导致我仅获得数组的第一部分。 How would I be able to reliably get the entire binary array/blob? 我如何能够可靠地获取整个二进制数组/ 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: 编辑:这就是我在C#方法中使用它的方式,通常我可以从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: 因此,C#看起来像这样:

[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. 注意,由于我们已经切换到字节数组,因此不需要CharSet There are no text parameters. 没有文字参数。 And note also that SetLastError is for use with functions that call the SetLastError Windows API function. 还要注意, SetLastError与调用SetLastError Windows API函数的函数一起使用。 I see no evidence that yours does so. 我没有证据表明您这样做。 Your function returns a C++ bool and so we marshal it as UnmanagedType.I1 . 您的函数返回一个C ++ bool ,因此我们将其UnmanagedType.I1UnmanagedType.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. 大概是ref传递了长度,以允许该函数告诉调用方实际复制了多少字节。

Either you can use IntPtr instead of char* _receiveBuffer and search the memory pointer then for the string blocks terminated by a NULL terminator. 您可以使用IntPtr代替char* _receiveBuffer并搜索内存指针,然后查找由NULL终止符终止的字符串块。 Or you could try it with char[] as type for _receiveBuffer and walk through the array of chars. 或者,您可以使用char[]作为_receiveBuffer类型尝试它,并遍历char数组。

Walking through the memory when using IntPtr would be something like: 使用IntPtr时在内存中穿行将类似于:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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