得到"错误地对齐或重叠非对象"显式结构上的错误

时间:2015-01-21 03:51:34

标签: c# .net marshalling

我试图阅读/编辑暗黑破坏神的保存文件。规范here,如果有人感兴趣,但我认为这与问题无关。

我有一个带有文件字节的字节数组,我试图解析一些结构。我已经可以很好地读取文件头了,但是我遇到了任务数据问题。我得到了结构:

[StructLayout(LayoutKind.Explicit, Size = 10, Pack = 1)]
public struct QuestCompletationDataHeader {
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4)]
    [FieldOffset(0)]
    public string Identifier;
    [FieldOffset(4)]
    uint _0x0004;
    [FieldOffset(8)]
    short _0x008;
}

[StructLayout(LayoutKind.Explicit, Size = 96, Pack = 1)]
public struct QuestData {
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 96, ArraySubType = UnmanagedType.U1)]
    [FieldOffset(0)]
    byte[] _0x0000; //Irrelevant for now.
}

[StructLayout(LayoutKind.Explicit, Size = 298, Pack = 1)]
public struct QuestCompletationData {
    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(0)]
    QuestCompletationDataHeader Header;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(10)]
    QuestData NormalQuests;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(106)]
    QuestData NightmareQuests;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(202)]
    QuestData HellQuests;

}

D2SFile类:

[StructLayout(LayoutKind.Explicit, Size = 638, Pack = 1)]
public struct D2SFile {
    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(0)]
    public D2SHeader Header;

    [MarshalAs(UnmanagedType.LPStruct)]
    [FieldOffset(335)]
    public QuestCompletationData Quests;
}

我使用的函数来执行字节到结构转换:

 public static D2SFile ByteArrayToD2SFile(byte[] bytes) {
        GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
        D2SFile stuff = (D2SFile)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(D2SFile));
        handle.Free();
        return stuff;
    }

正如我所说,我已经可以单独读取文件头而没有问题,但是当我将任务数据添加到D2SFile结构时,我得到:Could not load type 'MedianXLEditor.QuestCompletationData' from assembly '...' because it contains an object field at offset 10 that is incorrectly aligned or overlapped by a non-object field.

1 个答案:

答案 0 :(得分:5)

由于没有人回答,我已经发现了什么问题,我想我应该自己回答一下,以便任何碰巧在谷歌搜索后结束的人都会有更轻松的时间。

事实证明,你不能从不是4的倍数的偏移处开始一个数组。

在上面的示例中,QuestCompletationDataHeader长度为10个字节,因此在QuestCompletationData结构上,下一个字段将从位置10开始。下一个字段恰好是QuestData struct基本上是一个大数组(现在)。所以它会尝试将该数组放在偏移量10,10处不是4的倍数,因此它给出了异常。

我更改了QuestData结构,因此它在第一个位置没有使用数组,现在工作正常。

此外,当编组结构如上所述时,请使用[MarshalAs(UnmanagedType.Struct)]。我正在使用[MarshalAs(UnmanagedType.LPStruct)],后来又给了我另一个例外。