Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
4 tasks done
jkoritzinsky opened this issue Oct 7, 2022 · 2 comments
Assignees
Labels
area-System.Runtime.InteropServices Bottom Up Work Not part of a theme, epic, or user story User Story A single user-facing feature. Can be grouped under an epic.
Milestone

Comments

@jkoritzinsky
Copy link
Member

jkoritzinsky commented Oct 7, 2022

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.
@jkoritzinsky jkoritzinsky added Bottom Up Work Not part of a theme, epic, or user story area-System.Runtime.InteropServices labels Oct 7, 2022
@jkoritzinsky jkoritzinsky added this to the 8.0.0 milestone Oct 7, 2022
@ghost
Copy link

ghost commented Oct 7, 2022

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Issue Details

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;

public class ComObject : IDynamicInterfaceCastable, IComObjectWrapper<ComObject>
{
    // 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.
Author: jkoritzinsky
Assignees: -
Labels:

area-System.Runtime.InteropServices, Bottom Up Work

Milestone: 8.0.0

@agocke agocke added the User Story A single user-facing feature. Can be grouped under an epic. label Dec 5, 2022
@jkoritzinsky
Copy link
Member Author

The basic GeneratedComInterface attribute and source generator have been merged in to main, so I'm going to close this.

@ghost ghost locked as resolved and limited conversation to collaborators May 25, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime.InteropServices Bottom Up Work Not part of a theme, epic, or user story User Story A single user-facing feature. Can be grouped under an epic.
Projects
Archived in project
Development

No branches or pull requests

2 participants