Reputation: 243
I'm primarily a C# dev (not much C++ since college), but working on integrating a large collection of existing C++ code into an application. I have a C++/CLI assembly that is buffering the two worlds and have communication from C# through to C++ working fine. The question I have, is that the C++ class has a method call that generates a binary blob (think array of byte
s in C# world) that I need to get in C# and process (pass around like a solid bag).
What I'm looking for is advice on how to handle the buffer/wrapper method (C++/CLI) between the two worlds. I assumed that I'd pass a char*
and length, but C# sees that as a byte*
(I'm assuming that is some C++/CLI "magic").
I also tried passing array<Byte ^>^
but that haven't had much luck translating the char*
from the rest of the C++ lib to the byte
array... and what I have doesn't smell right.
Upvotes: 1
Views: 3377
Reputation: 393467
You can use an UnmanagedMemoryStream, like so:
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();
The reverse route, roughly:
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);
I'm sure that MSDN will have more resources
Upvotes: 3
Reputation: 134491
I took a shot at it and came up with this. Nothing crazy, just allocate the managed array, copy the data and return it.
header:
#pragma once
using namespace System;
using namespace System::Runtime::InteropServices;
namespace CLRLib
{
public ref class TwiddlerFunctions
{
public:
static array< Byte >^ GetArray();
};
}
implementation:
#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# side:
using System;
using CLRLib;
class Program
{
static void Main(string[] args)
{
byte[] arr = TwiddlerFunctions.GetArray();
Console.WriteLine(String.Join(" ", arr)); // 1 2 34 5
}
}
Upvotes: 2
Reputation: 62985
Have the C++/CLI code hand off a System::IO::UnmanagedMemoryStream
to the C# code, which can then use a System.IO.BinaryReader
on said stream to extract data as needed.
As an aside, C++/CLI's char
is synonymous with C#'s sbyte
, C++/CLI's unsigned char
is synonymous with C#'s byte
, C++/CLI's wchar_t
is synonymous with C#'s char
, and C++/CLI's array<unsigned char>^
is synonymous with C#'s byte[]
. Note that it's array<unsigned char>^
or array<System::Byte>^
rather than array<unsigned char^>^
or array<System::Byte^>^
, as System.Byte
is a value type rather than a ref type.
Upvotes: 3