Skip to content

Commit

Permalink
Improvements to subscribing to events (#1027)
Browse files Browse the repository at this point in the history
* WeakReference improvements

* Activatation IID improvements

* WeakReference optimization

* Move caching outside of event source which is per delegate type.

* Update modifiers.
  • Loading branch information
manodasanW authored Oct 26, 2021
1 parent db7a841 commit b8d4b5e
Show file tree
Hide file tree
Showing 12 changed files with 366 additions and 369 deletions.
16 changes: 10 additions & 6 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ public static partial class ComWrappersSupport

public static TReturn MarshalDelegateInvoke<TDelegate, TReturn>(IntPtr thisPtr, Func<TDelegate, TReturn> invoke)
where TDelegate : class, Delegate
{
{
#if !NET
using (new Mono.ThreadContext())
#endif
{
var target_invoke = FindObject<TDelegate>(thisPtr);
if (target_invoke != null)
Expand All @@ -46,7 +48,9 @@ public static TReturn MarshalDelegateInvoke<TDelegate, TReturn>(IntPtr thisPtr,
public static void MarshalDelegateInvoke<T>(IntPtr thisPtr, Action<T> invoke)
where T : class, Delegate
{
#if !NET
using (new Mono.ThreadContext())
#endif
{
var target_invoke = FindObject<T>(thisPtr);
if (target_invoke != null)
Expand Down Expand Up @@ -206,12 +210,12 @@ internal static List<ComInterfaceEntry> GetInterfaceTableEntries(Type type)
{
IID = typeof(ManagedCustomPropertyProviderVftbl).GUID,
Vtable = ManagedCustomPropertyProviderVftbl.AbiToProjectionVftablePtr
});

});

entries.Add(new ComInterfaceEntry
{
IID = typeof(ABI.WinRT.Interop.IWeakReferenceSource.Vftbl).GUID,
Vtable = ABI.WinRT.Interop.IWeakReferenceSource.Vftbl.AbiToProjectionVftablePtr
IID = ABI.WinRT.Interop.IWeakReferenceSource.IID,
Vtable = ABI.WinRT.Interop.IWeakReferenceSource.AbiToProjectionVftablePtr
});

// Add IMarhal implemented using the free threaded marshaler
Expand Down Expand Up @@ -439,7 +443,7 @@ private static ComInterfaceEntry ProvideIReference(Type type)
if (type == typeof(int))
{
return new ComInterfaceEntry
{
{
IID = global::WinRT.GuidGenerator.GetIID(typeof(ABI.System.Nullable<int>)),
Vtable = BoxedValueIReferenceImpl<int>.AbiToProjectionVftablePtr
};
Expand Down
4 changes: 2 additions & 2 deletions src/WinRT.Runtime/ComWrappersSupport.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -448,12 +448,12 @@ private static object CreateObject(IObjectReference objRef)

return ComWrappersSupport.GetTypedRcwFactory(runtimeClassName)(inspectable);
}
else if (objRef.TryAs<ABI.WinRT.Interop.IWeakReference.Vftbl>(ABI.WinRT.Interop.IWeakReference.IID, out var weakRef) == 0)
else if (objRef.TryAs<IUnknownVftbl>(ABI.WinRT.Interop.IWeakReference.IID, out var weakRef) == 0)
{
// IWeakReference is IUnknown-based, so implementations of it may not (and likely won't) implement
// IInspectable. As a result, we need to check for them explicitly.

return new SingleInterfaceOptimizedObject(typeof(IWeakReference), weakRef);
return new SingleInterfaceOptimizedObject(typeof(IWeakReference), weakRef, false);
}

// If the external COM object isn't IInspectable or IWeakReference, we can't handle it.
Expand Down
194 changes: 81 additions & 113 deletions src/WinRT.Runtime/Interop/IWeakReferenceSource.net5.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using global::WinRT;

namespace WinRT.Interop
{
Expand All @@ -21,7 +21,7 @@ public interface IWeakReference

internal class ManagedWeakReference : IWeakReference
{
private WeakReference<object> _ref;
private readonly WeakReference<object> _ref;
public ManagedWeakReference(object obj)
{
_ref = new WeakReference<object>(obj);
Expand All @@ -45,135 +45,103 @@ public IObjectReference Resolve(Guid riid)

namespace ABI.WinRT.Interop
{
using global::WinRT;
using WinRT.Interop;

public static class IWeakReferenceSourceMethods
{
public static unsafe global::WinRT.Interop.IWeakReference GetWeakReference(IObjectReference _obj)
{
var ThisPtr = _obj.ThisPtr;
IntPtr objRef = IntPtr.Zero;
try
{
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, int>**)ThisPtr)[3](ThisPtr, &objRef));
return MarshalInterface<global::WinRT.Interop.IWeakReference>.FromAbi(objRef);
}
finally
{
MarshalInspectable<object>.DisposeAbi(objRef);
}
}
}

[DynamicInterfaceCastableImplementation]
[Guid("00000038-0000-0000-C000-000000000046")]
internal unsafe interface IWeakReferenceSource : global::WinRT.Interop.IWeakReferenceSource
{
[Guid("00000038-0000-0000-C000-000000000046")]
public struct Vftbl
{
internal static readonly Guid IID = new(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

public static IntPtr AbiToProjectionVftablePtr;
static unsafe IWeakReferenceSource()
{
public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
private void* _GetWeakReference;
public delegate* unmanaged[Stdcall]<IntPtr, out IntPtr, int> GetWeakReference { get => (delegate* unmanaged[Stdcall]<IntPtr, out IntPtr, int>)_GetWeakReference; set => _GetWeakReference = value; }

public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;

static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,

_GetWeakReference = (delegate* unmanaged<IntPtr, IntPtr*, int>)&Do_Abi_GetWeakReference

};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}


[UnmanagedCallersOnly]

private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference)
{
*weakReference = default;

try
{
*weakReference = ComWrappersSupport.CreateCCWForObject(new global::WinRT.Interop.ManagedWeakReference(ComWrappersSupport.FindObject<object>(thisPtr))).As<ABI.WinRT.Interop.IWeakReference.Vftbl>().GetRef();
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
}
AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(IWeakReferenceSource), sizeof(global::WinRT.Interop.IUnknownVftbl) + sizeof(IntPtr) * 1);
*(global::WinRT.Interop.IUnknownVftbl*)AbiToProjectionVftablePtr = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl;
((delegate* unmanaged[Stdcall]<IntPtr, IntPtr*, int>*)AbiToProjectionVftablePtr)[3] = &Do_Abi_GetWeakReference;
}

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference)
{
*weakReference = default;

try
{
using var objRef = ComWrappersSupport.CreateCCWForObject(new global::WinRT.Interop.ManagedWeakReference(ComWrappersSupport.FindObject<object>(thisPtr)));
ExceptionHelpers.ThrowExceptionForHR(objRef.TryAs(IWeakReference.IID, out var ptr));
*weakReference = ptr;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
}

public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);

global::WinRT.Interop.IWeakReference global::WinRT.Interop.IWeakReferenceSource.GetWeakReference()
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IWeakReferenceSource).TypeHandle));
var ThisPtr = _obj.ThisPtr;

IntPtr objRef = IntPtr.Zero;
try
{
ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.GetWeakReference(ThisPtr, out objRef));
return MarshalInterface<global::WinRT.Interop.IWeakReference>.FromAbi(objRef);
}
finally
{
MarshalInspectable<object>.DisposeAbi(objRef);
}
var _obj = ((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IWeakReferenceSource).TypeHandle);
return IWeakReferenceSourceMethods.GetWeakReference(_obj);
}
}

