How to Send C++ Struct Message from C# Socket? - c#

This is the C++ Message that i need to pass from C#:
struct LoginMessage:public NMessage
{
char szUser[ 16 ];
char szPass[ 16 ];
LoginMessage()
{
msgId = CTRL_SESSION_LOGIN;
msgSize = sizeof( LoginMessage );
}
};
struct NMessage
{
DWORD msgSize;
union
{
DWORD msgId;
struct
{
BYTE msgId0;
BYTE msgId1;
BYTE msgId2;
BYTE msgId3;
};
};
NMessage()
{
}
BOOL IsLegal()
{
return msgSize>=sizeof(NMessage) && msgSize
What is the equivalent of this in C# so that C++ can understand this message?
Sample code is greatly appreciated.

To answer my own question..
[StructLayout(LayoutKind.Sequential)]
public struct LoginMessage
{
public int msgSize;
public int msgId;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 16)]
public string szUser;
[MarshalAsAttribute(UnmanagedType.ByValTStr, SizeConst = 16)]
public string szPass;
}
It is important to take note of the sequence of the class properties so that the byte array you send to c++ is exactly the same as what it expects.

Have a look at this. it's a nice marshaling guid.

Take a look at the StructLayout attribute on MSDN. There is a good example on that page on how to create a struct that can be marshalled correctly. You can also look at http://www.pinvoke.net to see different examples of how the Windows API structs are defined to be marshaled. Once you have the struct defined right, you should be able to use Marshal.StructureToPtr or Marshal.PtrToStructure. Here's a short article on it: http://geekswithblogs.net/taylorrich/archive/2006/08/21/88665.aspx

