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

Suggestion ComWrappers.TryGetComInstance() to improve UX #106979

Open
AaronRobinsonMSFT opened this issue Aug 26, 2024 · 5 comments
Open

Suggestion ComWrappers.TryGetComInstance() to improve UX #106979

AaronRobinsonMSFT opened this issue Aug 26, 2024 · 5 comments
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices
Milestone

Comments

@AaronRobinsonMSFT
Copy link
Member

AaronRobinsonMSFT commented Aug 26, 2024

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

namespace System.Runtime.InteropServices;

public abstract class ComWrappers
{
      public bool TryGetComInstance(object instance, CreateComInterfaceFlags flags, in Guid interfaceId, out IntPtr result);
}
namespace System.Runtime.InteropServices.Marshalling;

public class StrategyBasedComWrappers
{
     public bool TryGetComInstance<T>(object instance, CreateComInterfaceFlags flags, out IntPtr result) where T : class;
     public IntPtr GetComInstance<T>(T instance, CreateComInterfaceFlags flags) where T : class;
}

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();
            bool success = cw.TryGetComInstance<IFoo>(foo, CreateComInterfaceFlags.None, out nint ifoo);
            if (!success) throw new InvalidOper
            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

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Aug 26, 2024
@AaronRobinsonMSFT AaronRobinsonMSFT modified the milestones: 9.0.0, Future Aug 26, 2024
@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Aug 26, 2024
@AaronRobinsonMSFT AaronRobinsonMSFT added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Aug 26, 2024
Copy link
Contributor

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

@jkoritzinsky
Copy link
Member

We could do this as a method on StrategyBasedComWrappers without too much trouble as we have a mechanism to look up interface details.

On ComWrappers, we'd have to require the user to pass in the IID as there's no Type->IID mechanism at that level.

@AaronRobinsonMSFT
Copy link
Member Author

On ComWrappers, we'd have to require the user to pass in the IID as there's no Type->IID mechanism at that level.

I like that. We could follow what @smourier is alluding to and simply apply the Marshal.QueryInterface signature to the above. That way we have the low level API that we can build upon in derived ComWrappers?

@jkoritzinsky
Copy link
Member

Yep! I think that's a great way to do it.

@jkoritzinsky
Copy link
Member

I've updated the top of the issue to be in the API Proposal format and added one more convenience overload that I think would be quite useful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices
Projects
Status: No status
Development

No branches or pull requests

3 participants
@jkoritzinsky @AaronRobinsonMSFT and others