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

[API Proposal]: APIs to expose managed objects to COM #83471

Closed
jkoritzinsky opened this issue Mar 15, 2023 · 4 comments · Fixed by #84329
Closed

[API Proposal]: APIs to expose managed objects to COM #83471

jkoritzinsky opened this issue Mar 15, 2023 · 4 comments · Fixed by #84329
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.InteropServices source-generator Indicates an issue with a source generator feature
Milestone

Comments

@jkoritzinsky
Copy link
Member

jkoritzinsky commented Mar 15, 2023

Background and motivation

As part of our work to provide a source-generator for COM, we need to provide a mechanism for users to request that code be generated to support passing their types to native code.

API Proposal

namespace System.Runtime.InteropServices.Marshalling;


+ public unsafe interface IComExposedClass
+ {
+     public static abstract ComWrappers.ComInterfaceEntry* ComInterfaceEntries { get; }
+     public static abstract int InterfaceEntriesLength { get; }
+ }

+ public unsafe interface IComExposedDetails
+ {
+     ComWrappers.ComInterfaceEntry* ComInterfaceEntries { get; }
+ 
+     int InterfaceEntriesLength { get; }
+ }

+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed unsafe class ComExposedClassAttribute<T> : Attribute, IComExposedDetails
+     where T : IComExposedClass
+ {
+     public ComWrappers.ComInterfaceEntry* ComInterfaceEntries { get; }
+ 
+     public int InterfaceEntriesLength { get; }
+ }

public interface IIUnknownInterfaceDetailsStrategy
{
+    /// <summary>
+    /// Given a <see cref="RuntimeTypeHandle"/> get the details about the type that are exposed to COM.
+    /// </summary>
+    /// <param name="type">RuntimeTypeHandle instance</param>
+    /// <returns>Details if type is known.</returns>
+    IComExposedDetails? GetComExposedTypeDetails(RuntimeTypeHandle type);
}


+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public sealed class GeneratedComClassAttribute : Attribute
+ {
+ }


- public abstract class StrategyBasedComWrappers : ComWrappers
+ public class StrategyBasedComWrappers : ComWrappers
{
+     protected override sealed System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry* ComputeVtables(object obj, System.Runtime.InteropServices.CreateComInterfaceFlags flags, out int count);
}

API Usage