I usually manually serialize data using something like this.
class NMessage {
byte[] buffer;
//ctor to create a new message for sending.
public NMessage(int nSize) {
buffer = new byte[nSize];
Buffer.BlockCopy(BitConverter.GetBytes(nSize), 0, buffer, 0, sizeof(UInt32));
}
//ctor to create msg from received data.
publix NMessage(byte[] buffer) {
this.buffer = buffer;
}
public UInt32 MessageId {
get { return BitConverter.ToUInt32(buffer, 4);
set { Buffer.BlockCopy(BitConverter.GetBytes(value), 0, buffer, 4, sizeof(UInt32)); }
}
...
public Byte MessageId2 {
get { return buffer[6]; }
set { buffer[6] = value; }
}
...
public UInt32 Size {
get { return BitConverter.ToUInt32(buffer, 0) }
}
public Byte[] Buffer {
get { return buffer; }
}
}
class LoginMessage : NMessage {
Encoding encoding = new ASCIIEncoding(); //or whatever encoding you need.
public LoginMessage() : base(16 + 16) {
this.MessageId = CTRL_SESSION_LOGIN;
}
public LoginMessage(NMessage message) : base(message.Buffer) {
}
public string User {
get { return encoding.GetString(buffer, 8, 16); }
set { Buffer.BlockCopy(encoding.GetBytes(value), 0, buffer, 8, 16);
}
public string Pass {
get { return encoding.GetString(buffer, 24, 16); }
set { Buffer.BlockCopy(encoding.GetBytes(value), 0, buffer, 24, 16);
}
}
So you simply create you new message, set it's data, then send the Buffer property.
Send((new LoginMessage {
User = "user",
Pass = "pass",
}).Buffer);
On the receiving end, if you have enough data, you can build the message from the byte[] you receive.
byte[] recvBuf = new byte[MAX_RECV];
int recvSize = Receive(recvBuf);
...
var message = new NMessage(recvBuf);
if (message.MessageId == CTRL_SESSION_LOGIN)
var login = new LoginMessage(message);
var user = login.User;
...
That's just a rough overview anyway, the code obviously needs a cleanup as I reduced it to only demonstrate the idea.

Related

Marshal class instance from and to byte array

I'm trying to marshal a class instance from and to byte array using these methods:
Marshal to byte array:
public static byte[] MakeArrayFromCat(Cat cat)
{
var size = Marshal.SizeOf(typeof(Cat));
var bytes = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(cat, ptr, false);
Marshal.Copy(ptr, bytes, 0, size);
Marshal.FreeHGlobal(ptr);
return bytes;
}
Marshal to class instance:
public static Cat MakeCatFromArray(byte[] b)
{
var size = b.Length;
var bytes = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptr, size);
var cat = (Cat)Marshal.PtrToStructure(ptr, typeof(Cat));
Marshal.FreeHGlobal(ptr);
return cat;
}
Here's my class:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class Cat
{
public string Name { get; set; }
public int Weight { get; set; }
public int Age { get; set; }
public Cat (string name, int age, int weight)
{
Name = name;
Age = age;
Weight = weight;
}
}
So when I run the presented methods the program throws MissingMethodException meaning that there's no constructor that takes no arguements. I get it on this line (in MakeCatFromArray method):
var cat = (Cat)Marshal.PtrToStructure(ptr, typeof(Cat));
I've tried to add a default constructor, but what I get from it doesn't live up to what I expect: It gives me an instance with all its properties empty, although I marshalled an instance with non-default values. Thus I've got two questions:
1.How do I do marshalling properly in this case?
2.Is there any better way of converting an instance of a class into byte array without marking it as [Serializable] ?
The problem is with this:
Marshal.Copy(bytes, 0, ptr, size);
You are trying to create Cat from empty bytes array.
There should be b instead of bytes:
Marshal.Copy(b, 0, ptr, size);

How to change array reference index with don't use pointer in C#?

I'm writing code to parse packets.
I want to change the reference address of the array, but I do not know how to change the reference address without using the pointer.
If I copy a part of an array, I think it will slow down. If I use a pointer, it will be unsafe.
Below is the code I am writing.
public class Datagrams : LinkedList<DatagramPacket>
{
public Datagrams(byte[] RowData) : base()
{
AddLast(new DatagramPacket(RowData));
while(Last.Value.header.Length.LastIndicator)
{
///////////////////////////////////////////
//I want do that. But this is unsafe code//
///////////////////////////////////////////
AddLast(new DatagramPacket( RowData + sizeof[Last.Value] ));
}
}
}
public class DatagramPacket : Packet
{
public enum DatagramCmd : Byte
{
NOP = 0x0,
APRD = 0x1,
APWR = 0x2,
APRW = 0x3,
FPRD = 0x4,
FPWR = 0x5,
FPRW = 0x6,
BRD = 0x7,
BWR = 0x8,
BRW = 0x9,
LRD = 0xA,
LWR = 0xB,
LRW = 0xC,
ARMW = 0xD,
FRMW = 0xE
}
[StructLayout(LayoutKind.Explicit)]
public struct DatagramAddr
{
[MarshalAs(UnmanagedType.U4), FieldOffset(0)]
public UInt32 LogicalAddr;
[MarshalAs(UnmanagedType.U2), FieldOffset(0)]
public UInt16 SlaveAddr;
[MarshalAs(UnmanagedType.U2), FieldOffset(2)]
public UInt16 OffsetAddr;
}
public struct DatagramLength
{
[MarshalAs(UnmanagedType.U2)]
public UInt16 bits;
public int Length { get => bits & 0x07FF; }
public bool Valid { get => (bits & 0x0380) == 0; }
public bool RoundTrip { get => (bits & 0x4000) != 0; }
public bool LastIndicator { get => (bits & 0x8000) != 0; }
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct DatagramHeader
{
[MarshalAs(UnmanagedType.U1)]
public DatagramCmd Cmd;
[MarshalAs(UnmanagedType.U1)]
public Byte Index;
[MarshalAs(UnmanagedType.Struct)]
public DatagramAddr Addr;
[MarshalAs(UnmanagedType.Struct)]
public DatagramLength Length;
[MarshalAs(UnmanagedType.U2)]
public UInt16 Interrupt;
}
public DatagramHeader header;
public UInt16 wc; //Working Count
public DatagramPacket(byte[] RowData) : base(RowData)
{
header = new DatagramHeader();
GCHandle handle = GCHandle.Alloc(RowData, GCHandleType.Pinned);
try
{
header = (DatagramHeader)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(DatagramHeader));
}
finally
{
handle.Free();
}
body = new byte[header.Length.Length];
Buffer.BlockCopy(RowData, Marshal.SizeOf<DatagramHeader>(), body, 0, body.Length);
wc = BitConverter.ToUInt16(RowData, Marshal.SizeOf<DatagramHeader>() + body.Length);
}
public override Packet Parse()
{
throw new NotImplementedException();
}
}
Is there a way that change reference without using pointer?
I have already solved the problem by copying the array as shown below, but I think it will be slower than referring to it by any means. I tried to process packets in real time for showing graph, but should I give up real time processing as much as I use .net?
public class Datagrams : LinkedList<DatagramPacket>
{
public Datagrams(byte[] RowData) : base()
{
AddLast(new DatagramPacket(RowData));
while(Last.Value.header.Length.LastIndicator)
{
int index = Marshal.SizeOf<DatagramPacket.DatagramHeader>() + Last.Value.header.Length.Length + sizeof(UInt16);
byte[] temp = new byte[RowData.Length - index];
Buffer.BlockCopy(RowData, index, temp, 0, RowData.Length - index);
RowData = temp;
AddLast(new DatagramPacket(RowData));
}
}
}

Marshal array of struct into Ptr

I am calling a C library from a C# code. The function I am calling take as parameter a struct containing arrays of struct :
struct Example1Struct
{
char* a;
uint16_t b;
AnotherStruct* c;
}
c here is an array of pointer to AnotherStruct.
the struct in my C# code look like this
public struct Example1Struct
{
public IntPtr StationName;//is char*
public UInt16 IdCode;
public IntPtr AnotherStruct; //array of struct AnotherStruct
}
public static IntPtr MarshalToPointer(object data)
{
Type valueType = data.GetType();
IntPtr buf = IntPtr.Zero;
if (valueType.IsArray)
{
if (data is char[])
{
var d = data as char[];
buf = Marshal.AllocHGlobal(Marshal.SizeOf(d.GetType().GetElementType()) * d.Length);
}
else if (data is char[,])
{
var d = data as char[,];
buf = Marshal.AllocHGlobal(Marshal.SizeOf(d.GetType().GetElementType()) * d.Length);
}
else
{
buf = Marshal.AllocHGlobal(Marshal.SizeOf(data.GetType().GetElementType()) * count);
long LongPtr = buf.ToInt64(); // Must work both on x86 and x64
for (int I = 0; I < data.Lenght; I++)
{
IntPtr RectPtr = new IntPtr(LongPtr);
Marshal.StructureToPtr(data[I], RectPtr, false); // You do not need to erase struct in this case
LongPtr += Marshal.SizeOf(typeof(Rect));
}
}
return buf;
}
else
buf = Marshal.AllocHGlobal(Marshal.SizeOf(data));
Marshal.StructureToPtr(data, buf, false);
return buf;
}
my problem here is that I cannot cast data (who is an array of AnotherStruct) to object[] , neither in IEnumerable. So I cannot access to data[I] and don't have data.Lenght
Any idea ?
Usually I'd recommend using the MarshalAs attribute rather than writing manual marshalling code. It looks like:
public struct Example1Struct
{
public IntPtr StationName;//is char*
public UInt16 IdCode;
public IntPtr AnotherStruct; //array of struct AnotherStruct
}
Could be:
public struct Example1Struct
{
[MarshalAs(UnmanagedType.LPStr)]
public string StationName;
public UInt16 IdCode;
[MarshalAs(UnmanagedType.LPArray)]
public AnotherStruct[] OtherStructs;
}
And the marshaller should do the right thing for you when you pass it to unmanaged code.
You can get the length of the array like this:
if (data is Array a)
Console.WriteLine(a.Length);
Arrays in c# always derive from Array, so you can cast it to that.
But if possible in your real code, I'd recommend Damien's answer

Fixed Object to Byte Array

I have a simple object that looks like this:
public class Foo
{
public UInt32 One { get; set; }
public UInt32 Two { get; set; }
public UInt32 Three { get; set; }
public UInt32 Four { get; set; }
}
I tried this code I found somewhere on the net:
public byte[] ObjectToByteArray(Object obj)
{
MemoryStream fs = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(fs, obj);
byte[] rval = fs.ToArray();
fs.Close();
return rval;
}
But somehow the returning byte array has a size of 248 bytes.
I would expect it to be 4 bytes x 4 fields = 16 bytes.
QUESTION:
What's the cleanest way to convert a fixed object into a byte array?
And should the resulting array be 16 bytes in size in this case?
BinaryFormatter saves a lot of type information to be able to deserialize properly. If you want compact serialization or to comunicate via some strict protocol, you will have to do it explictly like this:
public byte[] ToByteArray()
{
List<byte> result = new List<byte>();
result.AddRange(BitConverter.GetBytes(One));
result.AddRange(BitConverter.GetBytes(Two));
result.AddRange(BitConverter.GetBytes(Three));
result.AddRange(BitConverter.GetBytes(Four));
return result.ToArray();
}
here I convert each of your UInt32 into byte array and store it in resulting array.
Edit
Turns out there is another way by using struct and Marshal
First you make struct and mark it with attributes like that:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct MyStruct
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string StringField;
public int IntField;
}
Here LayoutKind.Sequential tells clr to keep fields in memory in same order as declaration. Without Pack = 1 structures can take more memory than required. Like struct with one short field and one byte needs only 3 bytes, but by default it's size will most likely be 4 (processor has instructions for manipulating single byte, 2 bytes and 4 bytes, clr sacrifices one byte per instance of struct to reduce amount of instructions of machine code by half). Now you can use Marshal to copy bytes:
public static byte[] GetBytes<T>(T str)
{
int size = Marshal.SizeOf(str);
var bytes = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, bytes, 0, size);
return bytes;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
Everything works fine with simple types. For complex types such as string you'll have to use MarshalAs attribute and it's using is a bit more complicated (In example I told clr to marshal string as array of fixed 50 bytes size).
Here's another way...which way is best is a matter of opinion probably. I like Atomosk's answer. Combine that answer with cast operator overloads and you've got a pretty elegant solution.
class Foo
{
public UInt32 One { get; set; }
public UInt32 Two { get; set; }
public UInt32 Three { get; set; }
public UInt32 Four { get; set; }
static public implicit operator byte[](Foo f)
{
MemoryStream m = new MemoryStream(16);
BinaryWriter w = new BinaryWriter(m);
w.Write(f.One);
w.Write(f.Two);
w.Write(f.Three);
w.Write(f.Four);
w.Close();
m.Close();
return m.ToArray();
}
static public explicit operator Foo(byte[] b)
{
Foo f = new Foo();
MemoryStream m = new MemoryStream(b);
BinaryReader r = new BinaryReader(m);
f.One = r.ReadUInt32();
f.Two = r.ReadUInt32();
f.Three = r.ReadUInt32();
f.Four = r.ReadUInt32();
r.Close();
m.Close();
return f;
}
}
class Program
{
static void Main(string[] args)
{
Foo f = new Foo() { One = 1, Two = 2, Three = 3, Four = 4 };
byte[] b = (byte[])f;
Console.WriteLine(b.Length);
f = (Foo)b;
Console.WriteLine("{0} {1} {2} {3}", f.One, f.Two, f.Three, f.Four);
Console.ReadKey(true);
}
}
Keep in mind that when you serialise an object with the BinaryFormatter, you're including things like type information. That results in the overhead you're seeing.
If you want to serialise an object into (in this case) just 16 bytes then you'll need to do it manually with something like a StreamWriter.
If size isn't an issue then a Binaryformatter in this case isn't wrong and doesn't take much code to do it, but it's not the most memory efficient way of doing it.
Edit: Here's how you'd do it with a StreamWriter
System.IO.MemoryStream stream = new System.IO.MemoryStream();
StreamWriter writer = new StreamWriter(stream);
writer.Write(myObject.One); // here's where we actually write the data to the stream
writer.Write(myObject.Two);
writer.Write(myObject.Three);
writer.Write(myObject.Four);
writer.Flush(); // make sure all the data in the stream writer ends up in the
// underlying stream
byte[] result = stream.ToArray(); // here's your resulting byte array
stream.Dispose(); // don't forget to dispose of the stream!
Here is one way to do it manually which will guarantee the 16-bytes.
using System;
using System.IO;
using System.Linq;
public class Foo
{
public UInt32 One { get; set; }
public UInt32 Two { get; set; }
public UInt32 Three { get; set; }
public UInt32 Four { get; set; }
public Foo() {}
public Foo(byte[] array)
{
One = BitConverter.ToUInt32(array,0);
Two = BitConverter.ToUInt32(array,4);
Three = BitConverter.ToUInt32(array,8);
Four = BitConverter.ToUInt32(array,12);
}
public byte[] toByteArray()
{
byte[] retVal = new byte[16];
byte[] b = BitConverter.GetBytes(One);
Array.Copy(b, 0, retVal, 0, 4);
b = BitConverter.GetBytes(Two);
Array.Copy(b, 0, retVal, 4, 4);
b = BitConverter.GetBytes(Three);
Array.Copy(b, 0, retVal, 8, 4);
b = BitConverter.GetBytes(Four);
Array.Copy(b, 0, retVal, 12, 4);
return retVal;
}
}
public class P{
public static void Main(string[] args) {
Foo foo = new Foo();
foo.One = 1;
foo.Two = 2;
foo.Three = 3;
foo.Four = 4;
byte[] arr = foo.toByteArray();
Console.WriteLine(arr.Length);
Foo bar = new Foo(arr);
Console.WriteLine(string.Format("{0} {1} {2} {3}", bar.One, bar.Two, bar.Three, bar.Four));
}
}
Output:
16
1 2 3 4

Copying a string to a fixed length byte buffer in a structure

given this structure in c#:
[StructLayout(LayoutKind.Sequential)]
unsafe public struct AppVPEntry
{
public int Num;
public fixed byte CompName[256];
public int VPBeginAddress;
}
Whats the easiest way to copy a string ("c:\path\file.txt") to the fixed length buffer 'CompName'. This is in a structure thats being sent over to an archaic DLL that we've got no choice but to use. Ideally I'd love to use a .NET function but since it's fixed which implies 'unsafe' I know I'm limited here. A more generic function would help since we've got strings like this all over the DLL import space.
// C# to convert a string to a byte array.
public static byte[] StrToByteArray(string str)
{
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
return encoding.GetBytes(str);
}
You probably want to check to see if the size of the string isn't longer than the size of the buffer.
Try this out. Use an IntPtr in your DllImport wherever you might pass a VPEntry. Pass the "unmanaged" field wherever you call your DLL method.
public sealed class AppVPEntry : IDisposable {
[StructLayout(LayoutKind.Sequential, Size = 264)]
internal struct _AppVPEntry {
[MarshalAs(UnmanagedType.I4)]
public Int32 Num;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
public Byte[] CompName;
[MarshalAs(UnmanagedType.I4)]
public Int32 VPBeginAddress;
}
private readonly IntPtr unmanaged;
private readonly _AppVPEntry managed = new _AppVPEntry();
public AppVPEntry(Int32 num, String path, Int32 beginAddress) {
this.managed.Num = num;
this.managed.CompName = new byte[256];
Buffer.BlockCopy(Encoding.ASCII.GetBytes(path), 0, this.managed.CompName, 0, Math.Min(path.Length, 256));
this.managed.VPBeginAddress = beginAddress;
this.unmanaged = Marshal.AllocHGlobal(264);
Marshal.StructureToPtr(this.managed, this.unmanaged, false);
}
public void Dispose() {
Marshal.FreeHGlobal(this.unmanaged);
}
}

Categories