如何将二进制blob从C ++传递给C#?

时间:2011-05-18 21:03:08

标签: c#-4.0 interop c++-cli

我主要是一个C#dev(自大学以来没有多少C ++),但我正致力于将大量现有C ++代码集成到应用程序中。我有一个C ++ / CLI程序集正在缓冲这两个世界,并且从C#到C ++的通信工作正常。我的问题是,C ++类有一个方法调用,它生成一个二进制blob(想想在C#世界中byte的数组),我需要在C#中进行处理(像一个固体包一样传递) 。

我正在寻找的是如何在两个世界之间处理缓冲区/包装器方法(C ++ / CLI)的建议。我假设我传递char*和长度,但C#将其视为byte*(我假设这是一些C ++ / CLI“魔术”)。

我也试过传递array<Byte ^>^,但是没有太多运气将char*从C ++ lib的其余部分转换为byte数组......以及我所拥有的内容闻起来不错。

3 个答案:

答案 0 :(得分:3)

让C ++ / CLI代码将System::IO::UnmanagedMemoryStream移交给C#代码,然后可以在所述流上使用System.IO.BinaryReader来根据需要提取数据。

顺便说一句,C ++ / CLI的char与C#的sbyte是同义词,C ++ / CLI的unsigned char与C#的byte同义,C ++ / CLI的wchar_t }是C#的char的同义词,而C ++ / CLI的array<unsigned char>^与C#的byte[]同义。请注意,它是array<unsigned char>^array<System::Byte>^而非array<unsigned char^>^array<System::Byte^>^,因为System.Byte是值类型而非ref类型。

答案 1 :(得分:3)

您可以使用UnmanagedMemoryStream,如下所示:

byte[] message = UnicodeEncoding.Unicode.GetBytes("Here is some data.");
IntPtr memIntPtr = Marshal.AllocHGlobal(message.Length);
byte* memBytePtr = (byte*) memIntPtr.ToPointer();

UnmanagedMemoryStream writeStream = new UnmanagedMemoryStream(memBytePtr, message.Length, message.Length, FileAccess.Write);

writeStream.Write(message, 0, message.Length);
writeStream.Close();

反向路线,粗略地说:

UnmanagedMemoryStream readStream = new UnmanagedMemoryStream(memBytePtr, message.Length, message.Length, FileAccess.Read);

byte[] outMessage = new byte[message.Length];
readStream.Read(outMessage, 0, message.Length);
readStream.Close();

// Convert back into string for this example
string converted = UnicodeEncoding.Unicode.GetString(outMessage);

Marshal.FreeHGlobal(memIntPtr);

我确信MSDN会有更多资源

答案 2 :(得分:2)

我拍了一下它并想出了这个。没什么了不起的,只需分配托管数组,复制数据并将其返回。

头:

#pragma once
using namespace System;
using namespace System::Runtime::InteropServices;
namespace CLRLib
{
    public ref class TwiddlerFunctions
    {
    public:
        static array< Byte >^ GetArray();
    };
}

实现:

#include "CLRLib.h"
array< Byte >^ CLRLib::TwiddlerFunctions::GetArray()
{
    unsigned char data[] = { 1, 2, 34, 5 };
    // convert the unmanaged array to a managed array
    array< Byte >^ arr = gcnew array< Byte >(sizeof data);
    Marshal::Copy((IntPtr)data, arr, 0, arr->Length);
    return arr;
}

C#方:

using System;
using CLRLib;
class Program
{
    static void Main(string[] args)
    {
        byte[] arr = TwiddlerFunctions.GetArray();
        Console.WriteLine(String.Join(" ", arr)); // 1 2 34 5
    }
}