i trying share a array via memoryfile c++ to c# based on this example:stream data from c++ to c# over shared memory.
work fine, but i just can get until position 3 from array, another position come 0.
C++ that creat MemoryFile
#include <windows.h>
#include <stdio.h>
struct Pair {
int length;
int data[10];
};
struct Pair* p;
HANDLE handle;
int dataSend[10]{ 500,33,44,66,2,55,98,7,52,36 };
bool startShare()
{
try
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Pair), L"DataSend");
p = (struct Pair*) MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(Pair));
return true;
}
catch (...)
{
return false;
}
}
int main()
{
if (startShare() == true)
{
printf("Memory Create");
while (true)
{
if (p != 0) {
for (int h = 0; h < 10; h++)
{
p->data[h] = dataSend[h];
printf("\n number %d", dataSend[h]);
}
}
else
puts("create shared memory error");
}
}
if (handle != NULL)
CloseHandle(handle);
return 0;
}
my C# Read
public static int[] data = new int[10];
public static MemoryMappedFile mmf;
public static MemoryMappedViewStream mmfvs;
static public bool MemOpen()
{
try
{
mmf = MemoryMappedFile.OpenExisting("DataSend");
mmfvs = mmf.CreateViewStream();
return true;
}
catch
{
return false;
}
}
public static void Main(string[] args)
{
while (true)
{
if (MemOpen())
{
byte[] blen = new byte[4];
mmfvs.Read(blen, 0, 4);
byte[] bPosition = new byte[280];
mmfvs.Read(bPosition, 0, 280);
Buffer.BlockCopy(bPosition, 0, data, 0, bPosition.Length);
for (int i = 0; i < data.Length; i++)
{
Console.WriteLine(data[i]);
}
}
}
}
work fine, but i just can get until position 3 from array, another position come 0.
Update, code work fine now
Just a detail,i return a array hex value example:52A7E600
but in my code c# get bit numbers like: 10300071984, how i cant convert in side c# to get same format?
to convert long value to hex in c# you could use:
long intValue = 10300071984;
// Convert long value 10300071984 -> 265EEA030 as a hex in a string variable
string hexValue = intValue.ToString("X");
Related
As several blogposts and Stackoverflow answers suggest, it is trivial to get this information via a combination of get-process and Get-NetTCPConnection commandlets. It is possible to execute these commands via .net code, parse the output and retrieve the information.
Is it not possible to get the port number a process is listening on in pure .net code using just the .net libraries? System.Diagnostics.Process.GetProcesByName returns a ton of information via the Process object, except for the port the process is listening on.
Any leads highly appreciated.
Unfortunately, IPGlobalProperties.GetIPGlobalProperties() does not return any information on which process is holding the socket, as it uses GetTcpTable not GetTcpTable2.
You would need to code it yourself. The below code works for TCP over IPv4. You would need similar code for UDP and IPv6.
[DllImport("Iphlpapi.dll", ExactSpelling = true)]
static extern int GetTcpTable2(
IntPtr TcpTable,
ref int SizePointer,
bool Order
);
[StructLayout(LayoutKind.Sequential)]
struct MIB_TCPTABLE
{
public int dwNumEntries;
}
[StructLayout(LayoutKind.Sequential)]
struct MIB_TCPROW2
{
public MIB_TCP_STATE dwState;
public int dwLocalAddr;
public byte localPort1;
public byte localPort2;
// Ports are only 16 bit values (in network WORD order, 3,4,1,2).
// There are reports where the high order bytes have garbage in them.
public byte ignoreLocalPort3;
public byte ignoreLocalPort4;
public int dwRemoteAddr;
public byte remotePort1;
public byte remotePort2;
// Ports are only 16 bit values (in network WORD order, 3,4,1,2).
// There are reports where the high order bytes have garbage in them.
public byte ignoreremotePort3;
public byte ignoreremotePort4;
public int dwOwningPid;
public TCP_CONNECTION_OFFLOAD_STATE dwOffloadState;
}
public enum MIB_TCP_STATE
{
Closed = 1,
Listen,
SynSent,
SynRcvd,
Established,
FinWait1,
FinWait2,
CloseWait,
Closing,
LastAck,
TimeWait,
DeleteTcb
}
enum TCP_CONNECTION_OFFLOAD_STATE
{
TcpConnectionOffloadStateInHost,
TcpConnectionOffloadStateOffloading,
TcpConnectionOffloadStateOffloaded,
TcpConnectionOffloadStateUploading,
TcpConnectionOffloadStateMax
}
static List<IPEndPoint> GetSocketsForProcess(int pid, MIB_TCP_STATE state = MIB_TCP_STATE.Established)
{
const int ERROR_INSUFFICIENT_BUFFER = 0x7A;
var size = 0;
var result = GetTcpTable2(IntPtr.Zero, ref size, false);
if (result != ERROR_INSUFFICIENT_BUFFER)
throw new Win32Exception(result);
var ptr = IntPtr.Zero;
try
{
ptr = Marshal.AllocHGlobal(size);
result = GetTcpTable2(ptr, ref size, false);
if (result != 0)
throw new Win32Exception(result);
var list = new List<IPEndPoint>();
var count = Marshal.ReadInt32(ptr);
var curPtr = ptr + Marshal.SizeOf<MIB_TCPTABLE>();
var length = Marshal.SizeOf<MIB_TCPROW2>();
for(var i = 0; i < count; i++)
{
var row = Marshal.PtrToStructure<MIB_TCPROW2>(curPtr);
if(row.dwOwningPid == pid && row.dwState == state)
list.Add(new IPEndPoint(row.dwLocalAddr, row.localPort1 << 8 | row.localPort2));
curPtr += length;
}
return list;
}
finally
{
Marshal.FreeHGlobal(ptr);
}
}
I had similar task not long ago. Here is complete .NET 6 code that you should be able to adopt for your particular needs:
public static int CheckConnection(string[] servers)
{
try
{
var srvs = servers.ToDictionary(k => k.Split("/", StringSplitOptions.RemoveEmptyEntries)[1], v => false);
IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] endPoints = ipProperties.GetActiveTcpListeners();
TcpConnectionInformation[] tcpConnections = ipProperties.GetActiveTcpConnections();
var count = 0;
foreach (var info in tcpConnections)
{
var ep = string.Format("{0}:{1}", info.RemoteEndPoint.Address, info.RemoteEndPoint.Port);
if (info.State.ToString().ToUpper() != "ESTABLISHED")
continue;
if (srvs.ContainsKey(ep))
{
count++;
srvs[ep] = true;
}
}
var sb = new StringBuilder();
foreach (var kvp in srvs)
{
sb.AppendFormat("{0,-21}: {1}", kvp.Key, kvp.Value ? "OK" : "FAIL");
sb.AppendLine();
}
Program.logger.Trace($"ZMQF. Connection check:\n{sb}");
return count;
}
catch (Exception ex)
{
Program.logger.Fatal(ex, $"ZMQF. CheckConnection exception. Servers: {(string.Join(",", servers))}");
return -1;
}
}
I am trying to convert a zip file into a text file (xml) using the following methods. It works fine for smaller file but dose not seem to work for files larger than 50 mb.
class Program
{
public static void Main(string[] args)
{
try
{
string importFilePath = #"D:\CorpTax\Tasks\966442\CS Publish error\CSUPD20180604L.zip";
int maxLengthInMb = 20;
byte[] payLoad = File.ReadAllBytes(importFilePath);
int payLoadInMb = (payLoad.Length / 1024) / 1024;
bool splitIntoMultipleFiles = (payLoadInMb / maxLengthInMb) > 1;
int payLoadLength = splitIntoMultipleFiles ? maxLengthInMb * 1024 * 1024 : payLoad.Length;
if (splitIntoMultipleFiles)
{
foreach (byte[] splitPayLoad in payLoad.Slices(payLoadLength))
{
ToXml(payLoad);
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
public static string ToXml(byte[] payLoad)
{
using (XmlStringWriter xmlStringWriter = new XmlStringWriter())
{
xmlStringWriter.WriteStartDocument();
xmlStringWriter.Writer.WriteStartElement("Payload");
xmlStringWriter.Writer.WriteRaw(Convert.ToBase64String(payLoad));
xmlStringWriter.Writer.WriteEndElement();
xmlStringWriter.WriteEndDocument();
return xmlStringWriter.ToString();
}
}
}
I have a .zip file which is like 120 MB in size and I get the
System.OutOfMemoryException when calling Convert.ToBase64String().
So I went ahead and split the byte array into a size of 20 mb chunks hoping that it will not fail. But I see that it works until it goes through the loop 3 times i.e able to convert 60mb of the data and in the 4th iteration i get the same exception. Some times I also get exceptions at the line return xmlStringWriter.ToString()
To split the byte[] I have used the following extension classes
public static class ArrayExtensions
{
public static T[] CopySlice<T>(this T[] source, int index, int length, bool padToLength = false)
{
int n = length;
T[] slice = null;
if (source.Length < index + length)
{
n = source.Length - index;
if (padToLength)
{
slice = new T[length];
}
}
if (slice == null) slice = new T[n];
Array.Copy(source, index, slice, 0, n);
return slice;
}
public static IEnumerable<T[]> Slices<T>(this T[] source, int count, bool padToLength = false)
{
for (var i = 0; i < source.Length; i += count)
{
yield return source.CopySlice(i, count, padToLength);
}
}
}
I got the above code from the following link
Splitting a byte[] into multiple byte[] arrays in C#
Funny part is the program runs fine when I run it in a console application but when I put this code into the windows application it throws the System.OutOfMemoryException.
Preferablilty you want to be doing something like this
byte[] Packet = new byte[4096];
string b64str = "";
using (FileStream fs = new FileStream(file, FileMode.Open))
{
int i = Packet.Length;
while (i == Packet.Length)
{
i = fs.Read(Packet, 0, Packet.Length);
b64str = Convert.ToBase64String(Packet, 0, i);
}
}
with that b64str you should create your xml data.
Also it is typically unwise to allocate 20mb on stack all in one go.
i'm trying to get the C# equivalent of a C++ class, i've very very basic knowledge in C++ so idk if that's really possible or not. I've try something but i'm stuck. So if you can help me to "parse" this c++ class to c# and explain me how you do it or give some link who could help me. (Or give me a tips for using this c++ class into my c# project (idk if it's possible because of the managed/unmanaged code etc..)
C++ class:
class GameString
{
public:
GameString (GameString const&) = delete;
GameString& operator=(GameString const&) = delete;
GameString (const std::string &str)
: _buf (8)
{
append (str);
setHeader (1, length ());
}
GameString& operator+=(const std::string &str)
{
append (str);
setHeader (1, length ());
return *this;
}
std::size_t length ()
{
return _buf.size () - 8;
}
char *str ()
{
return reinterpret_cast<char*>(_buf.data () + 8);
}
private:
std::vector<unsigned char> _buf;
void append (const std::string &str)
{
for (auto &c : str)
{
_buf.push_back (c);
}
}
void setHeader (std::size_t ref, std::size_t len)
{
memcpy (&_buf[0], &ref, 4);
memcpy (&_buf[4], &len, 4);
}
};
C# class:
class GameString
{
private List<char> _buf = new List<char>(8);
public GameString(string str)
{
Append(str);
SetHeader(1, Length());
}
private void Append(string str)
{
foreach (char c in str)
{
_buf.Add(c);
}
}
public int Length()
{
return _buf.Count - 8;
}
public string Str()
{
// return new String(_buf.ToArray());
}
private void SetHeader(int rf, int length)
{
// memcpy(&_buf[0], &ref, 4);
// memcpy(&_buf[4], &len, 4);
}
}
And thanks for your help
public class GameString
{
private MemoryStream buf;
public GameString(string str)
{
buf = new MemoryStream();
// 8 empty bytes at the beginning
buf.SetLength(8);
buf.Position = 8;
Append(str);
}
// Different from C++ implementation. This one is public
// and updates the SetHeader
public void Append(string str)
{
byte[] utf8 = Encoding.UTF8.GetBytes(str);
buf.Write(utf8, 0, utf8.Length);
SetHeader(1, Length);
}
public static GameString operator +(GameString gs, string str)
{
gs.Append(str);
return gs;
}
// This one is a property instead of being a method
public int Length { get => (int)buf.Length - 8; }
// The char *str ()
public override string ToString()
{
return Encoding.UTF8.GetString(buf.GetBuffer(), 8, (int)buf.Length - 8);
}
// This one was missing in the C++ implementation. Returns the internal buffer.
// trimmed to the correct length. Note that it creates a copy!
public byte[] ToByteArray()
{
return buf.ToArray();
}
private void SetHeader(int #ref, int len)
{
// This could be optimized. Sadly the GetBytes create new
// arrays as the return value, instead of writing to a
// preexisting array.
byte[] temp = BitConverter.GetBytes(#ref);
Buffer.BlockCopy(temp, 0, buf.GetBuffer(), 0, temp.Length);
temp = BitConverter.GetBytes(len);
Buffer.BlockCopy(temp, 0, buf.GetBuffer(), 4, temp.Length);
}
}
And then:
var gs = new GameString("Foo");
gs.Append("Bar");
gs.Append("Baz");
gs += "Hello";
gs += "World";
string str = gs.ToString();
byte[] bytes = gs.ToByteArray();
I've made some changes to the C++ code, commented inside the C# code.
I'm using MemoryStream instead of a List<> or a StringBuilder. char in C# is 2 bytes, while in C it is 1 byte, so in C# you should use byte, not char.
Since the header is seemingly a fixed value of 1 and the length, unless i'm missing something
You could easily just use string and string.Length();
// instantiate
string gameString = "sadasd";
// get length
var len = gameString.Length();
// append
gameString += "sdfsfsdfdsf";
// get length again
var newLen = gameString.Length();
I am attempting to stream data from a c++ application to a C# application using shared memory. Based on example I found, I have:
c++ (sending)
struct Pair {
int length;
float data[3];
};
#include <windows.h>
#include <stdio.h>
struct Pair* p;
HANDLE handle;
float dataSend[3]{ 22,33,44 };
bool startShare()
{
try
{
handle = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(Pair), L"DataSend");
p = (struct Pair*) MapViewOfFile(handle, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, sizeof(Pair));
return true;
}
catch(...)
{
return false;
}
}
int main()
{
if (startShare() == true)
{
while (true)
{
if (p != 0) {
//dataSend[0] += 1; // here the value doesn't refresh
for (int h = 0; h < 3; h++)
{
p->data[h] = dataSend[h];
}
//dataSend[0] += 1; // here it does
}
else
puts("create shared memory error");
}
}
if (handle != NULL)
CloseHandle(handle);
return 0;
}
C# (receiving)
namespace sharedMemoryGET
{
class Program
{
public static float[] data = new float[3];
public static MemoryMappedFile mmf;
public static MemoryMappedViewStream mmfvs;
static public bool MemOpen()
{
try {
mmf = MemoryMappedFile.OpenExisting("DataSend");
mmfvs = mmf.CreateViewStream();
return true;
}
catch
{
return false;
}
}
public static void Main(string[] args)
{
while (true)
{
if (MemOpen())
{
byte[] blen = new byte[4];
mmfvs.Read(blen, 0, 4);
int len = blen[0] + blen[1] * 256 + blen[2] * 65536 + blen[2] * 16777216;
byte[] bPosition = new byte[12];
mmfvs.Read(bPosition, 0, 12);
Buffer.BlockCopy(bPosition, 0, data, 0, bPosition.Length);
Console.WriteLine(data[0]);
}
}
}
}
}
The c++ side never updates the variable, making me think i have missed something in my if-loop. Additionally, is a always-running loop the best way to go here? Is there a way to 'request' the data somehow from the C# side, to make this a more efficient system? Thank you.
..Actually this is working, I had the update for the variable in the wrong place. I have edited and will leave the code for others.
I have a system where a remote agent sends serialized structures (from an embedded C system) for me to read and store via IP/UDP. In some cases I need to send back the same structure types. I thought I had a nice setup using Marshal.PtrToStructure (receive) and Marshal.StructureToPtr (send). However, a small gotcha is that the network big endian integers need to be converted to my x86 little endian format to be used locally. When I'm sending them off again, big endian is the way to go.
Here are the functions in question:
private static T BytesToStruct<T>(ref byte[] rawData) where T: struct
{
T result = default(T);
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr rawDataPtr = handle.AddrOfPinnedObject();
result = (T)Marshal.PtrToStructure(rawDataPtr, typeof(T));
}
finally
{
handle.Free();
}
return result;
}
private static byte[] StructToBytes<T>(T data) where T: struct
{
byte[] rawData = new byte[Marshal.SizeOf(data)];
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr rawDataPtr = handle.AddrOfPinnedObject();
Marshal.StructureToPtr(data, rawDataPtr, false);
}
finally
{
handle.Free();
}
return rawData;
}
And a quick example structure that might be used like this:
byte[] data = this.sock.Receive(ref this.ipep);
Request request = BytesToStruct<Request>(ref data);
Where the structure in question looks like:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
private struct Request
{
public byte type;
public short sequence;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public byte[] address;
}
What (generic) way can I swap the endianness when marshalling the structures? My need is such that the locally stored 'request.sequence' in this example should be little-endian for displaying to the user. I don't want to have to swap the endianness in a structure-specific way since it's a generic problem.
My first thought was to use Reflection, but I'm not very familiar with that feature. Also, I hoped that there would be a better solution out there that somebody could point me towards. Thanks in advance :)
Reflection does seem like the only real way to accomplish what you're after.
I've put together some code below. It creates an attribute called EndianAttribute that can be applied at the field level on a struct. I've included the definition for this attribute and it's associated enum, as well as the modifications to your code necessary to use it.
As a side note, you did not need to define rawData as a ref parameter.
Note that this does require the use of C# 3.0/.NET 3.5, since I'm using LINQ and anonymous types in the function doing the work. It would not be difficult to rewrite the function without these features, though.
[AttributeUsage(AttributeTargets.Field)]
public class EndianAttribute : Attribute
{
public Endianness Endianness { get; private set; }
public EndianAttribute(Endianness endianness)
{
this.Endianness = endianness;
}
}
public enum Endianness
{
BigEndian,
LittleEndian
}
private static void RespectEndianness(Type type, byte[] data)
{
var fields = type.GetFields().Where(f => f.IsDefined(typeof(EndianAttribute), false))
.Select(f => new
{
Field = f,
Attribute = (EndianAttribute)f.GetCustomAttributes(typeof(EndianAttribute), false)[0],
Offset = Marshal.OffsetOf(type, f.Name).ToInt32()
}).ToList();
foreach (var field in fields)
{
if ((field.Attribute.Endianness == Endianness.BigEndian && BitConverter.IsLittleEndian) ||
(field.Attribute.Endianness == Endianness.LittleEndian && !BitConverter.IsLittleEndian))
{
Array.Reverse(data, field.Offset, Marshal.SizeOf(field.Field.FieldType));
}
}
}
private static T BytesToStruct<T>(byte[] rawData) where T : struct
{
T result = default(T);
RespectEndianness(typeof(T), rawData);
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr rawDataPtr = handle.AddrOfPinnedObject();
result = (T)Marshal.PtrToStructure(rawDataPtr, typeof(T));
}
finally
{
handle.Free();
}
return result;
}
private static byte[] StructToBytes<T>(T data) where T : struct
{
byte[] rawData = new byte[Marshal.SizeOf(data)];
GCHandle handle = GCHandle.Alloc(rawData, GCHandleType.Pinned);
try
{
IntPtr rawDataPtr = handle.AddrOfPinnedObject();
Marshal.StructureToPtr(data, rawDataPtr, false);
}
finally
{
handle.Free();
}
RespectEndianness(typeof(T), rawData);
return rawData;
}
For those of us without Linq, a replacement RespectEndianness():
private static void RespectEndianness(Type type, byte[] data) {
foreach (FieldInfo f in type.GetFields()) {
if (f.IsDefined(typeof(EndianAttribute), false)) {
EndianAttribute att = (EndianAttribute)f.GetCustomAttributes(typeof(EndianAttribute), false)[0];
int offset = Marshal.OffsetOf(type, f.Name).ToInt32();
if ((att.Endianness == Endianness.BigEndian && BitConverter.IsLittleEndian) ||
(att.Endianness == Endianness.LittleEndian && !BitConverter.IsLittleEndian)) {
Array.Reverse(data, offset, Marshal.SizeOf(f.FieldType));
}
}
}
}
Here's my variation - it handles nested structs and arrays, with the assumption that arrays are of a fixed size, eg marked with a [MarshalAs(UnmanagedType.ByValArray, SizeConst = N)] attribute.
public static class Serializer
{
public static byte[] GetBytes<T>(T structure, bool respectEndianness = true) where T : struct
{
var size = Marshal.SizeOf(structure); //or Marshal.SizeOf<T>(); in .net 4.5.1
var bytes = new byte[size];
var ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(structure, ptr, true);
Marshal.Copy(ptr, bytes, 0, size);
Marshal.FreeHGlobal(ptr);
if (respectEndianness) RespectEndianness(typeof(T), bytes);
return bytes;
}
public static T FromBytes<T>(byte[] bytes, bool respectEndianness = true) where T : struct
{
var structure = new T();
if (respectEndianness) RespectEndianness(typeof(T), bytes);
int size = Marshal.SizeOf(structure); //or Marshal.SizeOf<T>(); in .net 4.5.1
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptr, size);
structure = (T)Marshal.PtrToStructure(ptr, structure.GetType());
Marshal.FreeHGlobal(ptr);
return structure;
}
private static void RespectEndianness(Type type, byte[] data, int offSet = 0)
{
var fields = type.GetFields()
.Select(f => new
{
Field = f,
Offset = Marshal.OffsetOf(type, f.Name).ToInt32(),
}).ToList();
foreach (var field in fields)
{
if (field.Field.FieldType.IsArray)
{
//handle arrays, assuming fixed length
var attr = field.Field.GetCustomAttributes(typeof(MarshalAsAttribute), false).FirstOrDefault();
var marshalAsAttribute = attr as MarshalAsAttribute;
if (marshalAsAttribute == null || marshalAsAttribute.SizeConst == 0)
throw new NotSupportedException(
"Array fields must be decorated with a MarshalAsAttribute with SizeConst specified.");
var arrayLength = marshalAsAttribute.SizeConst;
var elementType = field.Field.FieldType.GetElementType();
var elementSize = Marshal.SizeOf(elementType);
var arrayOffset = field.Offset + offSet;
for (int i = arrayOffset; i < arrayOffset + elementSize * arrayLength; i += elementSize) {
RespectEndianness(elementType, data, i);
}
}
else if (!field.Field.FieldType.IsPrimitive) //or !field.Field.FiledType.GetFields().Length == 0
{
//handle nested structs
RespectEndianness(field.Field.FieldType, data, field.Offset);
}
else
{
//handle primitive types
Array.Reverse(data, offSet + field.Offset, Marshal.SizeOf(field.Field.FieldType));
}
}
}
}
This question was awesome and helped me a lot! I needed to expand on the endian changer though as it doesn't seem to handle arrays or structs within structs.
public struct mytest
{
public int myint;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public int[] ptime;
}
public static void SwapIt(Type type, byte[] recvbyte, int offset)
{
foreach (System.Reflection.FieldInfo fi in type.GetFields())
{
int index = Marshal.OffsetOf(type, fi.Name).ToInt32() + offset;
if (fi.FieldType == typeof(int))
{
Array.Reverse(recvbyte, index, sizeof(int));
}
else if (fi.FieldType == typeof(float))
{
Array.Reverse(recvbyte, index, sizeof(float));
}
else if (fi.FieldType == typeof(double))
{
Array.Reverse(recvbyte, index, sizeof(double));
}
else
{
// Maybe we have an array
if (fi.FieldType.IsArray)
{
// Check for MarshalAs attribute to get array size
object[] ca = fi.GetCustomAttributes(false);
if (ca.Count() > 0 && ca[0] is MarshalAsAttribute)
{
int size = ((MarshalAsAttribute)ca[0]).SizeConst;
// Need to use GetElementType to see that int[] is made of ints
if (fi.FieldType.GetElementType() == typeof(int))
{
for (int i = 0; i < size; i++)
{
Array.Reverse(recvbyte, index + (i * sizeof(int)), sizeof(int));
}
}
else if (fi.FieldType.GetElementType() == typeof(float))
{
for (int i = 0; i < size; i++)
{
Array.Reverse(recvbyte, index + (i * sizeof(float)), sizeof(float));
}
}
else if (fi.FieldType.GetElementType() == typeof(double))
{
for (int i = 0; i < size; i++)
{
Array.Reverse(recvbyte, index + (i * sizeof(double)), sizeof(double));
}
}
else
{
// An array of something else?
Type t = fi.FieldType.GetElementType();
int s = Marshal.SizeOf(t);
for (int i = 0; i < size; i++)
{
SwapIt(t, recvbyte, index + (i * s));
}
}
}
}
else
{
SwapIt(fi.FieldType, recvbyte, index);
}
}
}
}
Note this code was only tested on structs made of int, float, double. Will probably mess up if you have a string in there!