Skip to content

Implement source generator for proposed System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute #76767

@jkoritzinsky

Description

@jkoritzinsky

In the design doc for the COM source generator, we determined that we wanted to add a new attribute named System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute (name subject to change in API review) with the following tentative shape:

namespace System.Runtime.InteropServices.Marshalling;

[AttributeUsage(AttributeTargets.Interface)]
public class GeneratedComInterfaceAttribute
{
    public GeneratedComInterfaceAttribute(Type comWrappersType);

    public GeneratedComInterfaceAttribute(Type comWrappersType, bool generateManagedObjectWrapper, bool generateComObjectWrapper);

    public Type ComWrappersType { get; };

    public bool GenerateManagedObjectWrapper { get; } = true;

    public bool GenerateComObjectWrapper { get; } = true;

    public bool ExportInterfaceDefinition { get; }
}

This attribute could also alternatively be a generic attribute so we as the source-generator authors don't need to handle validating the type passed to the constructor.

After discussing the design further, we also proposed adding a new public type that implements basic COM support around IUnknown as well as a ComWrappers-derived base class and an interface to help, possibly with the following shapes:

namespace System.Runtime.InteropServices.Marshalling;

// This type represents the TypeKey concept. We wrap the Guid type here mainly to signify specific usage (effectively make a strong typedef)
public readonly record struct InterfaceId(Guid IID);

public class ComObject : IDynamicInterfaceCastable, IUnmanagedVirtualMethodTableProvider<InterfaceId>
{
    // Implement support for casting through IUnknown.
    // No thread-affinity aware support.
    // No IDispatch support.
    // No aggregation support.
}

public abstract class GeneratedComWrappersBase<TComObject> : ComWrappers
{
}

The user will use the attribute as follows:

[GeneratedComInterface(typeof(MyComWrappers))]
interface IFoo
{
    void Bar();
}

public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
{
}

This issues tracks the following components of the generator, each of which can be completed relatively independently:

  • Implement the ComputeVtables method for MyComWrappers to return vtables for all interfaces with the [GeneratedComInterface] attribute that point at MyComWrappers that the provided object implements.
  • Implement the CreateObject method to create an object of type ComObject around the provided external COM object.
    • Possibly generate a nested type that has optimized support for the provided interfaces (such as a cache where the expected interfaces have optimized access).
  • Generate an DynamicInterfaceCastableImplementation-interface for the marked interface that provides the managed-to-unmanaged implementation based on the design and generator in Introduce a source generator for invoking methods on unmanaged vtables #68276.
  • Generate a native vtable for the interface that implements the unmanaged-to-managed implemenation for when managed objects are passed to unmanaged code through the ComWrappers type.

Metadata

Metadata

Assignees

Type

No type

Projects

Status

No status

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions