`Marshal.StructureToPtr`在尝试获取结构的字节数组表示时抛出异常

时间:2013-03-10 08:13:05

标签: c# exception marshalling

我要将DataTable保存到* .dbf文件(dBase IV)。所以我有这样的结构:

[StructLayout(LayoutKind.Explicit, Pack = 1)]
public struct DbfHeader
{
    [FieldOffset(0)]
    private byte versionNumber;

    [FieldOffset(1)]
    private byte yearOfLastUpdate;

    [FieldOffset(2)]
    private byte monthOfLastUpdate;

    [FieldOffset(3)]
    private byte dayOfLastUpdate;

    [FieldOffset(4)]
    private Int32 numberOfRecords;

    [FieldOffset(8)]
    private Int16 lengthOfHeader;

    [FieldOffset(10)]
    private Int16 lengthOfEachRecord;

    [FieldOffset(12)]
    private Int16 reserved1;

    [FieldOffset(14)]
    private byte incompleteTransaction;

    [FieldOffset(15)]
    private byte encryptionFlag;

    [FieldOffset(16)]
    private byte[] freeRecordThread;

    [FieldOffset(20)]
    private byte[] reserved2;

    [FieldOffset(28)]
    private byte mdxFlag;

    [FieldOffset(29)]
    private byte languageDriver;

    [FieldOffset(30)]
    private Int16 reserved3;

    public DbfHeader(int numberOfRecords, int numberOfFields, short recordLength, Encoding encoding)
    {
        // some code that initialize each field
    }

}

另外,我有一种将DbfHeader变量转换为byte[]数组的方法,如下所示:

public static byte[] StructureToByteArray<T>(T structure)
{
    int len = Marshal.SizeOf(structure);
    byte[] result = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(structure, ptr, true);
    Marshal.Copy(ptr, result, 0, len);
    Marshal.FreeHGlobal(ptr);
    return result;
}

但这种方法不起作用。在Marshal.StructureToPtr(structure, ptr, true)行,我得到了这个例外:

Attempted to read or write protected memory. 
This is often an indication that other memory is corrupt.

任何人都知道出了什么问题?任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:3)

为什么您将fDeleteOld传递给Marshal.StructureToPtr()

你应该尽可能地通过false

我认为你应该在复制内存后调用Marshal.DestroyStructure():

public static byte[] StructureToByteArray<T>(T structure)
{
    int len = Marshal.SizeOf(structure);
    byte[] result = new byte[len];
    IntPtr ptr = Marshal.AllocHGlobal(len);
    Marshal.StructureToPtr(structure, ptr, false);
    Marshal.Copy(ptr, result, 0, len);
    Marshal.DestroyStructure(ptr, typeof(T));
    Marshal.FreeHGlobal(ptr);
    return result;
}

之前崩溃的原因是因为将fDeleteOld传递为true假设您已经已经为该IntPtr调用了Marshal.StructureToPtr()。因为你没有,它崩溃了(内存块没有按照StructureToPtr()期望的方式进行初始化。)

但是,您仍然需要按照上面的示例调用Marshal.DestroyStructure()来清理内存。这是清理用于包含引用的结构的数据所必需的。 (您的特定示例结构不包含引用,但您可以将此类结构传递给StructureToByteArray())。

最后,请注意,如果你这样做,它就不会崩溃(除了演示如何使用fDeleteOld标志外,这段代码没有意义):

Marshal.StructureToPtr(structure, ptr, false); // First time; must be false.
Marshal.StructureToPtr(structure, ptr, true); // Second time: Now it can be true.