从c++到c#的二进制/十六进制数据的编组/输出

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

本文关键字:数据 输出 十六进制 二进制 c++      更新时间:2023-10-16

我有一个c++头文件,它让我可以访问两个函数,在删除不必要的东西之后,是:

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

_data和_receiveBuffer参数应该是二进制信息,而不是char*最初建议的字符串。

我的c++参考实现将使用这样的函数:

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

这两个的Import声明现在看起来像这样:

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

考虑到这一点,我试图得到的结果是byte[]二进制数组。这在大多数情况下都很有效。然而,我有一个字节数组,中间是"0"字节。使用StringBuilder,这将导致我只获得数组的第一部分。我如何能够可靠地得到整个二进制数组/blob?

编辑:这就是我如何在我的c#方法中使用它,通常我可以从StringBuilder内的字符串中提取二进制数据:

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

这个函数的协议似乎是调用者分配缓冲区,并通过引用将分配的缓冲区的长度传递给函数。我假设函数修改返回值的长度以包含复制的字节数。

您希望将签名更改为返回一个字节数组,以便可以处理包含空字符的文本。所以c#看起来像这样:

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

请注意,由于我们已经切换到字节数组,因此不需要CharSet。没有文本参数。还要注意,SetLastError是用于调用SetLastError Windows API函数的函数。我看不出有任何证据表明你是这样做的。您的函数返回c++ bool,因此我们将其封送为UnmanagedType.I1

要调用函数,必须分配一个字节数组供函数填充。例如:

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

这个长度可能是由ref传递的,以允许函数告诉调用者实际复制了多少字节。

您可以使用IntPtr代替char* _receiveBuffer,然后在内存指针中搜索由NULL终止符终止的字符串块。或者您可以尝试使用char[]作为_receiveBuffer的类型,并遍历字符数组。

在使用IntPtr时遍历内存,类似于:

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