[DynamicInterfaceCastableImplementation]
[Guid("00000037-0000-0000-C000-000000000046")]
internal unsafe interface IWeakReference : global::WinRT.Interop.IWeakReference
{
internal static readonly Guid IID = new(0x00000037, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

[Guid("00000037-0000-0000-C000-000000000046")]
public struct Vftbl
internal static readonly Guid IID = new(0x00000037, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);

public static IntPtr AbiToProjectionVftablePtr;
static unsafe IWeakReference()
{
public global::WinRT.Interop.IUnknownVftbl IUnknownVftbl;
private void* _Resolve;
public delegate* unmanaged[Stdcall]<IntPtr, ref Guid, out IntPtr, int> Resolve { get => (delegate* unmanaged[Stdcall]<IntPtr, ref Guid, out IntPtr, int>)_Resolve; set => _Resolve = value; }

public static readonly Vftbl AbiToProjectionVftable;
public static readonly IntPtr AbiToProjectionVftablePtr;


static Vftbl()
{
AbiToProjectionVftable = new Vftbl
{
IUnknownVftbl = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl,

_Resolve = (delegate* unmanaged<IntPtr, Guid*, IntPtr*, int>)&Do_Abi_Resolve

};
AbiToProjectionVftablePtr = Marshal.AllocHGlobal(Marshal.SizeOf<Vftbl>());
Marshal.StructureToPtr(AbiToProjectionVftable, AbiToProjectionVftablePtr, false);
}


[UnmanagedCallersOnly]

private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference)
{
IObjectReference _objectReference = default;

*objectReference = default;

try
{
_objectReference = global::WinRT.ComWrappersSupport.FindObject<global::WinRT.Interop.IWeakReference>(thisPtr).Resolve(*riid);
*objectReference = _objectReference?.GetRef() ?? IntPtr.Zero;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
}
AbiToProjectionVftablePtr = ComWrappersSupport.AllocateVtableMemory(typeof(IWeakReference), sizeof(global::WinRT.Interop.IUnknownVftbl) + sizeof(IntPtr) * 1);
*(global::WinRT.Interop.IUnknownVftbl*)AbiToProjectionVftablePtr = global::WinRT.Interop.IUnknownVftbl.AbiToProjectionVftbl;
((delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>*)AbiToProjectionVftablePtr)[3] = &Do_Abi_Resolve;
}

[UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]
private static int Do_Abi_Resolve(IntPtr thisPtr, Guid* riid, IntPtr* objectReference)
{
IObjectReference _objectReference = default;

*objectReference = default;

try
{
_objectReference = global::WinRT.ComWrappersSupport.FindObject<global::WinRT.Interop.IWeakReference>(thisPtr).Resolve(*riid);
*objectReference = _objectReference?.GetRef() ?? IntPtr.Zero;
}
catch (Exception __exception__)
{
return __exception__.HResult;
}
return 0;
}

public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);

IObjectReference global::WinRT.Interop.IWeakReference.Resolve(Guid riid)
{
var _obj = ((ObjectReference<Vftbl>)((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IWeakReference).TypeHandle));
var ThisPtr = _obj.ThisPtr;

ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.Resolve(ThisPtr, ref riid, out IntPtr objRef));
{
var _obj = ((IWinRTObject)this).GetObjectReferenceForType(typeof(global::WinRT.Interop.IWeakReference).TypeHandle);
var ThisPtr = _obj.ThisPtr;

IntPtr objRef;
ExceptionHelpers.ThrowExceptionForHR((*(delegate* unmanaged[Stdcall]<IntPtr, Guid*, IntPtr*, int>**)ThisPtr)[3](ThisPtr, &riid, &objRef));
try
{
return ComWrappersSupport.GetObjectReferenceForInterface(objRef);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,10 @@ private static int Do_Abi_GetWeakReference(IntPtr thisPtr, IntPtr* weakReference
}
return 0;
}
}

}

