How to copy struct to byte [] ?
-
I need to call an unmanaged function that takes, basically, a void pointer to a buffer. I've got the transfer to the unmanaged DLL working by passing a byte [] and letting .NET marshal. However, the buffer may contain different data structures on different calls since it's a kind of generic entry point with the exact function specified in the first field. In C I would do something like this: char buf[1000]; struct Header { int cmd; int flags; int param; }; struct Cmd1SpecificData { double param1ForCommand1; short param2ForCommand1; short param3ForCommand1; // and so on... }; void foo() { Header *header = (Header *)buf; Cmd1SpecificData = (Cmd1SpecificData *)(header + 1); header->cmd = 1; header->flags = 999; Cmd1SpecificData->param1ForCommand1 = 123.456; APICALL(buf); } APICALL can now look at the first field and figure out what to do. In C# I don't quite know how to do this. I have a byte [] which is the equivalent of the char buf[] but how do I cast pointers into the byte []? I couldn't find a simple way to copy data from a struct to a byte [] or how to use a MemoryStream to stream the data into the byte []. My questions: 1) What's the best way of getting the contents of a struct into a byte array? Note that I'll need to get different structures chained together so I might need to put the contents of the structs at specific offsets in the byte array. 2) Is there a fundamentally better way of getting .NET data to an API of this sort? Maybe I should do the marshalling myself and convert everything to a pointer before calling the unmanaged code? Thanks, Andrew Queisser
-
I need to call an unmanaged function that takes, basically, a void pointer to a buffer. I've got the transfer to the unmanaged DLL working by passing a byte [] and letting .NET marshal. However, the buffer may contain different data structures on different calls since it's a kind of generic entry point with the exact function specified in the first field. In C I would do something like this: char buf[1000]; struct Header { int cmd; int flags; int param; }; struct Cmd1SpecificData { double param1ForCommand1; short param2ForCommand1; short param3ForCommand1; // and so on... }; void foo() { Header *header = (Header *)buf; Cmd1SpecificData = (Cmd1SpecificData *)(header + 1); header->cmd = 1; header->flags = 999; Cmd1SpecificData->param1ForCommand1 = 123.456; APICALL(buf); } APICALL can now look at the first field and figure out what to do. In C# I don't quite know how to do this. I have a byte [] which is the equivalent of the char buf[] but how do I cast pointers into the byte []? I couldn't find a simple way to copy data from a struct to a byte [] or how to use a MemoryStream to stream the data into the byte []. My questions: 1) What's the best way of getting the contents of a struct into a byte array? Note that I'll need to get different structures chained together so I might need to put the contents of the structs at specific offsets in the byte array. 2) Is there a fundamentally better way of getting .NET data to an API of this sort? Maybe I should do the marshalling myself and convert everything to a pointer before calling the unmanaged code? Thanks, Andrew Queisser
Well, to copy a struct to a byte[], you need some marshaling code..It uses the Marshal class (as if that wasn't obvious) to allocate some memory..Like this: (i usually declare methods like this as an instance method and a static method with a parameter of whatever type it's defined in)
public byte[] ToBytes() { byte[] buff = new byte[Marshal.SizeOf(typeof(MyType))]; GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned); Marshal.StructureToPtr(this, handle.AddrOfPinnedObject(), false); handle.Free(); return buff; }
That code will marshal the struct to a byte[], and from that code, the code for marshaling back to a struct comes easy:public static MyType FromBytes(byte[] buff) { GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned); MyType mt = (MyType)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(MyType)); // because ptrtostructure returns an object :-\ handle.Free(); return mt; }
Now as for chaining structures together, you can do that yourself using Array.Copy() and copying into a byte[] Passing back the data as an IntPtr requires only slight modification to the original functions:public IntPtr ToIntPtr() { byte[] buff = new byte[Marshal.SizeOf(typeof(MyType))]; IntPtr handle = Marshal.AllocHGlobal(buff.Length); Marshal.StructureToPtr(this, handle, true); // passing false for that last param can cause memory leaks return handle; } public static MyType FromIntPtr(IntPtr ptr) { MyType mt = (MyType)Marshal.PtrToStructure(ptr, typeof(MyType)); // because ptrtostructure returns an object :-\ //Marshal.FreeHGlobal(ptr); - only do this if you know you won't be using that IntPtr again return mt; }
Note: That code is not 100% guaranteed to compile or work, I didn't test it very much, but it should work, and the basic concept is more or less correct. If you have any more questions, feel free to ask.
-
I need to call an unmanaged function that takes, basically, a void pointer to a buffer. I've got the transfer to the unmanaged DLL working by passing a byte [] and letting .NET marshal. However, the buffer may contain different data structures on different calls since it's a kind of generic entry point with the exact function specified in the first field. In C I would do something like this: char buf[1000]; struct Header { int cmd; int flags; int param; }; struct Cmd1SpecificData { double param1ForCommand1; short param2ForCommand1; short param3ForCommand1; // and so on... }; void foo() { Header *header = (Header *)buf; Cmd1SpecificData = (Cmd1SpecificData *)(header + 1); header->cmd = 1; header->flags = 999; Cmd1SpecificData->param1ForCommand1 = 123.456; APICALL(buf); } APICALL can now look at the first field and figure out what to do. In C# I don't quite know how to do this. I have a byte [] which is the equivalent of the char buf[] but how do I cast pointers into the byte []? I couldn't find a simple way to copy data from a struct to a byte [] or how to use a MemoryStream to stream the data into the byte []. My questions: 1) What's the best way of getting the contents of a struct into a byte array? Note that I'll need to get different structures chained together so I might need to put the contents of the structs at specific offsets in the byte array. 2) Is there a fundamentally better way of getting .NET data to an API of this sort? Maybe I should do the marshalling myself and convert everything to a pointer before calling the unmanaged code? Thanks, Andrew Queisser
Best way it to create a pinned pointer, then it looks/works like C. EG
byte[] buf = new byte[1000];
unsafe
{
fixed (byte* b = buf)
{
Header *header = (Header *)b;
Cmd1SpecificData* specdata = (Cmd1SpecificData *)(header + 1);
header->cmd = 1;
header->flags = 999;
specdata->param1ForCommand1 = 123.456;APICALL(b);
}
}xacc-ide 0.0.15 now with C#, MSIL, C, XML, ASP.NET, Nemerle, MyXaml and HLSL coloring - Screenshots