Marshal.PtrToStructure (and back again) and generic solution for endianness swapping

后端 未结 4 1911
情书的邮戳
情书的邮戳 2020-12-02 15:02

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

4条回答
  •  情话喂你
    2020-12-02 15:16

    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!

提交回复
热议问题