Skip to content

Suggestion ComWrappers.TryGetComInstance() to improve UX #106979

Description

@AaronRobinsonMSFT

Background and motivation

It would be nice to have some wrappers that would return other interfaces pointers, something like:

ComWrappers.TryGetComInstance<T>(unwrapped, out nint iface);

that would do the QI so I could call it like this:

ComWrappers.TryGetComInstance<IFoo>(unwrapped, out nint ifoo);

As a "frequent COM flyer", It's quite perturbing to have to juggle between ComWrappers and Marshal classes, actually it would be nice with all that new code to be able to avoid using Marshal completely :-)

Originally posted by @smourier in #106978 (comment)

public abstract partial class ComWrappers
{
+    public bool TryGetComInstance<TInterface>(object instance, CreateComInterfaceFlags flags, out IntPtr result);
}

This could also be an auto-generated method that would be provided on a derived ComWrappers instance. Looking up the IID on TInterface would need to be AOT friendly, which means typeof(TInterface).GUID is out.

API Proposal

The below API is modified from the OP proposal to align with existing API shape and motivating example below.

public abstract class ComWrappers
{
      public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags);
+     public IntPtr GetOrCreateComInterfaceForObject(object instance, CreateComInterfaceFlags flags, in Guid interfaceId);
}
public class StrategyBasedComWrappers
{
+     public IntPtr GetOrCreateComInterfaceForObject<TInterface>(object instance, CreateComInterfaceFlags flags);
}
  • Failing to QI for TInterface will trigger an InvalidCastException.
  • Failing to QI for TInterface will still insert into the map.

API Usage

using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

[assembly: DisableRuntimeMarshalling]

namespace ConsoleAotAuthor
{
    internal partial class Program
    {
        static void Main()
        {
            var cw = new StrategyBasedComWrappers();
            var foo = new Foo();

            // Will throw if foo doesn't QI for IFoo.
            nint ifoo = cw.GetOrCreateComInterfaceForObject<Foo, IFoo>(foo, CreateComInterfaceFlags.None);
            GivePointerToComInterface(ifoo);
        }

        [LibraryImport("Dll1.dll")]
        private static partial void GivePointerToComInterface(nint comObject);
    }

    [GeneratedComInterface, Guid("217104c3-ce28-4d13-a32e-ef65ee75edf1")]
    public partial interface IFoo
    {
        void Method(int i);
    }

    [GeneratedComClass]
    public partial class Foo : IFoo
    {
        public void Method(int i) => Console.WriteLine(".NET i:" + i);
    }
}

Alternative Designs

No response

Risks

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

  • Status
    No status

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions