SoFunction
Updated on 2025-03-07

Interpreting examples of marshalling classes, structures and unions

Marshaling, structure and union examples

Marshaling category

In the .NET Framework, a class is a reference type, while a structure is a value type. For classes, they can only be marshaled through COM interoperability and are always marshaled as interfaces.

When a managed class is passed to COM, the interoperable marshaling processor automatically wraps the class using a COM proxy and passes the class interface generated by the proxy to the COM method call.

For example:

// Suppose there is an unmanaged COM interface IDemoInterface[ComImport]
[Guid("...")]
interface IDemoInterface {
    void DoSomething();
}

// Define a managed class that implements the interfacepublic class ManagedClass : IDemoInterface {
    public void DoSomething() {
        ("Doing something...");
    }
}

// Create and pass to unmanaged code in managed codevar managedInstance = new ManagedClass();
// Here is a suppose that an unmanaged function receives parameters of IDemoInterface type(managedInstance);

herePassToUnmanagedis a method defined by a platform call (P/Invoke) that is responsible forManagedClassThe object is converted into a COM interface pointer and passed to unmanaged code.

Marshaling structure

As a value type, structures also require appropriate marshaling when calling across platforms.

To ensure that the structure members are interpreted in the way they are intended, they are usually applied on the structure.StructLayoutAttributeProperties to specify layout.

Consider the following C++ defined structure:

typedef struct _MYPERSON {
    char* first;
    char* last;
} MYPERSON, *LP_MYPERSON;

The C# marshalling definition might look like this:

[StructLayout(, CharSet = )]
public struct MyPerson {
    [MarshalAs()]
    public string first;
    [MarshalAs()]
    public string last;
}

Used hereStructLayoutThe feature specifies the sequential layout and passesMarshalAsThe feature specifies how the string field is marshaled.

If you want to pass this structure to unmanaged code, you can do it like this:

[DllImport("")]
static extern int TestStructInStruct([In] MyPerson2 person2);

// Build MyPerson instancevar person = new MyPerson { first = "John", last = "Doe" };
// Create a MyPerson2 instance containing a person pointervar person2 = new MyPerson2 { person = ((person)), age = 30 };
// Copy the contents of the person to the allocated unmanaged memory(person, , false);
try {
    // Call unmanaged functions    var result = TestStructInStruct(person2);
} finally {
    // Clean up unmanaged resources    ();
}

This code shows how to safely manage unmanaged memory and ensure that the structure is correctly marshaled to unmanaged functions.

Marshaling Consortium

Unions allow different types of data members to be stored in the same memory space. This means that only one member is valid at any time.

Indicating a consortium in C# is usually involved in the useStructLayout()Features andFieldOffsetFeatures to precisely control member position.

For example, we have the following C++ definition union:

union MYUNION {
    int i;
    double d;
};

The C# marshalling definition can be:

[StructLayout()]
public struct MyUnion {
    [FieldOffset(0)]
    public int i;
    [FieldOffset(0)]
    public double d;
}

Used hereExplicitLayout mode, all fields start with offset 0, meaning they share the same memory location.

When you need to pass this unmanaged code, you can use the above definition directly because the .NET runtime knows how to properly marshal members in the unmanaged code.

Summarize

The above is personal experience. I hope you can give you a reference and I hope you can support me more.