I read following some where. Can somebody shed some light on it probably with an example
'the message could even be a struct that is just converted to a byte array which is outputted on the debug UART.
Then on the PC side, the incoming byte array can be easily converted back to a struct like object.'
You can use unsafe to access any blittable (arrays, strings, structs etc.) types as a byte pointer.
Local variables of value types don't have to be pinned:
public unsafe void ReadAsBytePointer(MyStruct obj)
{
byte* ptr = (byte*)&obj;
...
}
Arrays must be pinned. The easiest solution is to use fixed:
public unsafe void ReadAsBytePointer(MyStruct[] input)
{
fixed(MyStruct* ptr = input)
{
byte* byteArray = (byte*)ptr;
}
}
For a general case without adding unsafe to your code you can use GCHandle:
static byte[] GetBytes<T>(T input)
where T : struct
{
int size = Marshal.SizeOf(typeof(T));
byte[] result = new byte[size];
GCHandle gc = GCHandle.Alloc(input, GCHandleType.Pinned);
try
{
Marshal.Copy(gc.AddrOfPinnedObject(), result, 0, size);
}
finally
{
gc.Free();
}
return result;
}
Related
I'm trying to fill a structure (does not have to be an actual struct), with data loaded from a byte[].
There are many different data structures in the byte[], one of them is a string, which is declared as:
UInt16 stringLenght
byte[stringLenght] zeroTerminatedString
I 'c' language this could be handled by declaring a fixed size struct, and instead of a the struct containing the actual string, make a pointer to the string.
Something like:
UInt16 stringLength
char* zeroTerminatedString
Is there a (smart) way to do something similar in c#? I mean loading binary data from a file/memory and filling it into a structure?
Regards
Jakob Justesen
That's not how you'd declare it in C. If the record in the file contains a string then you'd declare the structure similar to:
struct Example {
int mumble; // Anything, not necessarily a string length
char text[42];
// etc...
};
The equivalent C# declaration would look like:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
private struct Example {
public int mumble;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
public string text;
// etc...
}
You'd normally use BinaryReader to read the data. But it cannot handle strings like this directly, you have to read them as a byte[] and do the string conversion yourself. You also cannot take advantage of the declarative syntax, you have to write a call for each individual member of the struct.
There's a workaround for that, the Marshal class already knows how to convert unmanaged structures to managed ones with the PtrToStructure() method. Here's a generic implementation, it works for any blittable type. Two versions, a static one that reads from a byte[] and an instance method that was optimized to repeatedly read from a stream. You'd use a FileStream or MemoryStream with that one.
using System;
using System.IO;
using System.Runtime.InteropServices;
class StructTranslator {
public static bool Read<T>(byte[] buffer, int index, ref T retval) {
if (index == buffer.Length) return false;
int size = Marshal.SizeOf(typeof(T));
if (index + size > buffer.Length) throw new IndexOutOfRangeException();
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try {
IntPtr addr = (IntPtr)((long)handle.AddrOfPinnedObject() + index);
retval = (T)Marshal.PtrToStructure(addr, typeof(T));
}
finally {
handle.Free();
}
return true;
}
public bool Read<T>(Stream stream, ref T retval) {
int size = Marshal.SizeOf(typeof(T));
if (buffer == null || size > buffer.Length) buffer = new byte[size];
int len = stream.Read(buffer, 0, size);
if (len == 0) return false;
if (len != size) throw new EndOfStreamException();
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try {
retval = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally {
handle.Free();
}
return true;
}
private byte[] buffer;
}
Untested, hope it works.
The Marshal should be able to do this for you.
Note that this can only be done to a struct and you will probably need to use the StructLayout attribute.
I'm not 100% sure on how to handle the string or arrays, but BStrWrapper or ArrayWithOffset MIGHT help, also keep on the lookout for similar classes/attributes (I know I have done stuff like this before for binding to native functions).
I am trying to serialize a structure to disk as raw bytes. This is a (simplified)version of it.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestData :BaseStructure
{
public byte[] bytes = new byte[]{65,66,67}; // this doesn't write ABC as expected
}
A write function uses ConvertStructureToBytes method to convert this to a byte array and a binary writer then writes it.
public void Write(BaseStructure baseStructure)
{
binaryWriter.Write(ConvertStructureToBytes(baseStructure));
}
The ConvertStructureToBytes section
public byte[] ConvertStructureToBytes(BaseStructure baseStructure)
{
int len = Marshal.SizeOf(baseStructure);
byte[] arr = new byte[len];
IntPtr ptr = Marshal.AllocHGlobal(len);
Marshal.StructureToPtr(baseStructure, ptr,false);
Marshal.Copy(ptr, arr, 0, len);
Marshal.FreeHGlobal(ptr);
return arr;
}
If I replace the bytes line to
public byte byte = 65; // This now writes an A , as expected
I have tried
public byte[] bytes = Encoding.ASCII.GetBytes("ABC"); //doesn't work either
This probably has something to do with the ConvertStructureToBytes function , it isn't treating the byte array as it should.
What do I need to do to be able to write 'ABC' successfully?
Several problems. First your structure declaration is not correct, you have to in-line the array so it no longer a pointer:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestData {
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] bytes = new byte[] { 65, 66, 67 };
}
Then your ConvertStructureToBytes() method is not correct, it is only ever going to marshal BaseStructure. You need to make it generic:
public static byte[] ConvertStructureToBytes<T>(T baseStructure) {
// rest the same...
}
Do note the kind of trouble you can get into with this approach, it most certainly is not a universal way to marshal data. Only very specific classes can be serialized this way. That [MarshalAs] attribute is of course very painful to maintain. You might as well use binary serialization.
Change the class definition to this and try it:
StructLayout(LayoutKind.Sequential, Pack = 1)]
public class TestData :BaseStructure
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] bytes = new byte[]{65,66,67};
}
Try this:
byte[] bytes = Encoding.ASCII.GetBytes("ABC").ToArray();
Or, after I tested that. Maybe you mean this:
bytes = new byte[] { 65, 66, 67 };
string test = Encoding.UTF8.GetString(bytes).ToString();
I am using the excellent VLC wrapper created by Roman Ginzburg re: nVLC
This part of his code returns a bitmap object.
In myh calling code I then convert it to a byte array.
I sthere a way to directly convert the memory pointer to a byte array with converting to a bitmap object.
this is his code:
unsafe void OnpDisplay(void* opaque, void* picture)
{
lock (m_lock)
{
PixelData* px = (PixelData*)opaque;
MemoryHeap.CopyMemory(m_pBuffer, px->pPixelData, px->size);
m_frameRate++;
if (m_callback != null)
{
using (Bitmap frame = GetBitmap())
{
m_callback(frame);
}
}
}
}
private Bitmap GetBitmap()
{
return new Bitmap(m_format.Width, m_format.Height, m_format.Pitch, m_format.PixelFormat, new IntPtr(m_pBuffer));
}
What I would like is another function like:
private byte[] GetBytes()
{
//not sure what to put here...
}
I am lookinga s I type but still cannot find anything or even if it possible to do so...
Thanks
Use Marshal.Copy. Like this:
private byte[] GetBytes() {
byte[] bytes = new byte[size];
Marshal.Copy(m_pBuffer, bytes, 0, size);
return bytes;
}
I'm not quite sure where you are storing the size of the buffer, but you must know that.
An aside. Why do you write new IntPtr(m_pBuffer) in GetBitmap rather than plain m_pBuffer?
I also wonder why you feel the need to use unsafe code here. Is it really needed?
I'm trying to fill a structure (does not have to be an actual struct), with data loaded from a byte[].
There are many different data structures in the byte[], one of them is a string, which is declared as:
UInt16 stringLenght
byte[stringLenght] zeroTerminatedString
I 'c' language this could be handled by declaring a fixed size struct, and instead of a the struct containing the actual string, make a pointer to the string.
Something like:
UInt16 stringLength
char* zeroTerminatedString
Is there a (smart) way to do something similar in c#? I mean loading binary data from a file/memory and filling it into a structure?
Regards
Jakob Justesen
That's not how you'd declare it in C. If the record in the file contains a string then you'd declare the structure similar to:
struct Example {
int mumble; // Anything, not necessarily a string length
char text[42];
// etc...
};
The equivalent C# declaration would look like:
[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
private struct Example {
public int mumble;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 42)]
public string text;
// etc...
}
You'd normally use BinaryReader to read the data. But it cannot handle strings like this directly, you have to read them as a byte[] and do the string conversion yourself. You also cannot take advantage of the declarative syntax, you have to write a call for each individual member of the struct.
There's a workaround for that, the Marshal class already knows how to convert unmanaged structures to managed ones with the PtrToStructure() method. Here's a generic implementation, it works for any blittable type. Two versions, a static one that reads from a byte[] and an instance method that was optimized to repeatedly read from a stream. You'd use a FileStream or MemoryStream with that one.
using System;
using System.IO;
using System.Runtime.InteropServices;
class StructTranslator {
public static bool Read<T>(byte[] buffer, int index, ref T retval) {
if (index == buffer.Length) return false;
int size = Marshal.SizeOf(typeof(T));
if (index + size > buffer.Length) throw new IndexOutOfRangeException();
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try {
IntPtr addr = (IntPtr)((long)handle.AddrOfPinnedObject() + index);
retval = (T)Marshal.PtrToStructure(addr, typeof(T));
}
finally {
handle.Free();
}
return true;
}
public bool Read<T>(Stream stream, ref T retval) {
int size = Marshal.SizeOf(typeof(T));
if (buffer == null || size > buffer.Length) buffer = new byte[size];
int len = stream.Read(buffer, 0, size);
if (len == 0) return false;
if (len != size) throw new EndOfStreamException();
var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try {
retval = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
}
finally {
handle.Free();
}
return true;
}
private byte[] buffer;
}
Untested, hope it works.
The Marshal should be able to do this for you.
Note that this can only be done to a struct and you will probably need to use the StructLayout attribute.
I'm not 100% sure on how to handle the string or arrays, but BStrWrapper or ArrayWithOffset MIGHT help, also keep on the lookout for similar classes/attributes (I know I have done stuff like this before for binding to native functions).
I want to pass a byte[] to a method takes a IntPtr Parameter in C#, is that possible and how?
Another way,
GCHandle pinnedArray = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
IntPtr pointer = pinnedArray.AddrOfPinnedObject();
// Do your stuff...
pinnedArray.Free();
The following should work but must be used within an unsafe context:
byte[] buffer = new byte[255];
fixed (byte* p = buffer)
{
IntPtr ptr = (IntPtr)p;
// Do your stuff here
}
Beware: you have to use the pointer within the fixed block. The GC can move the object once you are no longer within the fixed block.
Not sure about getting an IntPtr to an array, but you can copy the data for use with unmanaged code by using Mashal.Copy:
IntPtr unmanagedPointer = Marshal.AllocHGlobal(bytes.Length);
Marshal.Copy(bytes, 0, unmanagedPointer, bytes.Length);
// Call unmanaged code
Marshal.FreeHGlobal(unmanagedPointer);
Alternatively you could declare a struct with one property and then use Marshal.PtrToStructure, but that would still require allocating unmanaged memory.
Edit: Also, as Tyalis pointed out, you can also use fixed if unsafe code is an option for you
You could use Marshal.UnsafeAddrOfPinnedArrayElement to get a memory pointer to the array (or to a specific element in the array). Keep in mind that the array must be pinned first as per the API documentation:
The array must be pinned using a GCHandle before it is passed to this method. For maximum performance, this method does not validate the array passed to it; this can result in unexpected behavior.
Here's a twist on #user65157's answer (+1 for that, BTW):
I created an IDisposable wrapper for the pinned object:
class AutoPinner : IDisposable
{
GCHandle _pinnedArray;
public AutoPinner(Object obj)
{
_pinnedArray = GCHandle.Alloc(obj, GCHandleType.Pinned);
}
public static implicit operator IntPtr(AutoPinner ap)
{
return ap._pinnedArray.AddrOfPinnedObject();
}
public void Dispose()
{
_pinnedArray.Free();
}
}
then use it like thusly:
using (AutoPinner ap = new AutoPinner(MyManagedObject))
{
UnmanagedIntPtr = ap; // Use the operator to retrieve the IntPtr
//do your stuff
}
I found this to be a nice way of not forgetting to call Free() :)
Marshal.Copy works but is rather slow. Faster is to copy the bytes in a for loop. Even faster is to cast the byte array to a ulong array, copy as much ulong as fits in the byte array, then copy the possible remaining 7 bytes (the trail that is not 8 bytes aligned). Fastest is to pin the byte array in a fixed statement as proposed above in Tyalis' answer.
In some cases you can use an Int32 type (or Int64) in case of the IntPtr. If you can, another useful class is BitConverter. For what you want you could use BitConverter.ToInt32 for example.