I need to copy native (i.e. unmanaged) data (byte*) to managed byte array with C++/CLI (array).
I tried Marshal::Copy (data is pointed to by const void* data and is
All these answers dance around the real misunderstanding in the original question.. The essential mistake made is that this code:
System::Runtime::InteropServices::Marshal::Copy(new IntPtr(data),
_Data,
0,
dataSize)
is incorrect.. you don't new (or gcnew) an IntPtr. Its a value type. One of the answers shows this, but it doesn't point out the original misunderstanding. The correct code can be expressed this way:
System::Runtime::InteropServices::Marshal::Copy(IntPtr((void *)data),
_Data,
0,
dataSize)
This confused me when I first started using these constructs also..
IntPtr is a C# struct.. a value type.
"IntPtr" is just a wrapper around a "void *". You shouldn't need the new syntax, just use of the explicit conversion operator.
System::Runtime::InteropServices::Marshal::Copy( IntPtr( ( void * ) data ), _Data, 0, dataSize );
Should work.
The C++/CLI compiler is a bit obtuse about this. The formal definition of IntPtr is "native integer", it is not a pointer type. The C++ language however only allows conversion of void* to a pointer type. The CLI supports pointer types but there are very few framework methods that accept them. Marshal::Copy() doesn't. One of the three IntPtr constructors does.
You have to whack the compiler over the head with a cast or by using the IntPtr constructor. It is anybody's guess if this will still work on a 128-bit operating system, I'm not going to worry about it for a while.
As you've noted, Marshal::Copy
(and .NET in general), is not const
-safe.
However, the usual C and C++ functions are. You can write either:
array<byte>^ data_array =gcnew array<byte>(dataSize);
pin_ptr<byte> data_array_start = &data_array[0];
memcpy(data_array_start, data, dataSize);
or to avoid pinning:
array<byte>^ data_array =gcnew array<byte>(dataSize);
for( int i = 0; i < data_array->Length; ++i )
data_array[i] = data[i];
System::Runtime::InteropServices::Marshal::Copy(new IntPtr((void*)data), _Data, 0, dataSize);
Pay attention to (void*) which type-casts from (const void*) so new IntPtr constructor can take it as argument.