2013-03-10 2 views
0

Я собираюсь сохранить файл DataTable в * .dbf (dBase IV). Таким образом, у меня есть структура вроде этого:`Marshal.StructureToPtr` выдает исключение, пытаясь получить представление массива байтов структуры

[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

Хотя это стандартная практика в C, в C# редко можно копировать между массивами байтов и структурами. Маршаллинг предназначен для вызова неуправляемого кода, который вы здесь не делаете. Посмотрите на [класс BinaryWriter] (http://msdn.microsoft.com/en-us/library/system.io.binarywriter.aspx). – dtb

+0

@dtb Да. Это верно. Но чтение/запись всех этих полей с классами BinaryReader/BinaryWriter выглядит жестко. Когда вам нужно сделать это для нескольких структур, это будет сложнее. Поэтому я думал, что написать одну функцию может решить ее для всех структур, которые у меня есть. –

+0

@dtb Есть ли другой способ сопоставления байтовых массивов и структур (в C#) с использованием одной функции? –

ответ

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, как верно предполагает, что у вас есть уже называется Marshal.StructureToPtr() для этого IntPtr. Поскольку вы этого не сделали, он разбился (блок памяти не был инициализирован так, как ожидал StructureToPtr()).

Однако вам по-прежнему необходимо очистить память, вызвав Marshal.DestroyStructure() в соответствии с моим примером выше. Это необходимо для очистки данных, используемых для структур, содержащих ссылки. (В вашем конкретном примере struct не содержит ссылок, но вы можете передать такую ​​структуру на ваш StructureToByteArray()).

Наконец, обратите внимание, что если вы сделали это, не сломается (этот код не имеет смысла, кроме как продемонстрировать, как используется fDeleteOld флаг):

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

Решает проблему! но можете ли вы объяснить, почему он выдает исключение, когда для параметра 'fDeleteOld' установлено значение true? –

+0

Я отредактирую свой ответ –

+0

Спасибо. Это очень помогло мне. –

 Смежные вопросы

  • Нет связанных вопросов^_^