将字节数组封送到C#结构

我正在研究用于读取FAT32引导扇区和BPB的C#项目,问题是我正在使用编组机制将字节数组转换为自定义FAT32数据结构。 我收到一条消息错误说:无法从程序集’FAT32Management,Version = 1.0.0.0,Culture = neutral,PublicKeyToken = null’加载类型’FAT32Management.Fat32BootSector’,因为它包含偏移3处的对象字段,该字段未正确对齐或重叠由非对象字段。

我无法解决问题

这是代码

using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace FAT32Management { [StructLayout(LayoutKind.Explicit)]//, CharSet = CharSet.Ansi, Size = 96, Pack = 1)] public struct Fat32BootSector { #region Common Region With all FAT systems ///  /// First 3 Bytes of the Jump insctructions. /// Offset 0x00 ///  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] [FieldOffset(0x00)] public byte[] JumpBootInstructions; ///  /// 8 Bytes of the OemName /// Offset 0x03 ///  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(0x03)] public string OemName; #region BIOS Parameter Block (BPB) ///  /// 2 Bytes of the BytesPerSector parameter. The BIOS Paramter Block Starts here /// Offset 0x0b ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x0b)] public ushort BpbBytesPerSector; ///  /// 1 Byte containing the number of sectors per cluster. This must be a power of 2 from 1 to 128 /// Offset 0x0d ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x0d)] public byte BpbSectorsPerCluster; ///  /// 2 Bytes for the Bpb reserved sectors count, Usually 32 for FAT32. /// Offset 0x0e ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x0e)] public ushort BpbReservedSectorsCount; ///  /// 1 Byte Number of file allocation tables. Almost always 2. /// Offset 0x10 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x10)] public byte BpbFatCount; ///  /// 2 Bytes, Maximum number of root directory entries. Only used on FAT12 and FAT16 /// Offset 0x11 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x11)] public ushort BpbMaxRootDirectoriesCount; ///  /// 2 Bytes, Total sectors (if zero, use 4 byte value at offset 0x20) used only for FAT12 AND FAT16 Systems /// Offset 0x13 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x13)] public ushort BpbTotalSectors16; ///  /// 1 Byte, the media descriptor /// Offset 0x15 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x15)] public MediaDescriptor BpbMediaDescriptor; ///  /// 2 Bytes, Sectors per File Allocation Table for FAT12/FAT16 /// Offset 0x16 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x16)] public ushort BpbSectorsPerFat16; ///  /// 2 Bytes, Sectors per track /// Offset 0x18 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x18)] public ushort BpbSectorsPerTrack; ///  /// 2 Bytes Number of heads. /// Offset 0x1a ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x1a)] public ushort BpbNumberOfHeads; ///  /// 4 Bytes Hidden sectors. /// Offset 0x1c ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x1c)] public uint BpbHiddenSectors; ///  /// 4 Bytes, Total sectors (if greater than 65535; otherwise, see offset 0x13) /// Offset 0x20 ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x20)] public uint BpbTotalSectors32; #endregion #endregion #region Extended BIOS Parameter Block: FAT32 Specific ///  /// 4 Bytes for the number of sectors occupied by ONE FAT. /// Offset 0x24 ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x24)] public uint FatSize32; ///  /// 2 Bytes /// This field is only defined for FAT32 media and does not exist on FAT12 and FAT16 media. /// Bits 0-3 -- Zero-based number of active FAT. Only valid if mirroring is disabled. /// Bits 4-6 -- Reserved. /// Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. /// -- 1 means only one FAT is active; it is the one referenced in bits 0-3. /// Bits 8-15 -- Reserved. /// Offset 0x28 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x28)] public ushort ExtendedFlags; ///  /// 2 Bytes for the file system version. The high byte is major revision number. Low byte is minor revision number. /// Offset 0x2a ///  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] [FieldOffset(0x24)] public byte[] FileSystemVersion; ///  /// 4 Bytes for the first cluster number of the root directory /// Offset 0x2c ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x2c)] public uint RootDirFirstClusterNumber; ///  /// 2 Bytes for the Sector number of FS Information Sector. /// Offset 0x30 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x30)] public ushort FSInfoSectorNumber; ///  /// 2 Bytes. If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6. /// Offset 0x32 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x32)] public ushort BackupBootSectorNumber; ///  /// 12 Reserved Bytes. /// Offset 0x34 ///  [MarshalAs(UnmanagedType.ByValArray,SizeConst = 12)] [FieldOffset(0x34)] public byte[] Reserved; ///  /// 1 Byte for the physical drive number. /// Offset 0x40 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x40)] public byte PhysicalDriveNumber; ///  /// 1 Reserved byte. /// Offset 0x41 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x41)] public byte Reserved1; ///  /// 1 Byte. The boot signature /// Offset 0x42 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x42)] public byte ExtendedBootSignature; ///  /// 4 Bytes for the volume serial number. /// Offset 0x43 ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x43)] public uint VolumeID; ///  /// 11 Byte for the volume label. /// Offset 0x47 ///  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] [FieldOffset(0x47)] public string VolumeLabel; ///  /// 8 Bytes for the file system type string. /// Offset 0x52 ///  [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] [FieldOffset(0x52)] public string FileSystemType; #endregion ///  /// Gets the boot sector for the specified drive. /// The drive letter must have this pattern X:  ///  /// The  /// The boot sector for the specified drive. public static Fat32BootSector GetBootSectorForDrive(string driveLetter) { byte[] bootSector = new byte[Marshal.SizeOf(typeof(Fat32BootSector))]; string drive = @"\\.\" + driveLetter; IntPtr hardDiskPointer = SystemIOCalls.OpenFile(drive); // Seeks to the start of the partition SystemIOCalls.SeekAbsolute(hardDiskPointer, 0, 0); // Read the first reserved sector of the drive data (Boot Sector) // The data should be read with a chunk of 512 X byte. SystemIOCalls.ReadBytes(hardDiskPointer, bootSector, 512); SystemIOCalls.CloseHandle(hardDiskPointer); // Marshaling the bytes array to a valid struct GCHandle pinnedInfos = GCHandle.Alloc(bootSector, GCHandleType.Pinned); var infos = (Fat32BootSector)Marshal.PtrToStructure(pinnedInfos.AddrOfPinnedObject(), typeof(Fat32BootSector)); pinnedInfos.Free(); return infos; } } } 

请帮忙!

显式结构布局和FieldOffsetAttribute适用于编组,还适用于CLR使用的运行时布局。 如果在不安全的代码中使用struct类型定义,或者根据重叠数据做出其他假设(即有效地创建C样式的union类型),这一点尤为重要。

作为混淆显式字段布局的这两种用法的副作用,将禁止违反CLR类型系统的布局:重叠对象引用可以允许在运行过程中构造对任意数据的对象引用,而未对齐的对象引用会影响该种类GC实现可以使用的优化。

我相信你需要回归使用固定字节数组作为字符串数据,并使用Encoding类自行解码。 例如:

 [FieldOffset(0x03)] public fixed byte OemName[8] 

fixed字段需要不安全的上下文,并且需要一次复制一个元素,或者在不安全的代码中作为例如byte*处理。

另一种方法是使用手动内存分配( Marhsal.AllocHGlobalbyte[] )并将数据视为blob,可能使用BinaryReader读取。

谢谢barry,我刚刚修改了它正在运行的代码

 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; namespace FAT32Management { [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi, Size = 96, Pack = 1)] public unsafe struct Fat32BootSector { #region Common Region With all FAT systems ///  /// First 3 Bytes of the Jump insctructions. /// Offset 0x00 ///  //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] [FieldOffset(0x00)] public fixed byte JumpBootInstructions[3]; ///  /// 8 Bytes of the OemName /// Offset 0x03 ///  [FieldOffset(0x03)] public fixed char OemName[8]; #region BIOS Parameter Block (BPB) ///  /// 2 Bytes of the BytesPerSector parameter. The BIOS Paramter Block Starts here /// Offset 0x0b ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x0b)] public ushort BpbBytesPerSector; ///  /// 1 Byte containing the number of sectors per cluster. This must be a power of 2 from 1 to 128 /// Offset 0x0d ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x0d)] public byte BpbSectorsPerCluster; ///  /// 2 Bytes for the Bpb reserved sectors count, Usually 32 for FAT32. /// Offset 0x0e ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x0e)] public ushort BpbReservedSectorsCount; ///  /// 1 Byte Number of file allocation tables. Almost always 2. /// Offset 0x10 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x10)] public byte BpbFatCount; ///  /// 2 Bytes, Maximum number of root directory entries. Only used on FAT12 and FAT16 /// Offset 0x11 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x11)] public ushort BpbMaxRootDirectoriesCount; ///  /// 2 Bytes, Total sectors (if zero, use 4 byte value at offset 0x20) used only for FAT12 AND FAT16 Systems /// Offset 0x13 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x13)] public ushort BpbTotalSectors16; ///  /// 1 Byte, the media descriptor /// Offset 0x15 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x15)] public MediaDescriptor BpbMediaDescriptor; ///  /// 2 Bytes, Sectors per File Allocation Table for FAT12/FAT16 /// Offset 0x16 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x16)] public ushort BpbSectorsPerFat16; ///  /// 2 Bytes, Sectors per track /// Offset 0x18 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x18)] public ushort BpbSectorsPerTrack; ///  /// 2 Bytes Number of heads. /// Offset 0x1a ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x1a)] public ushort BpbNumberOfHeads; ///  /// 4 Bytes Hidden sectors. /// Offset 0x1c ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x1c)] public uint BpbHiddenSectors; ///  /// 4 Bytes, Total sectors (if greater than 65535; otherwise, see offset 0x13) /// Offset 0x20 ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x20)] public uint BpbTotalSectors32; #endregion #endregion #region Extended BIOS Parameter Block: FAT32 Specific ///  /// 4 Bytes for the number of sectors occupied by ONE FAT. /// Offset 0x24 ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x24)] public uint FatSize32; ///  /// 2 Bytes /// This field is only defined for FAT32 media and does not exist on FAT12 and FAT16 media. /// Bits 0-3 -- Zero-based number of active FAT. Only valid if mirroring is disabled. /// Bits 4-6 -- Reserved. /// Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs. /// -- 1 means only one FAT is active; it is the one referenced in bits 0-3. /// Bits 8-15 -- Reserved. /// Offset 0x28 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x28)] public ushort ExtendedFlags; ///  /// 2 Bytes for the file system version. The high byte is major revision number. Low byte is minor revision number. /// Offset 0x2a ///  [FieldOffset(0x2a)] public fixed byte FileSystemVersion[2]; ///  /// 4 Bytes for the first cluster number of the root directory /// Offset 0x2c ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x2c)] public uint RootDirFirstClusterNumber; ///  /// 2 Bytes for the Sector number of FS Information Sector. /// Offset 0x30 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x30)] public ushort FSInfoSectorNumber; ///  /// 2 Bytes. If non-zero, indicates the sector number in the reserved area of the volume of a copy of the boot record. Usually 6. /// Offset 0x32 ///  [MarshalAs(UnmanagedType.U2)] [FieldOffset(0x32)] public ushort BackupBootSectorNumber; ///  /// 12 Reserved Bytes. /// Offset 0x34 ///  [FieldOffset(0x34)] public fixed byte Reserved[12]; ///  /// 1 Byte for the physical drive number. /// Offset 0x40 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x40)] public byte PhysicalDriveNumber; ///  /// 1 Reserved byte. /// Offset 0x41 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x41)] public byte Reserved1; ///  /// 1 Byte. The boot signature /// Offset 0x42 ///  [MarshalAs(UnmanagedType.U1)] [FieldOffset(0x42)] public byte ExtendedBootSignature; ///  /// 4 Bytes for the volume serial number. /// Offset 0x43 ///  [MarshalAs(UnmanagedType.U4)] [FieldOffset(0x43)] public uint VolumeID; ///  /// 11 Byte for the volume label. /// Offset 0x47 ///  [FieldOffset(0x47)] public fixed char VolumeLabel[11]; ///  /// 8 Bytes for the file system type string. /// Offset 0x52 ///  [FieldOffset(0x52)] public fixed char FileSystemType[8]; #endregion ///  /// Gets the boot sector for the specified drive. /// The drive letter must have this pattern X:  ///  /// The  /// The boot sector for the specified drive. public static Fat32BootSector GetBootSectorForDrive(string driveLetter) { byte[] bootSector = new byte[Marshal.SizeOf(typeof(Fat32BootSector))]; string drive = @"\\.\" + driveLetter; IntPtr hardDiskPointer = SystemIOCalls.OpenFile(drive); // Seeks to the start of the partition SystemIOCalls.SeekAbsolute(hardDiskPointer, 0, 0); // Read the first reserved sector of the drive data (Boot Sector) // The data should be read with a chunk of 512 X byte. SystemIOCalls.ReadBytes(hardDiskPointer, bootSector, 512); SystemIOCalls.CloseHandle(hardDiskPointer); // Marshaling the bytes array to a valid struct GCHandle pinnedInfos = GCHandle.Alloc(bootSector, GCHandleType.Pinned); var infos = (Fat32BootSector)Marshal.PtrToStructure(pinnedInfos.AddrOfPinnedObject(), typeof(Fat32BootSector)); pinnedInfos.Free(); return infos; } } }