Skip to content

[API Proposal]: 'ComWrappers' methods to get runtime-provided 'IUnknown' CCW vtable entries #114133

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

Closed
Tracked by #114179
Sergio0694 opened this issue Apr 2, 2025 · 3 comments · Fixed by #114354
Closed
Tracked by #114179
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices

Comments

@Sergio0694
Copy link
Contributor

Sergio0694 commented Apr 2, 2025

Contributes to #114024

Same motivation and context as the linked issue. This proposal is for an ILC-friendly set of APIs to build IUnknown CCW vtables.
Original suggestion for the shape by @jkotas in #114024 (comment).

Important

We can't just use the existing ComWrappers.GetIUnknownImpl, as its shape is too difficult for ILC to interpret it.

API Proposal

namespace System.Runtime.InteropServices;

public abstract class ComWrappers
{
    public static IntPtr GetIUnknownQueryInterfaceImpl();
    public static IntPtr GetIUnknownAddRefImpl();
    public static IntPtr GetIUnknownReleaseImpl();
}

API Usage

// Eg. in WinRT.Runtime.dll
internal unsafe struct IInspectableVftbl
{
    public delegate* unmanaged[MemberFunction]<void*, Guid*, void**, int> QueryInterface;
    public delegate* unmanaged[MemberFunction]<void*, uint> AddRef;
    public delegate* unmanaged[MemberFunction]<void*, uint> Release;
    public delegate* unmanaged[MemberFunction]<void*, uint*, Guid**, int> GetIids;
    public delegate* unmanaged[MemberFunction]<void*, nint*, int> GetRuntimeClassName;
    public delegate* unmanaged[MemberFunction]<void*, int*, int> GetTrustLevel;
}

internal static unsafe class IInspectableImpl
{
    [FixedAddressValueType]
    private static readonly IInspectableVftbl Vftbl;
    
    public static nint AbiToProjectionVftablePtr => (nint)Unsafe.AsPointer(ref Unsafe.AsRef(in Vftbl));

    static IInspectableImpl()
    {
        Vftbl.QueryInterface = (delegate* unmanaged[MemberFunction]<void*, Guid*, void**, int>)ComWrappers.GetIUnknownQueryInterfaceImpl();
        Vftbl.AddRef = (delegate* unmanaged[MemberFunction]<void*, uint>)ComWrappers.GetIUnknownAddRefImpl();
        Vftbl.Release = (delegate* unmanaged[MemberFunction]<void*, uint>)ComWrappers.GetIUnknownReleaseImpl();
        Vftbl.GetIids = &GetIids;
        Vftbl.GetRuntimeClassName = &GetRuntimeClassName;
        Vftbl.GetTrustLevel = &GetTrustLevel;
    }

    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])]
    private static int GetIids(void* thisPtr, uint* iidCount, Guid** iids)
    {
        *iidCount = 0;
        *iids = null;

        return 0;
    }

    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])]
    private static int GetRuntimeClassName(void* thisPtr, nint* className)
    {
        *className = default;

        return 0;
    }

    [UnmanagedCallersOnly(CallConvs = [typeof(CallConvMemberFunction)])]
    private static int GetTrustLevel(void* thisPtr, int* trustLevel)
    {
        *trustLevel = 0;

        return 0;
    }
}
@Sergio0694 Sergio0694 added api-suggestion Early API idea and discussion, it is NOT ready for implementation area-System.Runtime.InteropServices labels Apr 2, 2025
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Apr 2, 2025
Copy link
Contributor

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

@AaronRobinsonMSFT
Copy link
Member

@MichalStrehovsky I'm deferring to you if this is needed. Based on my reading of the referenced issue there are at least three options to consider.

  1. Update the ILC interpreter to process the current API.
  2. Special case this API call in the ILC intepreter.
  3. Create a new API that works more easily with the current ILC interpreter.

Are there others?

I've no strong preference on which is taken, but if (3) is done the proposed API should return IntPtr not typed function pointers. I'm fine taking this through API review if this is absolutely needed.

@Sergio0694
Copy link
Contributor Author

Sergio0694 commented Apr 2, 2025

"if (3) is done the proposed API should return IntPtr not typed function pointers"

I'm happy to update the proposed API shape to account for that. I think in the previous discussion we established that all casts between nint/pointers/fnpointers just vanish at the IL level, so they shouldn't make things more difficult for ILC anyway. Just make the callsite slightly more verbose, but then again most of it is just generated code, so not really a problem either way 🙂

EDIT: update the proposed API shape and the use case example.

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
Archived in project
Development

Successfully merging a pull request may close this issue.

2 participants