runtime: ComWrappers instances do not provide isolation

Repro:

using System;
using System.Collections;
using System.Runtime.InteropServices;

class ComWrappers1 : ComWrappers
{
    protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
    {
        throw new NotImplementedException();
    }

    protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flags)
    {
        return new ComWrapper1(externalComObject);
    }

    protected override void ReleaseObjects(IEnumerable objects)
    {
        throw new NotImplementedException();
    }
}

class ComWrapper1
{
    IntPtr _punk;

    public ComWrapper1(IntPtr punk)
    {
        _punk = punk;
    }
}

class ComWrappers2 : ComWrappers
{
    protected override unsafe ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
    {
        throw new NotImplementedException();
    }

    protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flags)
    {
        return new ComWrapper2(externalComObject);
    }

    protected override void ReleaseObjects(IEnumerable objects)
    {
        throw new NotImplementedException();
    }
}

class ComWrapper2
{
    IntPtr _punk;

    public ComWrapper2(IntPtr punk)
    {
        _punk = punk;
    }
}

class Program
{
    [DllImport("api-ms-win-core-winrt-l1-1-0.dll", PreserveSig = true)]
    internal static extern int RoGetActivationFactory(
          [MarshalAs(UnmanagedType.HString)] string activatableClassId,
          [In] ref Guid iid,
          [Out] out IntPtr factory);

    static Guid IID_IUnknown = new Guid("00000000-0000-0000-c000-000000000046");

    static void Component1()
    {
        var wrappers = new ComWrappers1();

        if (RoGetActivationFactory("Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", ref IID_IUnknown, out IntPtr punk) != 0)
            throw new COMException();

        var wrapper1 = (ComWrapper1)wrappers.GetOrCreateObjectForComInstance(punk, CreateObjectFlags.None);
    }

    static void Component2()
    {
        var wrappers = new ComWrappers2();

        if (RoGetActivationFactory("Windows.UI.Xaml.Interop.NotifyCollectionChangedEventArgs", ref IID_IUnknown, out IntPtr punk) != 0)
            throw new COMException();

        // Returns ComWrapper1!
        var wrapper2 = (ComWrapper2)wrappers.GetOrCreateObjectForComInstance(punk, CreateObjectFlags.None);
    }

    static void Main(string[] args)
    {
        Component1();
        Component2();
    }
}

Expected behavior: Succeeds Actual behavior: System.InvalidCastException: 'Unable to cast object of type ‘ComWrapper1’ to type ‘ComWrapper2’.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (21 by maintainers)

Most upvoted comments

We should extend the native weak reference support to also understand the isolation mechanism for when it has to rehydrate the managed wrapper to ensure we rehydrate the object via the same instance that created it.

I’d prefer the instance. From the implementer side, it seems clearer to me to have to use the same ComWrappers to get the non-isolated behaviour than to have to make separate types to make sure the instances are isolated

Okay. I think I see how this issue comes up. We will need to handle this.