none
Marshalling variable sized arrays. RRS feed

  • Question

  • I am playing around with serializing message data from a com port with some success until i reached some variable sized messages. I could easily do this with c++ but where is the fun in that!

    So I wrote some code, and was wondering if anyone has an easy way to marhsal variable sized arrays as per my sample code below. The odd part about this is that the Marshal.SizeOf gets the size right, but when you look at the memory it does not marshal TestClass1 array. It looks like this in memory -> 01 02 03 04 70 be 1e as if its only trying (and failing) to marshal 3 of the 4 bytes in the TestClass1 array.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.IO;

    namespace MarshalTest
    {
        class Program
        {
            static void Main(string[] args)
            {
                TestClass tc = new TestClass();
                tc.data1 = 1;
                tc.data2 = 2;
                tc.dataArray[0] = 3;
                tc.dataArray[1] = 4;
                tc.dataTestClass1[0].data[0] = 5;
                tc.dataTestClass1[0].data[1] = 6;
                tc.dataTestClass1[1].data[0] = 7;
                tc.dataTestClass1[1].data[1] = 8;

                int size = Marshal.SizeOf(tc);

                byte[] buffer = new byte[Marshal.SizeOf(tc)];
                GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                IntPtr temp = handle.AddrOfPinnedObject();
                Marshal.StructureToPtr(tc, handle.AddrOfPinnedObject(), false);
                handle.Free();

            }
        }

        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        class TestClass1
        {
            public TestClass1()
            {
                data = new byte[2];
            }

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
            public byte[] data;
        }


        [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
        class TestClass
        {
            public TestClass()
            {
                dataArray = new byte[2];
                //this is example only uses an 2 element array of TestClass1's
                //but in reality it could be any number of elements
                dataTestClass1 = new TestClass1[2];
                dataTestClass1[0] = new TestClass1();
                dataTestClass1[1] = new TestClass1();
            }
           
            public byte data1;
            public byte data2;
            [MarshalAs(UnmanagedType.ByValArray,SizeConst=2)]
            public byte[] dataArray;
            //wont marshall this class.. possible to do without using custom marshaller?
            public TestClass1[] dataTestClass1;
        }
    }



    Wednesday, March 26, 2008 5:09 AM

Answers

  • --I have had a very brief look at this and I dont think this would work for variable sized arrays.
    Yes, fixed array is only appliable for fixed length arrays.

    So far as I know, for variable size array, you have to manually do the marshalling job.


    Monday, March 31, 2008 5:48 AM

All replies

  • StructLayout is for structs not classes.  You can also use the new fixed keyword.

           

    Code Snippet

    static void Main()
            {
                unsafe
                {
                    TestStruct _TestStruct = new TestStruct();
                    int _Size = sizeof(TestStruct);
                    IntPtr _Ptr = Marshal.AllocHGlobal(_Size);
                    Marshal.StructureToPtr(_TestStruct, _Ptr, true);
                    //Do Stuff
                    _TestStruct = (TestStruct)Marshal.PtrToStructure(_Ptr, typeof(TestStruct));
                    Marshal.FreeHGlobal(_Ptr);
                }


            }

            [StructLayout(LayoutKind.Sequential,Pack=1)]
            public unsafe struct TestStruct
            {
                public fixed int MyInts[20];

                public int MyInt;
            }


    Wednesday, March 26, 2008 5:25 AM
  • According to MSDN doco you can use structlayout attribute with classes

    http://msdn2.microsoft.com/en-us/library/system.runtime.interopservices.structlayoutattribute.aspx

     

    I will look into fixed keyword. I have had a very brief look at this and I dont think this would work for variable sized arrays.

     

    Your suggestion would not work for me as I need to be able to modify the class before serializing it. I would also need a method of deserializing it after recieving it in its binary form. If create the class/struct in usafe code, i still need to marshal it to managed code.

    Wednesday, March 26, 2008 8:27 AM
  • --I have had a very brief look at this and I dont think this would work for variable sized arrays.
    Yes, fixed array is only appliable for fixed length arrays.

    So far as I know, for variable size array, you have to manually do the marshalling job.


    Monday, March 31, 2008 5:48 AM