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

时间:2014-05-28 10:40:38

标签: c# c++ pinvoke dllimport

我有一个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);

我对这两者的进口声明现在看起来像这样:

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

2 个答案:

答案 0 :(得分:1)

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

您希望更改签名以返回字节数组,以便您可以处理包含空字符的文本。所以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传递,以允许函数告诉调用者实际复制了多少字节。

答案 1 :(得分:-1)

您可以使用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
        }