[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public partial interface IComInterface1
{
    void Method();
}

[GeneratedComClass]
partial class A : IComInterface1
{
    void IComInterface1.Method()
    {
        Console.WriteLine("--- A.IComInterface1.Method");
    }
}

Examples of how generated code will use these APIs is at https://github.com/AaronRobinsonMSFT/ComObjectRedux/pull/8

Alternative Designs

Alternatively, we considered requiring the user to attribute a ComWrappers-derived type with attributes that point to each class type it should support. This ended up becoming a significantly more expensive design that was less trimmable (both this design and the alternative one are trim-friendly).

Risks

This adds a method to an interface, but we haven't shipped the interface yet.

@jkoritzinsky jkoritzinsky added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices source-generator Indicates an issue with a source generator feature labels Mar 15, 2023
@ghost
Copy link

ghost commented Mar 15, 2023

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

Issue Details

Background and motivation

As part of our work to provide a source-generator for COM, we need to provide a mechanism for users to request that code be generated to support passing their types to native code.

API Proposal

namespace System.Runtime.InteropServices.Marshalling;


+ public unsafe interface IComExposedClass
+ {
+     public static abstract ComWrappers.ComInterfaceEntry* ComInterfaceEntries { get; }
+     public static abstract int InterfaceEntriesLength { get; }
+ }

+ public unsafe interface IComExposedDetails
+ {
+     ComWrappers.ComInterfaceEntry* ComInterfaceEntries { get; }
+ 
+     int InterfaceEntriesLength { get; }
+ }

+ [AttributeUsage(AttributeTargets.Class)]
+ public sealed unsafe class ComExposedClassAttribute<T> : Attribute, IComExposedDetails
+     where T : IComExposedClass
+ {
+     public ComWrappers.ComInterfaceEntry* ComInterfaceEntries { get; }
+ 
+     public int InterfaceEntriesLength { get; }
+ }

public interface IIUnknownInterfaceDetailsStrategy
{
+    /// <summary>
+    /// Given a <see cref="RuntimeTypeHandle"/> get the details about the type that are exposed to COM.
+    /// </summary>
+    /// <param name="type">RuntimeTypeHandle instance</param>
+    /// <returns>Details if type is known.</returns>
+    IComExposedDetails? GetComExposedTypeDetails(RuntimeTypeHandle type);
}


+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public sealed class GeneratedComClassAttribute : Attribute
+ {
+ }


- public abstract class StrategyBasedComWrappers : ComWrappers
+ public class StrategyBasedComWrappers : ComWrappers
{
+     protected override sealed unsafe object CreateObject(nint externalComObject, CreateObjectFlags flags);
}

API Usage

[GeneratedComInterface]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public partial interface IComInterface1
{
    void Method();
}

[GeneratedComClass]
partial class A : IComInterface1
{
    void IComInterface1.Method()
    {
        Console.WriteLine("--- A.IComInterface1.Method");
    }
}

Alternative Designs

Alternatively, we considered requiring the user to attribute a ComWrappers-derived type with attributes that point to each class type it should support. This ended up becoming a significantly more expensive design that was less trimmable (both this design and the alternative one are trim-friendly).

Risks

This adds a method to an interface, but we haven't shipped the interface yet.

Author: jkoritzinsky
Assignees: -
Labels:

api-suggestion, area-System.Runtime.InteropServices, source-generator

Milestone: -

@ghost ghost added the untriaged New issue has not been triaged by the area owner label Mar 15, 2023
@jkoritzinsky jkoritzinsky added blocking Marks issues that we want to fast track in order to unblock other important work api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner labels Mar 15, 2023
@jkoritzinsky jkoritzinsky added this to the 8.0.0 milestone Mar 15, 2023
@jkotas
Copy link
Member

jkotas commented Mar 15, 2023

Is the source generator for COM going to be separate package or is going to be part of netcoreapp?

@jkoritzinsky
Copy link
Member Author

The current plan is for it to be part of netcoreapp.

@bartonjs
Copy link
Member

  • We rewrote IComExposedDetails to combine the pointer and length into a single member (consequently changing two properties into one method)
    • And then plumbed that through the shape of everything else
  • This proposal doesn't address COM activation. Please try to ensure that the shapes of interfaces won't need to change when that feature is added (and frontload that work if it will require changing things).
  • There was another suggestion of promoting the "trigger" attributes up to System.Runtime.InteropServices instead of down in Marshalling. If you take that suggestion, keep the CCW and RCW trigger attributes together.
namespace System.Runtime.InteropServices.Marshalling;


 public unsafe interface IComExposedClass
 {
     public static abstract ComWrappers.ComInterfaceEntry* GetComInterfaceEntries(out int count);
 }

 public unsafe interface IComExposedDetails
 {
     ComWrappers.ComInterfaceEntry* GetComInterfaceEntries(out int count);
 }

 [AttributeUsage(AttributeTargets.Class)]
 public sealed unsafe class ComExposedClassAttribute<T> : Attribute, IComExposedDetails
     where T : IComExposedClass
 {
     ComWrappers.ComInterfaceEntry* GetComInterfaceEntries(out int count);
 }

public interface IIUnknownInterfaceDetailsStrategy
{
    /// <summary>
    /// Given a <see cref="RuntimeTypeHandle"/> get the details about the type that are exposed to COM.
    /// </summary>
    /// <param name="type">RuntimeTypeHandle instance</param>
    /// <returns>Details if type is known.</returns>
    IComExposedDetails? GetComExposedTypeDetails(RuntimeTypeHandle type);
}


 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
 public sealed class GeneratedComClassAttribute : Attribute
 {
 }

// No longer declared `abstract`
 public class StrategyBasedComWrappers : ComWrappers
{
     protected override sealed System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry* ComputeVtables(object obj, System.Runtime.InteropServices.CreateComInterfaceFlags flags, out int count);
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed blocking Marks issues that we want to fast track in order to unblock other important work api-ready-for-review API is ready for review, it is NOT ready for implementation labels Mar 16, 2023
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Apr 4, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Apr 13, 2023
@ghost ghost locked as resolved and limited conversation to collaborators May 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.InteropServices source-generator Indicates an issue with a source generator feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants