我正在研究用于读取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
/// <summary>
/// First 3 Bytes of the Jump insctructions.
/// Offset 0x00
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
[FieldOffset(0x00)]
public byte[] JumpBootInstructions;
/// <summary>
/// 8 Bytes of the OemName
/// Offset 0x03
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
[FieldOffset(0x03)]
public string OemName;
#region BIOS Parameter Block (BPB)
/// <summary>
/// 2 Bytes of the BytesPerSector parameter. The BIOS Paramter Block Starts here
/// Offset 0x0b
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x0b)]
public ushort BpbBytesPerSector;
/// <summary>
/// 1 Byte containing the number of sectors per cluster. This must be a power of 2 from 1 to 128
/// Offset 0x0d
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x0d)]
public byte BpbSectorsPerCluster;
/// <summary>
/// 2 Bytes for the Bpb reserved sectors count, Usually 32 for FAT32.
/// Offset 0x0e
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x0e)]
public ushort BpbReservedSectorsCount;
/// <summary>
/// 1 Byte Number of file allocation tables. Almost always 2.
/// Offset 0x10
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x10)]
public byte BpbFatCount;
/// <summary>
/// 2 Bytes, Maximum number of root directory entries. Only used on FAT12 and FAT16
/// Offset 0x11
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x11)]
public ushort BpbMaxRootDirectoriesCount;
/// <summary>
/// 2 Bytes, Total sectors (if zero, use 4 byte value at offset 0x20) used only for FAT12 AND FAT16 Systems
/// Offset 0x13
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x13)]
public ushort BpbTotalSectors16;
/// <summary>
/// 1 Byte, the media descriptor
/// Offset 0x15
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x15)]
public MediaDescriptor BpbMediaDescriptor;
/// <summary>
/// 2 Bytes, Sectors per File Allocation Table for FAT12/FAT16
/// Offset 0x16
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x16)]
public ushort BpbSectorsPerFat16;
/// <summary>
/// 2 Bytes, Sectors per track
/// Offset 0x18
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x18)]
public ushort BpbSectorsPerTrack;
/// <summary>
/// 2 Bytes Number of heads.
/// Offset 0x1a
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x1a)]
public ushort BpbNumberOfHeads;
/// <summary>
/// 4 Bytes Hidden sectors.
/// Offset 0x1c
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x1c)]
public uint BpbHiddenSectors;
/// <summary>
/// 4 Bytes, Total sectors (if greater than 65535; otherwise, see offset 0x13)
/// Offset 0x20
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x20)]
public uint BpbTotalSectors32;
#endregion
#endregion
#region Extended BIOS Parameter Block: FAT32 Specific
/// <summary>
/// 4 Bytes for the number of sectors occupied by ONE FAT.
/// Offset 0x24
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x24)]
public uint FatSize32;
/// <summary>
/// 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
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x28)]
public ushort ExtendedFlags;
/// <summary>
/// 2 Bytes for the file system version. The high byte is major revision number. Low byte is minor revision number.
/// Offset 0x2a
/// </summary>
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
[FieldOffset(0x24)]
public byte[] FileSystemVersion;
/// <summary>
/// 4 Bytes for the first cluster number of the root directory
/// Offset 0x2c
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x2c)]
public uint RootDirFirstClusterNumber;
/// <summary>
/// 2 Bytes for the Sector number of FS Information Sector.
/// Offset 0x30
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x30)]
public ushort FSInfoSectorNumber;
/// <summary>
/// 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
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x32)]
public ushort BackupBootSectorNumber;
/// <summary>
/// 12 Reserved Bytes.
/// Offset 0x34
/// </summary>
[MarshalAs(UnmanagedType.ByValArray,SizeConst = 12)]
[FieldOffset(0x34)]
public byte[] Reserved;
/// <summary>
/// 1 Byte for the physical drive number.
/// Offset 0x40
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x40)]
public byte PhysicalDriveNumber;
/// <summary>
/// 1 Reserved byte.
/// Offset 0x41
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x41)]
public byte Reserved1;
/// <summary>
/// 1 Byte. The boot signature
/// Offset 0x42
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x42)]
public byte ExtendedBootSignature;
/// <summary>
/// 4 Bytes for the volume serial number.
/// Offset 0x43
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x43)]
public uint VolumeID;
/// <summary>
/// 11 Byte for the volume label.
/// Offset 0x47
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)]
[FieldOffset(0x47)]
public string VolumeLabel;
/// <summary>
/// 8 Bytes for the file system type string.
/// Offset 0x52
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)]
[FieldOffset(0x52)]
public string FileSystemType;
#endregion
/// <summary>
/// Gets the boot sector for the specified drive.
/// <remarks>The drive letter must have this pattern X: </remarks>
/// </summary>
/// <param name="driveLetter">The </param>
/// <returns>The boot sector for the specified drive.</returns>
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;
}
}
}
请帮忙!
答案 0 :(得分:6)
显式结构布局和FieldOffsetAttribute
不仅适用于编组,还适用于CLR使用的运行时布局。如果您在不安全的代码中使用struct
类型定义,或者根据重叠数据做出其他假设(即有效地创建C风格的union
类型),这一点尤为重要。
作为混淆显式字段布局的这两种用法的副作用,将禁止违反CLR类型系统的布局:重叠对象引用可以允许在运行过程中构造对任意数据的对象引用,而未对齐的对象引用影响GC实现可以使用的优化类型。
我相信您需要回归使用固定字节数组作为字符串数据,并使用Encoding
类自行解码。例如:
[FieldOffset(0x03)]
public fixed byte OemName[8]
fixed
字段需要不安全的上下文,并且需要一次复制一个元素,或者将其视为例如不安全代码中的byte*
。
另一种方法是使用手动内存分配(Marhsal.AllocHGlobal
或byte[]
)并将数据视为blob,可能使用BinaryReader
读取。
答案 1 :(得分:1)
谢谢巴里, 我刚刚修改了它现在正在运行的代码
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
/// <summary>
/// First 3 Bytes of the Jump insctructions.
/// Offset 0x00
/// </summary>
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
[FieldOffset(0x00)]
public fixed byte JumpBootInstructions[3];
/// <summary>
/// 8 Bytes of the OemName
/// Offset 0x03
/// </summary>
[FieldOffset(0x03)]
public fixed char OemName[8];
#region BIOS Parameter Block (BPB)
/// <summary>
/// 2 Bytes of the BytesPerSector parameter. The BIOS Paramter Block Starts here
/// Offset 0x0b
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x0b)]
public ushort BpbBytesPerSector;
/// <summary>
/// 1 Byte containing the number of sectors per cluster. This must be a power of 2 from 1 to 128
/// Offset 0x0d
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x0d)]
public byte BpbSectorsPerCluster;
/// <summary>
/// 2 Bytes for the Bpb reserved sectors count, Usually 32 for FAT32.
/// Offset 0x0e
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x0e)]
public ushort BpbReservedSectorsCount;
/// <summary>
/// 1 Byte Number of file allocation tables. Almost always 2.
/// Offset 0x10
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x10)]
public byte BpbFatCount;
/// <summary>
/// 2 Bytes, Maximum number of root directory entries. Only used on FAT12 and FAT16
/// Offset 0x11
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x11)]
public ushort BpbMaxRootDirectoriesCount;
/// <summary>
/// 2 Bytes, Total sectors (if zero, use 4 byte value at offset 0x20) used only for FAT12 AND FAT16 Systems
/// Offset 0x13
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x13)]
public ushort BpbTotalSectors16;
/// <summary>
/// 1 Byte, the media descriptor
/// Offset 0x15
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x15)]
public MediaDescriptor BpbMediaDescriptor;
/// <summary>
/// 2 Bytes, Sectors per File Allocation Table for FAT12/FAT16
/// Offset 0x16
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x16)]
public ushort BpbSectorsPerFat16;
/// <summary>
/// 2 Bytes, Sectors per track
/// Offset 0x18
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x18)]
public ushort BpbSectorsPerTrack;
/// <summary>
/// 2 Bytes Number of heads.
/// Offset 0x1a
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x1a)]
public ushort BpbNumberOfHeads;
/// <summary>
/// 4 Bytes Hidden sectors.
/// Offset 0x1c
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x1c)]
public uint BpbHiddenSectors;
/// <summary>
/// 4 Bytes, Total sectors (if greater than 65535; otherwise, see offset 0x13)
/// Offset 0x20
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x20)]
public uint BpbTotalSectors32;
#endregion
#endregion
#region Extended BIOS Parameter Block: FAT32 Specific
/// <summary>
/// 4 Bytes for the number of sectors occupied by ONE FAT.
/// Offset 0x24
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x24)]
public uint FatSize32;
/// <summary>
/// 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
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x28)]
public ushort ExtendedFlags;
/// <summary>
/// 2 Bytes for the file system version. The high byte is major revision number. Low byte is minor revision number.
/// Offset 0x2a
/// </summary>
[FieldOffset(0x2a)]
public fixed byte FileSystemVersion[2];
/// <summary>
/// 4 Bytes for the first cluster number of the root directory
/// Offset 0x2c
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x2c)]
public uint RootDirFirstClusterNumber;
/// <summary>
/// 2 Bytes for the Sector number of FS Information Sector.
/// Offset 0x30
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x30)]
public ushort FSInfoSectorNumber;
/// <summary>
/// 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
/// </summary>
[MarshalAs(UnmanagedType.U2)]
[FieldOffset(0x32)]
public ushort BackupBootSectorNumber;
/// <summary>
/// 12 Reserved Bytes.
/// Offset 0x34
/// </summary>
[FieldOffset(0x34)]
public fixed byte Reserved[12];
/// <summary>
/// 1 Byte for the physical drive number.
/// Offset 0x40
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x40)]
public byte PhysicalDriveNumber;
/// <summary>
/// 1 Reserved byte.
/// Offset 0x41
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x41)]
public byte Reserved1;
/// <summary>
/// 1 Byte. The boot signature
/// Offset 0x42
/// </summary>
[MarshalAs(UnmanagedType.U1)]
[FieldOffset(0x42)]
public byte ExtendedBootSignature;
/// <summary>
/// 4 Bytes for the volume serial number.
/// Offset 0x43
/// </summary>
[MarshalAs(UnmanagedType.U4)]
[FieldOffset(0x43)]
public uint VolumeID;
/// <summary>
/// 11 Byte for the volume label.
/// Offset 0x47
/// </summary>
[FieldOffset(0x47)]
public fixed char VolumeLabel[11];
/// <summary>
/// 8 Bytes for the file system type string.
/// Offset 0x52
/// </summary>
[FieldOffset(0x52)]
public fixed char FileSystemType[8];
#endregion
/// <summary>
/// Gets the boot sector for the specified drive.
/// <remarks>The drive letter must have this pattern X: </remarks>
/// </summary>
/// <param name="driveLetter">The </param>
/// <returns>The boot sector for the specified drive.</returns>
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;
}
}
}