C# - Convert unsafe byte* to byte[] - c#

I have an unsafe byte* pointing to a native byte array of known length. How can I convert it to byte[]?
An unsafe sbyte* pointing to a zero-terminated native string can be converted to a C# string easily, because there is a conversion constructor for this purpose, but I can't find a simple way to convert byte* to byte[].

If ptr is your unsafe pointer, and the array has length len, you can use Marshal.Copy like this:
byte[] arr = new byte[len];
Marshal.Copy((IntPtr)ptr, arr, 0, len);
But I do wonder how you came by an unsafe pointer to native memory. Do you really need unsafe here, or can you solve the problem by using IntPtr instead of an unsafe pointer? And if so then there's probably no need for unsafe code at all.

The Marshal class could help you.
byte[] bytes = new byte[length];
for(int i = 0; i < length; ++i)
bytes[i] = Marshal.ReadByte(yourPtr, i);
I think you might use Marshal.Copy too.

Related

How can I pass in a pointer to a pointer of a UInt16 array to a Marshalled function?

I'm attempting to send a pointer to a pointer of a UInt16 array to a marshalled function like so in C#:
C++:
int foo(Unsigned_16_Type** Buffer_Pointer);
C#:
[DllImport("example.dll")]
public static extern int foo(IntPtr Buffer_Pointer);
UInt16[] bufferArray = new UInt16[32];
IntPtr p_Buffer = (IntPtr)Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(UInt16)) * bufferArray.Length);
Marshal.Copy(bufferArray, 0, p_Buffer, bufferArray.Length); //Issue is here
GCHandle handle = GCHandle.Alloc(p_Buffer, GCHandleType.Pinned);
IntPtr ppUnmanagedBuffer = (IntPtr)handle.AddrOfPinnedObject();
UInt16 word_count = 0;
this.lstbox_DATA_WORDS.Items.Clear();
if ( foo(ppUnmanagedBuffer );
My main problem is with the Marshal.Copy, for the first argument which is the source array, it does not take a UInt16[]. I was wondering if anyone knew how to use Marshal.Copy with a UInt16 array.
There is no Marshal.Copy overload that takes an unsigned short array. Fortunately, ushort and short are the same size, so you can use the Marshal.Copy(Int16[], IntPtr, int) overload. You just need to coerce your ushort[] into a short[] first.
Probably the fastest way to do this is to use Buffer.BlockCopy. It copies bytes, so you just have to tell it to copy 2 bytes per entry:
short[] temp = new short[bufferArray.Length];
System.Buffer.BlockCopy(bufferArray, 0, temp, 0, temp.Length * 2);
This will copy the unsigned 16-bit integer values into a signed 16-bit integer array, but the underlying byte values will remain the same, and the unmanaged code won't know the difference.

Convert IntPtr to byte[] c#

I receive IntPtr value from C++ library method and i need to get byte[] array from this received IntPtr. When I try do this:
byte[] myArray = new byte[Marshal.SizeOf(myReceivedIntPtr)];
Marshal.Copy(myReceivedIntPtr, myArray, 0, Marshal.SizeOf(myReceivedIntPtr));
I receive an exception: AccessViolationException.
What I missed?
EDIT:
Here is Method name and params in header of C++ library:
int MSR_DecodeTrack(char *AscBuff, unsigned char *BinBuff, unsigned char bpc, unsigned char parity, unsigned char ss, unsigned char es);
And I call it from C# this way:
UInt32 result;
IntPtr myReceivedIntPtr;
IntPtr BinBuff;
byte BPC1 = 7, Parity1 = 1, SS1 = 0x05, ES1 = 0x1F;
result = MSR_DecodeTrack(ref myReceivedIntPtr, ref BinBuff, BPC1, Parity1, SS1, ES1);
And here is else code:
byte[] myArray = new byte[Marshal.SizeOf(myReceivedIntPtr)];
Marshal.Copy(myReceivedIntPtr, myArray, 0, Marshal.SizeOf(myReceivedIntPtr));
I'm pretty sure Marshal.SizeOf(myReceivedIntPtr) will return the size of the IntPtr object, not the size of the unmanaged array. You will need to get the size of the unmanaged array from the c++ library.
I haven't had to do this in a while so I'm a bit rusty but from looking at the c++ headers I think it is expecting a pointer to a buffer. You are giving it a pointer to a pointer (intptr is a pointer and passing it by ref means you are passing the c++ code a pointer to that pointer). Firstly, don't use ref. Secondly, I suspect you are supposed to be passing it an already sized buffer - is there any documentation describing what you are supposed to pass to the function? What is the return code from the function? You are checking it for success aren't you? ;)
The method named MSR_DecodeTrack should also return the length of each array it allocates.
As far as I know, when you allocate an array in C/C++ environment, you get a pointer to the zero element of that array, nothing more. For that reason, you should also somehow return the length of the allocated array back to the caller. It can be done by an additional "ref" parameter.
HTH.

C++ <--> C# modify a marshalled array of bytes

