Ask a questionAsk a question
 

AnswerMarshal Structure

  • Monday, October 26, 2009 1:47 PMJim Griffin Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    I have an unmanaged structure :
    struct {
      int level;
      char user[5];
      char name[32];
     ...
    }
    that I'm attempting to marshal into managed structure:
    [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Ansi,Pack=1)]
    public struct giidbm_MddDefinition
    {
      [MarshalAs(UnmanagedType.I4),FieldOffset(0)]
      public int level;
      [MarshalAs(UnamangedType.LPStr,SizeConst=4,FieldOffset(4)]
      public string user;
      [MarshalAs(UnmanagedType.LPStr,SizeConst=31,FieldOffset(9)]
      public string name;

    ...
    }

    This bombs at every instantiation of giidbm_MddDefinition, saying that:
     
      Message="Could not load type 'giidbm_MddDefinition' from assembly 'ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 9 that is incorrectly aligned or overlapped by a non-object field."

    I've tried many different ways to marshal this, but I always end up with the above error.

    What am I missing?

Answers

  • Tuesday, October 27, 2009 8:50 AMJialiang Ge [MSFT]MSFT, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hello Jim

    Please try this declaration:

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)]
    public struct giidbm_MddDefinition {
       
        /// int
        public int level;
       
        /// char[5]
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=5)]
        public string user;
       
        /// char[32]
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=32)]
        public string name;
    }


    It was auto-generated by one of my favorite tools: P/Invoke Interop Assistant
    http://blogs.msdn.com/bclteam/archive/2008/06/23/p-invoke-interop-assistant-justin-van-patten.aspx

    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
  • Monday, November 02, 2009 9:06 PMCaptain Kernel Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    I have an unmanaged structure :
    struct {
      int level;
      char user[5];
      char name[32];
     ...
    }
    that I'm attempting to marshal into managed structure:
    [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Ansi,Pack=1)]
    public struct giidbm_MddDefinition
    {
      [MarshalAs(UnmanagedType.I4),FieldOffset(0)]
      public int level;
      [MarshalAs(UnamangedType.LPStr,SizeConst=4,FieldOffset(4)]
      public string user;
      [MarshalAs(UnmanagedType.LPStr,SizeConst=31,FieldOffset(9)]
      public string name;

    ...
    }

    This bombs at every instantiation of giidbm_MddDefinition, saying that:
     
      Message="Could not load type 'giidbm_MddDefinition' from assembly 'ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 9 that is incorrectly aligned or overlapped by a non-object field."

    I've tried many different ways to marshal this, but I always end up with the above error.

    What am I missing?

    You can actually avoid marshalling here, if you are prepared to use 'unsafe' C# features:

    public unsafe struct giidbm_MddDefintion
    {
    public int     level;
    public fixed byte user[5];
    public fixed byte name[32]; 
    }

    This is an example of a blittable struct, meaning its physical organization is identical in managed and unmanaged code and the marshaller has very little work to do.

    To aid in manipulating the strings, you could add some properties:

    public unsafe struct giidbm_MddDefintion
    {
    public int level;
    private fixed byte user[5];
    private fixed byte name[32]; 

    // Treate the fixed byte buffer as a 'String'

    public string User
    {
    get { }
    set { }
    }

    // Treate the fixed byte buffer as a 'String'

    public string Name
    {
    get { }
    set { }
    }

    }

    This may or may not help you with your specific need, bit it is worth knowing about this technique sometimes and can be fast, for example you can readily pass such a struct by reference (or via a pointer) directly into unmanaged code.

    Cap'n


All Replies

  • Monday, October 26, 2009 3:43 PMMarcel Roma Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Try this:

        [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Pack = 1)]
        public struct giidbm_MddDefinition
        {
            [MarshalAs(UnmanagedType.I4), FieldOffset(0)]
            public int level;
            [MarshalAs(UnmanagedType.LPStr, SizeConst = 4), FieldOffset(4)]
            public string user;
            [MarshalAs(UnmanagedType.LPStr, SizeConst = 31), FieldOffset(8)]
            public string name;
        }

    If you really need name to start at offset 9, take a look at this: http://stackoverflow.com/questions/1190079/incorrectly-aligned-or-overlapped-by-a-non-object-field-error
  • Monday, October 26, 2009 10:37 PMnobugzMVP, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Beware that the structure alignment requested with the [StructLayout] attribute is honored both in managed code as well as for P/Invoke marshaling.  That's a problem here, a reference type like string must be aligned on an address that's a multiple of 4.  Just omit the FieldOffset attributes and use LayoutKind.Sequential.  The P/Invoke marshaller will align the unmanaged version of the struct as you want it.

    Note that your SizeConst values are wrong, it must include the terminating 0.  Make them one higher.

    Hans Passant.
  • Tuesday, October 27, 2009 8:50 AMJialiang Ge [MSFT]MSFT, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Hello Jim

    Please try this declaration:

    [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet=System.Runtime.InteropServices.CharSet.Ansi)]
    public struct giidbm_MddDefinition {
       
        /// int
        public int level;
       
        /// char[5]
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=5)]
        public string user;
       
        /// char[32]
        [System.Runtime.InteropServices.MarshalAsAttribute(System.Runtime.InteropServices.UnmanagedType.ByValTStr, SizeConst=32)]
        public string name;
    }


    It was auto-generated by one of my favorite tools: P/Invoke Interop Assistant
    http://blogs.msdn.com/bclteam/archive/2008/06/23/p-invoke-interop-assistant-justin-van-patten.aspx

    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
  • Monday, November 02, 2009 3:08 AMJialiang Ge [MSFT]MSFT, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Hello Jim

    How are you? I'm writing to check the status of the issue on your side. If you have any questions, please feel free to post here.
    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
  • Monday, November 02, 2009 9:06 PMCaptain Kernel Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    I have an unmanaged structure :
    struct {
      int level;
      char user[5];
      char name[32];
     ...
    }
    that I'm attempting to marshal into managed structure:
    [StructLayout(LayoutKind.Explicit, CharSet=CharSet.Ansi,Pack=1)]
    public struct giidbm_MddDefinition
    {
      [MarshalAs(UnmanagedType.I4),FieldOffset(0)]
      public int level;
      [MarshalAs(UnamangedType.LPStr,SizeConst=4,FieldOffset(4)]
      public string user;
      [MarshalAs(UnmanagedType.LPStr,SizeConst=31,FieldOffset(9)]
      public string name;

    ...
    }

    This bombs at every instantiation of giidbm_MddDefinition, saying that:
     
      Message="Could not load type 'giidbm_MddDefinition' from assembly 'ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 9 that is incorrectly aligned or overlapped by a non-object field."

    I've tried many different ways to marshal this, but I always end up with the above error.

    What am I missing?

    You can actually avoid marshalling here, if you are prepared to use 'unsafe' C# features:

    public unsafe struct giidbm_MddDefintion
    {
    public int     level;
    public fixed byte user[5];
    public fixed byte name[32]; 
    }

    This is an example of a blittable struct, meaning its physical organization is identical in managed and unmanaged code and the marshaller has very little work to do.

    To aid in manipulating the strings, you could add some properties:

    public unsafe struct giidbm_MddDefintion
    {
    public int level;
    private fixed byte user[5];
    private fixed byte name[32]; 

    // Treate the fixed byte buffer as a 'String'

    public string User
    {
    get { }
    set { }
    }

    // Treate the fixed byte buffer as a 'String'

    public string Name
    {
    get { }
    set { }
    }

    }

    This may or may not help you with your specific need, bit it is worth knowing about this technique sometimes and can be fast, for example you can readily pass such a struct by reference (or via a pointer) directly into unmanaged code.

    Cap'n


  • Friday, November 06, 2009 6:22 AMJialiang Ge [MSFT]MSFT, ModeratorUsers MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    Thanks Captain!

    Hello Jim, many community friends have shared their ideas in this thread. Could you please check them out? If you have any other questions, please feel free to post here.
    Regards,
    Jialiang Ge
    MSDN Subscriber Support in Forum
    If you have any feedback of our support, please contact msdnmg@microsoft.com.
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.