1

I've the following class

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
public class xy11Dataset : SZLDataset
{
    public short Index { get; set; }

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    private string _mlfB;
    public string MlfB
    {
        get { return _mlfB; }
        set { _mlfB = value; }
    }

    public UInt16 BGTyp { get; set; }

    public UInt16 Ausbg1 { get; set; }

    public UInt16 Ausbg2 { get; set; }
}

and I fill it with the following code:

byte[] objBuffer = new byte[retVal.Size];
Array.Copy(buffer, (n*retVal.Size) + 8, objBuffer, 0, retVal.Size);
GCHandle handle = GCHandle.Alloc(objBuffer, GCHandleType.Pinned);
datsets.Add((xy11Dataset)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(xy11Dataset)));
handle.Free();

I've Values in objBuffer at Position 2 (which should be the start of the string), but the string stays empty!

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Jochen Kühner
  • 1,385
  • 2
  • 18
  • 43

1 Answers1

3

You need to give up on using auto properties here. They generate a private backing field that is not sequential with the property, it's added to the end. You can see them with ildasm.exe, they have a name like <Index>k_Backingfield. You need to make this expression return the correct value:

        int offs = (int)Marshal.OffsetOf(typeof(xy11Dataset), "_mlfB");

I cannot see what SZLDataSet contains but without it this returns 0 right now. Not correct, you'd want 2. Best thing to do is to declare a struct with public fields whose layout is an exact match with the data in the buffer. Initialize the class object from the value.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Aren't auto property backing fields generated where the property is declared? Regardless, it is advisable to avoid auto properties; gives more control over the order of the fields. – Adam L. S. May 28 '21 at 11:16
  • "*not* sequential with the property", I made it as explicit as I could. – Hans Passant May 28 '21 at 11:57