0

I have a binary files that were made with structs. I'm getting this error when trying to write a struct back to the binary file: Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout.

Here's the struct, which should be 2368 bytes. Confirmed this by doing Marshal.SizeOf(typeof(DATA)) and basic math.

[StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct DATA
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] GD;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Label; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Feat;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Wor;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Source; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Anam;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Crete;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Miss;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Best;         
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] Xware;    
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] XVersion;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] UncertX;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
    public char[] UncertY;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public char[] Descrip;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)]
    public char[] Discrim; 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
    public char[] Reserved;
}

I made a simple char[] to test:

char[] testArray = new char[] { 'a', 'b', 'c', 'd' };
DATA testStruct = new DATA(); //declare the struct
testStruct.Miss = testArray; //set one of the fields to the char[]

Then I write to the binary file:

using (var fStream = new FileStream(filePath, FileMode.Append))
{
    WriteRampToFile(gisDA, fStream );
}

/// <summary>
/// Writes byte array containing a given struct to a file
/// </summary>
public void WriteRampToFile<T>(T str, FileStream fStream )
{
    byte[] buffer = GetBytes(str); //puts struct into byte array
    fStream .Write(buffer, 0, Marshal.SizeOf(typeof(T))); //write byte     array to file
}

/// <summary>
/// Converts the given struct and returns it as a byte array
/// </summary>
/// <param name="str">A structure defined at the top of this file</param>
public byte[] GetBytes<T>(T str)
{
    int size = Marshal.SizeOf(str);
    byte[] arr = new byte[size];
    GCHandle h = default(GCHandle);

    try
    {
        h = GCHandle.Alloc(arr, GCHandleType.Pinned);

        Marshal.StructureToPtr(str, h.AddrOfPinnedObject(), false); //Error     here
    }
    finally
    {
        if (h.IsAllocated)
        {
            h.Free();
        }
    }
    return arr;
}
pfinferno
  • 1,779
  • 3
  • 34
  • 62
  • 2
    Why do you declare the array with size 64 and fill it with 4? And have a look here: http://stackoverflow.com/questions/3278827/how-to-convert-a-structure-to-a-byte-array-in-c – LoekD Jul 22 '16 at 13:58
  • 1
    It is not a very appropriate way to accomplish this. Note the glaring bug in WriteRampToFile(), it is generic on T but you use typeof(GISDATA). What is GISDATA?? Your code corrupts the GC heap and anything can happen next. The exception is raised because the pinvoke marshaller sees a mismatch between the size of one the char[] elements and the SizeConst value. You'll have to slog the code and ensure they *all* are an exact match. That largely defeats the point of using Marshal.StructureToPtr(), you might as well use BinaryWriter. – Hans Passant Jul 22 '16 at 14:09
  • Sorry that was a remnant from older code I forgot to change. Fixed it. What would be an appropriate way to go about it? I can make the array size match like you guys said and make it work, but I want to do it the right way. – pfinferno Jul 22 '16 at 14:40
  • You're aware that `char` is two bytes? I'm not sure that the `Ansi` flag is going to save you. You might try switching to byte arrays and using the ANSII encoding to convert your values to bytes before sending. – Brannon Jul 22 '16 at 15:10

0 Answers0