internal static readonly Guid IID = new(0x00000038, 0, 0, 0xC0, 0, 0, 0, 0, 0, 0, 0x46);
public static IntPtr AbiToProjectionVftablePtr => Vftbl.AbiToProjectionVftablePtr;
public static ObjectReference<Vftbl> FromAbi(IntPtr thisPtr) => ObjectReference<Vftbl>.FromAbi(thisPtr);

public static implicit operator IWeakReferenceSource(IObjectReference obj) => (obj != null) ? new IWeakReferenceSource(obj) : null;
Expand Down
5 changes: 3 additions & 2 deletions src/WinRT.Runtime/MatchingRefApiCompatBaseline.net5.0.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
Compat issues with assembly WinRT.Runtime:
TypesMustExist : Type 'ABI.WinRT.Interop.IWeakReferenceSourceMethods' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'System.Numerics.VectorExtensions' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.ComWrappersHelper' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public void WinRT.ComWrappersSupport.RegisterObjectForInterface(System.Object, System.IntPtr, System.Runtime.InteropServices.CreateObjectFlags)' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'protected void WinRT.IObjectReference.AddRef(System.Boolean)' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public System.Int32 WinRT.IObjectReference.TryAs(System.Guid, System.IntPtr)' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.Interop.IWeakReference' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.Interop.IWeakReferenceSource' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public System.Int32 WinRT.IObjectReference.TryAs(System.Guid, System.IntPtr)' does not exist in the reference but it does exist in the implementation.
Total Issues: 7
Total Issues: 8
6 changes: 3 additions & 3 deletions src/WinRT.Runtime/Projections/EventHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ static EventHandler()
public static global::System.Delegate AbiInvokeDelegate { get; }

