Ich grüble bereits einen ganzen Nachmittag über einem Problem.
Anbei der Code:
Public Class Form1
' ****** Strukturen für die Iconfile-Datei ******
<StructLayout(LayoutKind.Sequential)> _
Private Structure IconHeader
Dim ihReserved As UInt16
Dim ihType As UInt16
Dim ihCount As UInt16
End Structure
<StructLayout(LayoutKind.Sequential)> _
Private Structure IconEntry
Dim ieWidth As Byte ' Breite in Pixeln
Dim ieHeight As Byte ' Höhe in Pixeln
Dim ieColorCount As Byte ' Anzahl der Farben (bei 256 Farben -->
0)
Dim ieReserved As Byte ' =0
Dim iePlanes As UInt16 ' Anzahl der Farbplanes =1, bei 16
Farben=0
Dim ieBitCount As UInt16 ' Bits pro Pixel (32 bei 256 Farben, 0
bei 16 Farben)
Dim ieBytesInRes As UInt32
' = Länge BitMapHeader (=40)
' + (bei 256 Farben Anzahl Pixel * 4,
bei 16 Farben Anzahl Pixel\2)(XOR)
' + 128 Bytes TransparenzInfos (ANF)
Dim ieImageOffset As UInt32 ' Länge IconHeader (=6) + Länge
IconEntry (=16) = 22
End Structure
' ****** Struktur myStruct ******
<StructLayout(LayoutKind.Sequential)> _
Private Structure myStruct
Dim Data1 As UInt32
Dim Data2 As UInt16
Dim Data3 As UInt16
Dim data4 As UInt16
End Structure
Public Structure Guid
Dim data1 As Integer
Dim data2 As Short
Dim data3 As Short
<VBFixedArray(7)> Dim data4() As Byte
' aus http://vbcity.com/forums/t/133014.aspx
' upgrade_todo: "initialize" must be called to initialize instances of
this
' structure. click for more:
'ms-help://ms.vscc.v80/dv_commoner/local/redirect.htm?keyword="b4bff9e0-8631-45cf-910e-62ab3970f27b"'
Public Sub initialize()
ReDim data4(7)
End Sub
End Structure
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim IconHeader As New IconHeader
Dim IconEntry As New IconEntry
Dim myStruct As New myStruct
Dim Guid As New Guid
Trace.WriteLine("Marshal.SizeOf(IconHeader): " &
Marshal.SizeOf(IconHeader))
Trace.WriteLine("Marshal.SizeOf(IconEntry): " &
Marshal.SizeOf(IconEntry))
Trace.WriteLine("Marshal.SizeOf(myStruct): " &
Marshal.SizeOf(myStruct))
Trace.WriteLine("Marshal.SizeOf(Guid): " & Marshal.SizeOf(Guid))
End Sub
End Class
Ergebnis:
Marshal.SizeOf(IconHeader): 6
Marshal.SizeOf(IconEntry): 16
Marshal.SizeOf(myStruct): 12
Marshal.SizeOf(Guid): 12
Ich verstehe das alles nicht wirklich.
Hat jemand dafür eine Erklärung?
Warum ist myStruct 12 Bytes lang?
Warum ist Guid nicht 15 Bytes lang?
Die Längen der restlichen Strukturen stimmen.
Kann ich die Länge 10 für myStruct irgendwie erzwingen?
Gibt es da ev. einen Bug?
Danke an alle,
Wolfgang
VBFixedArray hat keine Auswirkung auf den Marshaller
sondern nur auf die VB-eigenen Dateioperationen
wie FilePut/FileGet.
Verwende stattdessen MarshalAs(ByValArray) mit sizeconst := 8
Ich musste auch erst lange suchen, obwohl ich meinte,
es verstanden zu haben:
Man muss immer zwei hintereinanderliegende Objekte im RAM betrachten:
- Bei "IconHeader" sind es alles Uint16. Somit kann das
nächste Objekt vom selben Typ direkt hintendran
abgelegt werden. => Länge=6
- Bei "myStruct" würde als nächstes wieder ein Uint32
folgen. Somit muss auf 4-Byte-Grenze aufgerundet werden => Länge=12
Dadurch ist gewährleistet, dass die Felder immer an
Vielfachen der Größe des Typs abgelegt sind.
> Warum ist Guid nicht 15 Bytes lang?
s.o.
Selbst wenn VBFixedArray eine Auswirkung hätte, bedeutet
die 7 die obere Grenze, also 0-7 sind 8 Elemente, somit Länge=16.
> Die Längen der restlichen Strukturen stimmen.
>
> Kann ich die Länge 10 für myStruct irgendwie erzwingen?
> Gibt es da ev. einen Bug?
Mit
<StructLayout(LayoutKind.Sequential, pack:=1)> _
Wie aber schon in der Hilfe steht: Wenn das nicht unbedingt sein
muss, sollte man die Standardausrichtung belassen weil sonst
die Performance darunter leiden könnte. In deinem Fall beginnt
Data1 dann nicht mehr immer an einer 4-Byte-Grenze wenn
die Länge 10 ist.
--
Armin
ich hab ᅵbrigens mit folgendem Code experimentiert.
Du kannst mit den Feldern der Struktur und der
Pack-Eigenschaft "spielen" und den restlichen Code
beibehalten.
Imports System.Linq
Imports System.Runtime.InteropServices
Public Class Main
<StructLayout(LayoutKind.Sequential, pack:=2)> _
Private Structure myStruct
Dim Data1 As UInt32
Dim Data2 As UInt16
Dim Data3 As UInt16
Dim data4 As UInt16
Dim data5 As Byte
End Structure
Shared Sub main()
Dim t = GetType(myStruct)
Dim q = From field In t.GetFields(Reflection.BindingFlags.Instance Or Reflection.BindingFlags.Public) _
Let offset = Marshal.OffsetOf(t, field.Name).ToInt64, size = Marshal.SizeOf(field.FieldType) _
Order By offset _
Select offset & " - " & (offset + size - 1) & " " & field.FieldType.Name & " " & field.Name
Dim sw As New IO.StringWriter
sw.Write("Lᅵnge: ")
sw.WriteLine(Marshal.SizeOf(t))
sw.WriteLine()
q.ToList.ForEach(AddressOf sw.WriteLine)
MsgBox(sw.ToString)
End Sub
End Class
--
Armin
Danke.
Es ist ewig her, daß ich mich mit dem Problem des Alignements
an Wortgrenzen herumgeschlagen habe. Vor vielen Jahren waren es noch 16
Bits, jetzt sind es 32 und bald 64 Bits.
Ich versuchte die Strukturen zu abstrahieren, um das Problem
herauszuarbeiten.
Denn eigentlich handelt es sich um solche für die API-Programmierung.
Das pack=2 war mir völlig unbekannt.
Und da ich dachte, die Möglichkeiten ausgeschöpft zu haben suchte ich nicht
weiter,
sondern versuchte durch Vergleich der Varianten eine Lösung zu finden
Bei den Strukturen für die Icons habe ich einfach nur Glück gehabt.
Naja, braucht man manchmal auch.
Wolfgang