Results 1 to 18 of 18

Thread: [RESOLVED] A couple of questions about structures

  1. #1

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Resolved [RESOLVED] A couple of questions about structures

    Hi, I have this structure:

    Code:
    <StructLayout(LayoutKind.Sequential)>
    Public Structure ContFileHeader
        Public MagicID As UInteger    ' 4 bytes
        Public MajorVer As Byte       ' 1 byte
        Public MinorVer As Byte       ' 1 byte
        Public Reserved1 As UInt64    ' 8 bytes
        Public Reserved2 As UInt64    ' 8 bytes
        Public FTType As Byte         ' 1 byte
    End Structure
    4 + 1 + 1 + 8 + 8 +1 = 23 bytes

    Why then:
    Code:
    Dim header As New ContFileHeader
    Debug.WriteLine(Marshal.SizeOf(ContFileHeader))
    gives me 32 ?

    Is there a way go get 23 as the size of this structure?

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: A couple of questions about structures

    I think you'll find that the Byte fields are allocated 4 bytes of managed memory each. As the doco says:
    The size returned is the size of the unmanaged type. The unmanaged and managed sizes of an object can differ.
    I'm not aware of any specific method for getting the size you want. One option would be to get the types of each file and get the SizeOf each, then sum them.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: A couple of questions about structures

    Well, ok, let's suppose I have a structure like this (I have many, in fact)
    Is there any way I can do something like this:

    Code:
    Function SizeOf(structure As Object)
        ' For Each field in structure
        '    calc size
        ' Next
        ' return size
    End Function

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: A couple of questions about structures

    This seems to work:
    vb.net Code:
    1. Public Shared Function SizeOf(Of T As Structure)(s As T) As Integer
    2.     'Include all public and non-public instance fields in the calculation.
    3.     Dim flags = BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic
    4.  
    5.     Return s.GetType().GetFields(flags).Sum(Function(fi) Marshal.SizeOf(fi.FieldType))
    6. End Function
    The issue there is that, if a field is a complex type, it would show the same issue as before, so you might need to to throw some recursion in there. I've limited that method to structures with a generic type constraint but that might not really be worthwhile.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  5. #5

  6. #6
    Cumbrian Milk's Avatar
    Join Date
    Jan 2007
    Location
    0xDEADBEEF
    Posts
    2,448

    Re: [RESOLVED] A couple of questions about structures

    I don't know if it will help but you can use <StructLayout(LayoutKind.Explicit)>

    The byte at the end will still be padded, if you could just rearrange it a little....
    Code:
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure ContFileHeader
        <FieldOffset(0)>Public MagicID As UInteger    ' 4 bytes
        <FieldOffset(4)>Public MajorVer As Byte       ' 1 byte
        <FieldOffset(5)>Public MinorVer As Byte       ' 1 byte
        <FieldOffset(6)>Public FTType As Byte         ' 1 byte
        <FieldOffset(7)>Public Reserved1 As UInt64    ' 8 bytes
        <FieldOffset(15)>Public Reserved2 As UInt64    ' 8 bytes
    End Structure
    I would be inclined to add another byte so that the last two fields align.
    W o t . S i g

  7. #7
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,222

    Re: [RESOLVED] A couple of questions about structures

    Quote Originally Posted by Milk View Post
    I don't know if it will help but you can use <StructLayout(LayoutKind.Explicit)>

    The byte at the end will still be padded, if you could just rearrange it a little....
    Code:
    <StructLayout(LayoutKind.Explicit)> _
    Public Structure ContFileHeader
        <FieldOffset(0)>Public MagicID As UInteger    ' 4 bytes
        <FieldOffset(4)>Public MajorVer As Byte       ' 1 byte
        <FieldOffset(5)>Public MinorVer As Byte       ' 1 byte
        <FieldOffset(6)>Public FTType As Byte         ' 1 byte
        <FieldOffset(7)>Public Reserved1 As UInt64    ' 8 bytes
        <FieldOffset(15)>Public Reserved2 As UInt64    ' 8 bytes
    End Structure
    I would be inclined to add another byte so that the last two fields align.
    That is almost certainly a better way to handle structures you have defined yourself. If you are using existing types though you may still have to resort to the divide and conquer method.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  8. #8
    PowerPoster Evil_Giraffe's Avatar
    Join Date
    Aug 2002
    Location
    Suffolk, UK
    Posts
    2,555

    Re: [RESOLVED] A couple of questions about structures

    Is there a particular reason you want the 'managed size'? I'm confused as to what use it might be, when it doesn't really mean much. If you're concerned about the size of the struct, it's the actual size in memory that is important, no? And if you're wondering about unmanaged interop issues, again, you'd need to look at it from the unmanaged point of view.

    (This is a serious querstion, btw. I really am interested in the answer)

  9. #9
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: [RESOLVED] A couple of questions about structures

    Here is my version of jmc's function:-
    vbnet Code:
    1. '
    2.     Public Function SizeOfWithoutPadding(Of T As Structure)(ByVal s As T) As Integer
    3.         Return SizeOfWithoutPadding(s.GetType)
    4.     End Function
    5.  
    6.     Public Function SizeOfWithoutPadding(ByVal struct As Type) As Integer
    7.  
    8.  
    9.         'Include all public and non-public instance fields in the calculation.
    10.         'Dim struct As Type = GetType(T)
    11.         Dim flags = BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic
    12.         Dim fields = struct.GetFields(flags)
    13.         Dim sz As Integer = 0
    14.  
    15.         For Each Fi As FieldInfo In fields
    16.  
    17.             If Fi.FieldType.IsPrimitive Then
    18.                 sz += Marshal.SizeOf(Fi.FieldType)
    19.             Else
    20.  
    21.                 If Fi.FieldType.IsClass Then Throw New NotSupportedException("Reference types are not supported")
    22.  
    23.                 Dim inst As Object = Activator.CreateInstance(Fi.FieldType)
    24.  
    25.                 sz += SizeOfWithoutPadding(inst.GetType)
    26.             End If
    27.  
    28.         Next
    29.         Return sz
    30.     End Function
    This one can handle nested Structures but no reference types embedded within the Structure are allowed.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  10. #10

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: [RESOLVED] A couple of questions about structures

    I'm still experiencing some difficulties.
    Basically, I need this to read/write structured data from a file:
    vb Code:
    1. Public Shared Function StructToByteArray(Of T As Structure)(ByVal struct As T) As Byte()
    2.         Dim size As Integer = Marshal.SizeOf(struct)
    3.         Dim bytes(size - 1) As Byte '
    4.         Dim gc_handle As GCHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned)
    5.         Marshal.StructureToPtr(struct, gc_handle.AddrOfPinnedObject(), False)
    6.         gc_handle.Free()
    7.         Return bytes
    8.     End Function
    9.  
    10.     Public Shared Function ByteArrayToStruct(Of T As Structure)(ByVal bytes As Byte()) As T
    11.         Dim gc_handle = GCHandle.Alloc(bytes, GCHandleType.Pinned)
    12.         Dim ptr As IntPtr = gc_handle.AddrOfPinnedObject()
    13.         Dim struct As T = CType(Marshal.PtrToStructure(ptr, GetType(T)), T)
    14.         gc_handle.Free()
    15.         Return struct
    16.     End Function

    The problem is with the Marshal.SizeOf vs this SizeOf:
    Code:
    Public Shared Function SizeOf(Of T As Structure)(ByVal struct As T) As Integer
            'Include all public and non-public instance fields in the calculation.
            Dim flags = BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic
            Return struct.GetType().GetFields(flags).Sum(Function(fi) Marshal.SizeOf(fi.FieldType))
    End Function
    My struct.FTType field is set to 1 (it must be 1)

    If I use Marshal.SizeOf I get the 32-byte array instead of 23-byte
    If I use custom SizeOf I get the 23 byte arrray, but it's last element (FTType) is zero instead of one.


    I wrote this function that partially resolves the problem:
    vb Code:
    1. Public Shared Function SerializeStruct(Of T As Structure)(ByVal struct As T) As Byte()
    2.         Dim flags = BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic
    3.         Dim fields() As FieldInfo = struct.GetType().GetFields(flags)
    4.         Dim ms As New MemoryStream()
    5.         For Each fi As FieldInfo In fields
    6.             Dim value As Object = fi.GetValue(struct)
    7.             Dim b(Marshal.SizeOf(fi.FieldType) - 1) As Byte
    8.             Dim gc_handle As GCHandle = GCHandle.Alloc(value, GCHandleType.Pinned)
    9.             Dim ptr As IntPtr = gc_handle.AddrOfPinnedObject()
    10.             For i As Integer = 0 To b.Length - 1
    11.                 b(i) = Marshal.ReadByte(ptr, i)
    12.             Next
    13.             ms.Write(b, 0, b.Length)
    14.             gc_handle.Free()
    15.         Next
    16.         Return ms.ToArray()
    17. End Function

    But now I just can't read the 23 byte array back into the structure above.

  11. #11

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: [RESOLVED] A couple of questions about structures

    This function doesn't work. All fields in the struct passed by reference remain unchanged (zeroes)
    Perhaps, anybody knows what's been done wrong here?

    vb Code:
    1. Public Shared Sub DeserializeStruct(Of T As Structure)(ByVal data As Byte(), ByRef struct As T)
    2.         If data.Length <> SizeOf(struct) Then
    3.             Throw New ArgumentException("Data length is not equal to the targeted structure length.")
    4.         End If
    5.         Dim flags = BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic
    6.         Dim fields() As FieldInfo = struct.GetType().GetFields(flags)
    7.         Dim pos As Integer = 0
    8.         For Each fi As FieldInfo In fields
    9.             Dim value As Object = fi.GetValue(struct)
    10.             Dim FieldSize As Integer = Marshal.SizeOf(fi.FieldType)
    11.             Dim gc_handle As GCHandle = GCHandle.Alloc(value, GCHandleType.Pinned)
    12.             Dim ptr As IntPtr = gc_handle.AddrOfPinnedObject()
    13.             Marshal.Copy(data, pos, ptr, FieldSize)
    14.             pos += FieldSize
    15.             fi.SetValue(struct, value)
    16.             gc_handle.Free()
    17.         Next
    18.     End Sub

    I stepped through this and value variable changes after Marshal.Copy, but the structure field after
    fi.SetValue(struct, value) - does not.

    This task is so easily accomplished in C++, even in QuickBasic, but not in VB

  12. #12
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: [RESOLVED] A couple of questions about structures

    SetValue does not work with Structures because the are value types.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  13. #13

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: [RESOLVED] A couple of questions about structures

    Quote Originally Posted by Niya View Post
    SetValue does not work with Structures because the are value types.
    No workaround then?

  14. #14
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: [RESOLVED] A couple of questions about structures

    Well I saw a couple people elsewhere suggest that you can box the structure before using SetValue Eg.
    vbnet Code:
    1. '
    2. Dim v As MyStruct
    3. Dim boxed As Object = v
    4.  
    5. FI.SetValue(boxed, "value")
    But when I tried this it didn't work. I'm using .Net 3.5 with VS2008 so maybe it works with a later version. If you have .Net 4 or later and VS2010 you should try it there.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  15. #15
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: [RESOLVED] A couple of questions about structures

    Or you could simply use a Class instead of a Structure. Best workaround I can think of.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  16. #16
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: [RESOLVED] A couple of questions about structures

    I just tested your code with a Class and it works perfectly.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

  17. #17

    Thread Starter
    PowerPoster cicatrix's Avatar
    Join Date
    Dec 2009
    Location
    Moscow, Russia
    Posts
    3,654

    Re: [RESOLVED] A couple of questions about structures

    Thanks, I'll consider it. By the way - does it enumerate the fields in the as-defined order?

  18. #18
    Angel of Code Niya's Avatar
    Join Date
    Nov 2011
    Posts
    9,017

    Re: [RESOLVED] A couple of questions about structures

    Yes it does.
    Treeview with NodeAdded/NodesRemoved events | BlinkLabel control | Calculate Permutations | Object Enums | ComboBox with centered items | .Net Internals article(not mine) | Wizard Control | Understanding Multi-Threading | Simple file compression | Demon Arena

    Copy/move files using Windows Shell | I'm not wanted

    C++ programmers will dismiss you as a cretinous simpleton for your inability to keep track of pointers chained 6 levels deep and Java programmers will pillory you for buying into the evils of Microsoft. Meanwhile C# programmers will get paid just a little bit more than you for writing exactly the same code and VB6 programmers will continue to whitter on about "footprints". - FunkyDexter

    There's just no reason to use garbage like InputBox. - jmcilhinney

    The threads I start are Niya and Olaf free zones. No arguing about the benefits of VB6 over .NET here please. Happiness must reign. - yereverluvinuncleber

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width