public static unsafe IObjectReference CreateMarshaler(global::System.EventHandler<T> managedDelegate) =>
managedDelegate is null ? null : MarshalDelegate.CreateMarshaler(managedDelegate, GuidGenerator.GetIID(typeof(EventHandler<T>)));
managedDelegate is null ? null : MarshalDelegate.CreateMarshaler(managedDelegate, PIID);

public static IntPtr GetAbi(IObjectReference value) =>
value is null ? IntPtr.Zero : MarshalInterfaceHelper<global::System.EventHandler<T>>.GetAbi(value);

public static unsafe global::System.EventHandler<T> FromAbi(IntPtr nativeDelegate)
{
var abiDelegate = ComWrappersSupport.GetObjectReferenceForInterface(nativeDelegate)?.As<IDelegateVftbl>(GuidGenerator.GetIID(typeof(EventHandler<T>)));
var abiDelegate = ComWrappersSupport.GetObjectReferenceForInterface(nativeDelegate)?.As<IDelegateVftbl>(PIID);
return abiDelegate is null ? null : (global::System.EventHandler<T>)ComWrappersSupport.TryRegisterObjectForInterface(new global::System.EventHandler<T>(new NativeDelegateWrapper(abiDelegate).Invoke), nativeDelegate);
}

Expand Down Expand Up @@ -275,7 +275,7 @@ protected override Delegate GetEventInvoke()
{
global::System.EventHandler handler = (global::System.Object obj, global::System.EventArgs e) =>
{
var localDel = del;
var localDel = (global::System.EventHandler) del;
if (localDel != null)
localDel.Invoke(obj, e);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ protected override Delegate GetEventInvoke()
global::System.Collections.Specialized.NotifyCollectionChangedEventHandler handler =
(global::System.Object obj, global::System.Collections.Specialized.NotifyCollectionChangedEventArgs e) =>
{
var localDel = del;
var localDel = (global::System.Collections.Specialized.NotifyCollectionChangedEventHandler) del;
if (localDel != null)
localDel.Invoke(obj, e);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ protected override Delegate GetEventInvoke()
global::System.ComponentModel.PropertyChangedEventHandler handler =
(global::System.Object obj, global::System.ComponentModel.PropertyChangedEventArgs e) =>
{
var localDel = del;
var localDel = (global::System.ComponentModel.PropertyChangedEventHandler) del;
if (localDel != null)
localDel.Invoke(obj, e);
};
Expand Down
Loading

0 comments on commit b8d4b5e

Please sign in to comment.