Skip to content

Commit

Permalink
Bring over changes from the .NET 6 projection to .NET standard projec…
Browse files Browse the repository at this point in the history
…tion (#1298)

* Bring over changes from the .NET 5 projection to .NET standard projection to have similar behavior

* Remove namespace
  • Loading branch information
manodasanW authored Mar 14, 2023
1 parent 8d8f1e1 commit 609cda8
Showing 1 changed file with 40 additions and 17 deletions.
57 changes: 40 additions & 17 deletions src/WinRT.Runtime/ComWrappersSupport.netstandard2.0.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,14 @@ static partial class ComWrappersSupport
private static ConcurrentDictionary<IntPtr, System.WeakReference<object>> RuntimeWrapperCache = new ConcurrentDictionary<IntPtr, System.WeakReference<object>>();
private readonly static ConcurrentDictionary<Type, Func<object, IObjectReference>> TypeObjectRefFuncCache = new ConcurrentDictionary<Type, Func<object, IObjectReference>>();

internal static InspectableInfo GetInspectableInfo(IntPtr pThis) => UnmanagedObject.FindObject<ComCallableWrapper>(pThis).InspectableInfo;
internal static InspectableInfo GetInspectableInfo(IntPtr pThis) => UnmanagedObject.FindObject<ComCallableWrapper>(pThis).InspectableInfo;

public static T CreateRcwForComObject<T>(IntPtr ptr)
{
return CreateRcwForComObject<T>(ptr, true);
}

public static T CreateRcwForComObject<T>(IntPtr ptr)
private static T CreateRcwForComObject<T>(IntPtr ptr, bool tryUseCache)
{
if (ptr == IntPtr.Zero)
{
Expand All @@ -47,9 +52,17 @@ public static T CreateRcwForComObject<T>(IntPtr ptr)
}
else if (identity.TryAs<IInspectable.Vftbl>(out var inspectableRef) == 0)
{
var inspectable = new IInspectable(identity);
Type runtimeClassType = GetRuntimeClassForTypeCreation(inspectable, typeof(T));
runtimeWrapper = runtimeClassType == null ? inspectable : TypedObjectFactoryCacheForType.GetOrAdd(runtimeClassType, classType => CreateTypedRcwFactory(classType))(inspectable);
var inspectable = new IInspectable(identity);

if (typeof(T).IsSealed)
{
runtimeWrapper = TypedObjectFactoryCacheForType.GetOrAdd(typeof(T), classType => CreateTypedRcwFactory(classType))(inspectable);
}
else
{
Type runtimeClassType = GetRuntimeClassForTypeCreation(inspectable, typeof(T));
runtimeWrapper = runtimeClassType == null ? inspectable : TypedObjectFactoryCacheForType.GetOrAdd(runtimeClassType, classType => CreateTypedRcwFactory(classType))(inspectable);
}
}
else if (identity.TryAs<ABI.WinRT.Interop.IWeakReference.Vftbl>(out var weakRef) == 0)
{
Expand All @@ -62,17 +75,25 @@ public static T CreateRcwForComObject<T>(IntPtr ptr)
return runtimeWrapperReference;
};

RuntimeWrapperCache.AddOrUpdate(
identity.ThisPtr,
rcwFactory,
(ptr, oldValue) =>
{
if (!oldValue.TryGetTarget(out keepAliveSentinel))
{
return rcwFactory(ptr);
}
return oldValue;
}).TryGetTarget(out object rcw);
object rcw;
if (tryUseCache)
{
RuntimeWrapperCache.AddOrUpdate(
identity.ThisPtr,
rcwFactory,
(ptr, oldValue) =>
{
if (!oldValue.TryGetTarget(out keepAliveSentinel))
{
return rcwFactory(ptr);
}
return oldValue;
}).TryGetTarget(out rcw);
}
else
{
rcwFactory(ptr).TryGetTarget(out rcw);
}

GC.KeepAlive(keepAliveSentinel);

Expand All @@ -86,7 +107,9 @@ public static T CreateRcwForComObject<T>(IntPtr ptr)
return rcw switch
{
ABI.System.Nullable nt => (T)nt.Value,
_ => (T)rcw
T castRcw => castRcw,
_ when tryUseCache => CreateRcwForComObject<T>(ptr, false),
_ => throw new ArgumentException(string.Format("Unable to create a wrapper object. The WinRT object {0} has type {1} which cannot be assigned to type {2}", ptr, rcw.GetType(), typeof(T)))
};
}

Expand Down

0 comments on commit 609cda8

Please sign in to comment.