id:n7shi:20110420の続きです。フィールドを1つずつ指定して書き込むのは面倒なので、リフレクションで自動化します。
Function writeFields%(image As Byte(), pos%, obj As Object) Dim t = obj.GetType For Each f In t.GetFields Dim v = f.GetValue(obj) If TypeOf v Is Byte Then image(pos) = CByte(v) pos += 1 ElseIf TypeOf v Is UShort Then pos = write16(image, pos, CUShort(v)) ElseIf TypeOf v Is Integer Then pos = write32(image, pos, CInt(v)) ElseIf TypeOf v Is Byte() Then pos = writebin(image, pos, CType(v, Byte())) ElseIf TypeOf v Is UShort() Then pos = write16s(image, pos, CType(v, UShort())) ElseIf TypeOf v Is Integer() Then pos = write32s(image, pos, CType(v, Integer())) Else Throw New ArgumentException("不明な型: ", t.FullName) End If Next Return pos End Function
obj.GetType.GetFieldsでobjのパブリックフィールドが取得できます。GetValueで値を取り出しながら、型ごとに処理を振り分けて書き込みます。これによりクラスはフィールドだけを定義すれば済みます。
Public Class IMAGE_DOS_HEADER Public e_magic, e_cblp, e_cp, e_crlc, e_cparhdr, e_minalloc, e_maxalloc, e_ss, e_sp, e_csum, e_ip, e_cs, e_lfarlc, e_ovno, e_res(3), e_oemid, e_oeminfo, e_res2(9) As UShort Public e_lfanew% End Class Public Class IMAGE_FILE_HEADER Public Machine, NumberOfSections As UShort Public TimeDateStamp, PointerToSymbolTable, NumberOfSymbols As Integer Public SizeOfOptionalHeader, Characteristics As UShort End Class
書き込む側ではwriteFieldsを呼ぶだけです。
Dim dosh = New IMAGE_DOS_HEADER With { .e_magic = conv16("MZ"), .e_cblp = &H90, .e_cp = 3, .e_cparhdr = 4, .e_maxalloc = &HFFFF, .e_sp = &HB8, .e_lfarlc = &H40, .e_lfanew = &H80} writeFields(image, 0, dosh) Dim fh = New IMAGE_FILE_HEADER With { .Machine = &H14C, .NumberOfSections = 1, .SizeOfOptionalHeader = &HE0, .Characteristics = &H102} writeFields(image, &H84, fh)
だいぶC++のコードに近付きました。Win32では構造体の中に構造体が入っています。次回はこれに対応します。