我正在尝试将以下C++结构移植到C#。
#pragma pack(push,1)
struct FatBootSectorStruct {
UCHAR BS_jmpBoot[3]; // 0
UCHAR BS_OEMName[8]; // 3
USHORT BPB_BytsPerSec; // 11
UCHAR BPB_SecPerClus; // 13
USHORT BPB_RsvdSecCnt; // 14
UCHAR BPB_NumFATs; // 16
USHORT BPB_RootEntCnt; // 17
USHORT BPB_TotSec16; // 19
UCHAR BPB_Media; // 21
USHORT BPB_FATSz16; // 22
USHORT BPB_SecPerTrk; // 24
USHORT BPB_NumHeads; // 26
ULONG BPB_HiddSec; // 28
ULONG BPB_TotSec32; // 32
union {
struct {
UCHAR BS_DrvNum; // 36
UCHAR BS_Reserved1; // 37
UCHAR BS_BootSig; // 38
ULONG BS_VolID; // 39
UCHAR BS_VolLab[11]; // 43
UCHAR BS_FilSysType[8]; // 54
UCHAR BS_Reserved2[448]; // 62
} Fat16;
struct {
ULONG BPB_FATSz32; // 36
USHORT BPB_ExtFlags; // 40
USHORT BPB_FSVer; // 42
ULONG BPB_RootClus; // 44
USHORT BPB_FSInfo; // 48
USHORT BPB_BkBootSec; // 50
UCHAR BPB_Reserved[12]; // 52
UCHAR BS_DrvNum; // 64
UCHAR BS_Reserved1; // 65
UCHAR BS_BootSig; // 66
ULONG BS_VolID; // 67
UCHAR BS_VolLab[11]; // 71
UCHAR BS_FilSysType[8]; // 82
UCHAR BPB_Reserved2[420]; // 90
} Fat32;
};
USHORT Signature; // 510
};
这就是我所拥有的:
[StructLayout(LayoutKind.Explicit, Size = 512, Pack=1)]
internal struct FATBootSector
{
[FieldOffset(0)]
public byte[] BS_jmpBoot; // 0
[FieldOffset(3)]
public byte[] BS_OEMName; // 3
[FieldOffset(11)]
public ushort BPB_BytsPerSec; // 11
[FieldOffset(13)]
public byte BPB_SecPerClus; // 13
[FieldOffset(14)]
public ushort BPB_RsvdSecCnt; // 14
[FieldOffset(16)]
public byte BPB_NumFATs; // 16
[FieldOffset(17)]
public ushort BPB_RootEntCnt; // 17
[FieldOffset(19)]
public ushort BPB_TotSec16; // 19
[FieldOffset(21)]
public byte BPB_Media; // 21
[FieldOffset(22)]
public ushort BPB_FATSz16; // 22
[FieldOffset(24)]
public ushort BPB_SecPerTrk; // 24
[FieldOffset(26)]
public ushort BPB_NumHeads; // 26
[FieldOffset(28)]
public ulong BPB_HiddSec; // 28
[FieldOffset(32)]
public ulong BPB_TotSec32; // 32
// FAT16
[FieldOffset(36)]
public byte FAT16_BS_DrvNum; // 36
[FieldOffset(37)]
public byte FAT16_BS_Reserved1; // 37
[FieldOffset(38)]
public byte FAT16_BS_BootSig; // 38
[FieldOffset(39)]
public ulong FAT16_BS_VolID; // 39
[FieldOffset(43)]
public byte[] FAT16_BS_VolLab; // 43
[FieldOffset(54)]
public byte[] FAT16_BS_FilSysType; // 54
[FieldOffset(62)]
public byte[] FAT16_BS_Reserved2; // 62
// FAT32
[FieldOffset(36)]
public ulong FAT32_BPB_FATSz32; // 36
[FieldOffset(40)]
public ushort FAT32_BPB_ExtFlags; // 40
[FieldOffset(42)]
public ushort FAT32_BPB_FSVer; // 42
[FieldOffset(44)]
public ulong FAT32_BPB_RootClus; // 44
[FieldOffset(48)]
public ushort FAT32_BPB_FSInfo; // 48
[FieldOffset(50)]
public ushort FAT32_BPB_BkBootSec; // 50
[FieldOffset(52)]
public byte[] FAT32_BPB_Reserved; // 52
[FieldOffset(64)]
public byte FAT32_BS_DrvNum; // 64
[FieldOffset(65)]
public byte FAT32_BS_Reserved1; // 65
[FieldOffset(66)]
public byte FAT32_BS_BootSig; // 66
[FieldOffset(67)]
public byte FAT32_BS_VolID; // 67
[FieldOffset(71)]
public byte[] BS_VolLab; // 71
[FieldOffset(82)]
public byte[] FAT32_BS_FilSysType; // 82
[FieldOffset(90)]
public byte[] FAT32_BPB_Reserved2; // 90
[FieldOffset(510)]
public ushort Signature;
}
问题出在字段偏移量0和3上。当我尝试在C#中加载结构时,出现
Could not load type 'FATBootSector' from assembly 'xxxx' because it contains an object field at offset 3 that is incorrectly aligned or overlapped by a non-object field.
。我碰到this previous question on SO,但这似乎无济于事。我也尝试将其更改为如下所示的顺序结构:
[StructLayout(LayoutKind.Sequential, Size = 512, Pack=1, CharSet=CharSet.Ansi)]
internal struct FATBootSector
{
[MarshalAs(UnmanagedType.U1)]
public byte BS_jmpBoot0; // 0
[MarshalAs(UnmanagedType.U1)]
public byte BS_jmpBoot1; // 0
[MarshalAs(UnmanagedType.U1)]
public byte BS_jmpBoot2; // 0
[MarshalAs(UnmanagedType.LPStr, SizeConst=8)]
public string BS_OEMName; // 3
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_BytsPerSec; // 11
[MarshalAs(UnmanagedType.U1)]
public byte BPB_SecPerClus; // 13
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_RsvdSecCnt; // 14
[MarshalAs(UnmanagedType.U1)]
public byte BPB_NumFATs; // 16
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_RootEntCnt; // 17
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_TotSec16; // 19
[MarshalAs(UnmanagedType.U1)]
public byte BPB_Media; // 21
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_FATSz16; // 22
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_SecPerTrk; // 24
[MarshalAs(UnmanagedType.U2)]
public ushort BPB_NumHeads; // 26
[MarshalAs(UnmanagedType.U4)]
public ulong BPB_HiddSec; // 28
[MarshalAs(UnmanagedType.U4)]
public ulong BPB_TotSec32; // 32
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 474)]
public byte[] FAT1632Info;
[MarshalAs(UnmanagedType.U2)]
public ushort Signature;
}
我正在使用以下代码来获取结构:
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool ReadFile(IntPtr hFile, [Out] IntPtr lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, [In] ref System.Threading.NativeOverlapped lpOverlapped);
public bool GetPartitionDetails()
{
uint BytesRead;
IntPtr BootSectorPtr = Marshal.AllocHGlobal(512);
PInvoke.FATBootSector BootSector;
System.Threading.NativeOverlapped Overlapped = new System.Threading.NativeOverlapped();
bool ret = PInvoke.ReadFile(this.Handle, BootSectorPtr, (uint)512, out BytesRead, ref Overlapped);
BootSector = (PInvoke.FATBootSector)Marshal.PtrToStructure(BootSectorPtr, typeof(PInvoke.FATBootSector)); // causes access violation
return true;
}
我希望不必这样做,但是我能想到的唯一替代方法是使用
IntPtr
遍历内存。有任何想法吗? 最佳答案
这里有很多问题。首先,您正在滥用FieldOffset
。当编译器无法为您布局结构时,可以使用它。总是有工会的时候。不要在这里使用FieldOffset
。当然不要预先指定大小。同样,让编译器执行此操作。根据本机版本进行检查。
然后,您不正确地处理数组。您不需要fixed
,但您需要说明数组的长度。结构的开始应如下所示:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct FATBootSector
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] BS_jmpBoot;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] BS_OEMName;
....
}
您其余的问题是由错误的类型转换引起的。 C++中的
ULONG
是4字节无符号类型。这是C#中的uint
。您使用的ulong
为8字节宽。这是该结构的一个版本,它将至少避免访问冲突:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct FATBootSector
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] BS_jmpBoot;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] BS_OEMName;
public ushort BPB_BytsPerSec;
public byte BPB_SecPerClus;
public ushort BPB_RsvdSecCnt;
public byte BPB_NumFATs;
public ushort BPB_RootEntCnt;
public ushort BPB_TotSec16;
public byte BPB_Media;
public ushort BPB_FATSz16;
public ushort BPB_SecPerTrk;
public ushort BPB_NumHeads;
public uint BPB_HiddSec;
public uint BPB_TotSec32;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 474)]
public byte[] FAT1632Info;
public ushort Signature;
}
要转换FAT16 / FAT32并集,您可能需要使用
fixed
。或者,可以选择两种FATBootSector
类型。一种用于FAT16,另一种用于FAT32。