AnonyMuskOx
AnonyMuskOx

Reputation: 11

Marshal.PtrToStructure<T>(IntPtr ptr, T structure) throws [System.ArgumentException]: The structure must not be a value class

I think there might be a bug in the C# method

Marshal.PtrToStructure<T>(IntPtr ptr, T structure)

I wrongly assumed T structure means you can pass in your structure you want to fill but when I do this as in the example below an exception is thrown:

[System.ArgumentException: The structure must not be a value class. Parameter name: structure]

To give you a simple example:

using System;
using System.Runtime.InteropServices;

public class Program
{
    public static void Main()
    {
        MyStruct s = new MyStruct();

        var buffer = new Byte[]{1,2,3};
        var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
        Marshal.PtrToStructure<MyStruct>(handle.AddrOfPinnedObject(), s);
        handle.Free();
    }

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    struct MyStruct
    {
        public Byte a;
        public Byte b;
        public Byte c;
    }
}

Am I reading the method decleration wrong? Or is there a bug?

Upvotes: 1

Views: 1340

Answers (3)

Rainmaker
Rainmaker

Reputation: 171

Instead of converting your struct to a class (or record, I presume), there is a new overload in 4.5.1 and newer (and .NET core), which did work for me using a struct.

var msgReceived = new FixedLengthStruct();
unsafe
{
  fixed(byte* buffer = memoryAccessor.Bytes)
  {
    msgReceived = Marshal.PtrToStructure<FixedLengthStruct>((IntPtr)buffer);
  }
}
// Process msgReceived

My struct here used LayoutKind.Explicit.

Upvotes: 0

Tanveer Badar
Tanveer Badar

Reputation: 5530

The parameter name structure is misleading here. The documentation calls out twice that it must be a class.

The type of structure. This must be a formatted class.

You cannot use this method overload with value types.

However, it also self-contradicts itself when it says

Structure layout is not sequential or explicit.

Looking at the actual source, you don't find a where T : class constraint either which I guess given the docs should be present.

Upvotes: 1

Milton Neal
Milton Neal

Reputation: 1

[StructLayout(LayoutKind.Sequential, Pack = 1)]
class MyStruct
{
    public Byte a;
    public Byte b;
    public Byte c;
}

Had this problem myself and found that changing the structure to a class (ref type) over comes the problem.

Upvotes: 0

Related Questions