I have an unmanaged C++ function which is calling a managed C# method in a DLL. The purpose of the C# method is to take an array of bytes (allocated by the C++ caller), populate the array, and return it. I can get the array INTO the C# method, but the populated data are lost when they get back to the C++ function. Right now, this is my test code to debug the process:
C# DLL Method:
// Take an array of bytes and modify it
public ushort GetBytesFromBlaster([MarshalAs(UnmanagedType.LPArray)] byte[] dataBytes)
{
dataBytes[0] = (byte)'a';
dataBytes[1] = (byte)'b';
dataBytes[2] = (byte)'c';
return 3;
}
C++ function which calls the DLL:
// bytes[] has been already allocated by its caller
short int SimGetBytesP2P(unsigned char bytes[])
{
unsigned short int numBytes = 0;
bytes[0] = 'x';
bytes[1] = 'y';
bytes[2] = 'z';
// bytes[] are {'x', 'y', 'z'} here
guiPtr->GetBytesFromBlaster(bytes, &numBytes);
// bytes[] SHOULD be {'a', 'b', 'c'} here, but they are still {'x', 'y', 'z'}
return(numBytes);
}
I believe it has something to do with C# turning the C++ pointer into a new managed array, but modifying the original one. I have tried several variations using the "ref" modifyer, etc., but no luck. Also, these data are NOT null-terminated strings; the date bytes are raw 1-byte values, not null-terminated.
Can anyone please shed some light on this? Thanks!
Stuart
You could do the marshaling yourself. Have the C# function accept a parameter by value of type IntPtr. Also a second parameter indicating array length. No special marshaling attributes are needed or wanted.
Then, use Marshal.Copy and copy the array from the unmanaged pointer to a managed byte[] array that you allocated. Do your thing, and then when you're done, use Marshal.Copy to copy it back to the C++ unmanaged array.
These particular overloads should get you started:
http://msdn.microsoft.com/en-us/library/ms146625.aspx
http://msdn.microsoft.com/en-us/library/ms146631.aspx
For example:
public ushort GetBytesFromBlaster(IntPtr dataBytes, int arraySize)
{
byte[] managed = new byte[arraySize];
Marshal.Copy(dataBytes, managed, 0, arraySize);
managed[0] = (byte)'a';
managed[1] = (byte)'b';
managed[2] = (byte)'c';
Marshal.Copy(managed, 0, dataBytes, arraySize);
return 3;
}
Alternatively you could implement a custom marshaller as described in http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx if the default one isn't doing what you need it to. But that looks like more work.
I believe that you just need to add a SizeConst attribute:
public ushort GetBytesFromBlaster(
[MarshalAs(UnmanagedType.LPArray, SizeConst=3)]
byte[] dataBytes
)
and the default marshaller should do the rest for you.

byte[] to byte* in C#

I created 2 programs - in C# and C++, both invoke native methods from C dll. C++ works fine, because there are the same data types, C# doesn't work.
And native function parameter is unsigned char*. I tried byte[] in C#, it didn't work, then I tried:
fixed(byte* ptr = byte_array) {
native_function(ptr, (uint)byte_array.Length);
}
It also doesn't work. Is it correct to convert byte array to byte* in such way? Is it correct to use byte in C# as unsigned char in C?
EDIT:
This stuff returns the wrong result:
byte[] byte_array = Encoding.UTF8.GetBytes(source_string);
nativeMethod(byte_array, (uint)byte_array.Length);
This stuff also returns the wrong result:
byte* ptr;
ptr = (byte*)Marshal.AllocHGlobal((int)byte_array.Length);
Marshal.Copy(byte_array, 0, (IntPtr)ptr, byte_array.Length);
unsafe class Test
{
public byte* PointerData(byte* data, int length)
{
byte[] safe = new byte[length];
for (int i = 0; i < length; i++)
safe[i] = data[i];
fixed (byte* converted = safe)
{
// This will update the safe and converted arrays.
for (int i = 0; i < length; i++)
converted[i]++;
return converted;
}
}
}
You also need to set the "use unsafe code" checkbox in the build properties.
You have to marshal the byte[] :
[DllImport("YourNativeDLL.dll")]
public static extern void native_function
(
[MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)]
byte[] data,
int count // Recommended
);
You could allocate an unmanaged array and use Marshal.Copy to copy the contents of the managed byte[] array to an unmanaged unsigned char* array. Note that unmanaged resources must be cleaned up manually.

How to set an int to byte* C#

How can I convert an int to a byte* at a certain index in a byte*?
Ideally I would like to have something like:
unsafe{
byte* igm=stackalloc byte[8];
igm[4]=4283;
}
It would set the first part of the bit to igm[4] and the rest into igm[5].
Edit: I realize there may be a lot of possible ways to handle this, i am looking for the most efficient way if possible.
try this:
unsafe
{
byte* igm = stackalloc byte[8];
*(int*)(igm + 4) = 4283;
}
Once you realize that you can use simple pointer arithmetic to index anywhere in your byte array, things get a LOT easier.
The type system in C# will prevent you from doing that, as you might have noticed. However, you can cast your pointers to be the appropiate types:
unsafe
{
byte* igm = stackalloc byte[8];
int* intPtr = (int*)igm;
intPtr[1] = 4283;
}
You need to break your int to sizeof(int) count of bytes and then manually set this parts to your byte* at specified indexes.
This will be safer as you'll know WHAT and WHERE you place your data.

Categories