Skip to content

Commit

Permalink
Expose api's for Context on ObjectReference. (#1466)
Browse files Browse the repository at this point in the history
* Expose api's for Context on ObjectReference.

* Add GC.KeepAlive.

* Add old signature back.

* Keep Resurrect.

* Use Unsafe.AsRef

* Update projections.

* Fix.

* Update baseline.

* Use virtual method to safe cost of a field in every instance.

* Fix passing iid.
  • Loading branch information
jlaanstra authored Jan 24, 2024
1 parent 49e1e54 commit b207988
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 220 deletions.
59 changes: 21 additions & 38 deletions src/WinRT.Runtime/ComWrappersSupport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,15 @@ public static void MarshalDelegateInvoke<T>(IntPtr thisPtr, Action<T> invoke)

// If we are free threaded, we do not need to keep track of context.
// This can either be if the object implements IAgileObject or the free threaded marshaler.
internal unsafe static bool IsFreeThreaded(IObjectReference objRef)
internal unsafe static bool IsFreeThreaded(IntPtr iUnknown)
{
if (objRef.TryAs(InterfaceIIDs.IAgileObject_IID, out var agilePtr) >= 0)
if (Marshal.QueryInterface(iUnknown, ref Unsafe.AsRef(InterfaceIIDs.IAgileObject_IID), out var agilePtr) >= 0)
{
Marshal.Release(agilePtr);
return true;
}
else if (objRef.TryAs(InterfaceIIDs.IMarshal_IID, out var marshalPtr) >= 0)

if (Marshal.QueryInterface(iUnknown, ref Unsafe.AsRef(InterfaceIIDs.IMarshal_IID), out var marshalPtr) >= 0)
{
try
{
Expand All @@ -103,6 +104,14 @@ internal unsafe static bool IsFreeThreaded(IObjectReference objRef)
return false;
}

internal unsafe static bool IsFreeThreaded(IObjectReference objRef)
{
var isFreeThreaded = IsFreeThreaded(objRef.ThisPtr);
// ThisPtr is owned by objRef, so need to make sure objRef stays alive.
GC.KeepAlive(objRef);
return isFreeThreaded;
}

public static IObjectReference GetObjectReferenceForInterface(IntPtr externalComObject)
{
return GetObjectReferenceForInterface<IUnknownVftbl>(externalComObject);
Expand All @@ -115,21 +124,7 @@ public static ObjectReference<T> GetObjectReferenceForInterface<T>(IntPtr extern
return null;
}

ObjectReference<T> objRef = ObjectReference<T>.FromAbi(externalComObject);
if (IsFreeThreaded(objRef))
{
return objRef;
}
else
{
using (objRef)
{
return new ObjectReferenceWithContext<T>(
objRef.GetRef(),
Context.GetContextCallback(),
Context.GetContextToken());
}
}
return ObjectReference<T>.FromAbi(externalComObject);
}

public static ObjectReference<T> GetObjectReferenceForInterface<T>(IntPtr externalComObject, Guid iid)
Expand All @@ -144,31 +139,14 @@ internal static ObjectReference<T> GetObjectReferenceForInterface<T>(IntPtr exte
return null;
}

ObjectReference<T> objRef;
if (requireQI)
{
Marshal.ThrowExceptionForHR(Marshal.QueryInterface(externalComObject, ref iid, out IntPtr ptr));
objRef = ObjectReference<T>.Attach(ref ptr);
return ObjectReference<T>.Attach(ref ptr, iid);
}
else
{
objRef = ObjectReference<T>.FromAbi(externalComObject);
}

if (IsFreeThreaded(objRef))
{
return objRef;
}
else
{
using (objRef)
{
return new ObjectReferenceWithContext<T>(
objRef.GetRef(),
Context.GetContextCallback(),
Context.GetContextToken(),
iid);
}
return ObjectReference<T>.FromAbi(externalComObject, iid);
}
}

Expand Down Expand Up @@ -487,7 +465,12 @@ private static Func<IInspectable, object> CreateCustomTypeMappingFactory(Type cu
}

var fromAbiMethodFunc = (Func<IntPtr, object>) fromAbiMethod.CreateDelegate(typeof(Func<IntPtr, object>));
return (IInspectable obj) => fromAbiMethodFunc(obj.ThisPtr);
return (IInspectable obj) =>
{
var fromAbiMethod = fromAbiMethodFunc(obj.ThisPtr);
GC.KeepAlive(obj);
return fromAbiMethod;
};
}

internal static Func<IInspectable, object> CreateTypedRcwFactory(
Expand Down
10 changes: 4 additions & 6 deletions src/WinRT.Runtime/ComWrappersSupport.net5.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public static object TryRegisterObjectForInterface(object obj, IntPtr thisPtr)
public static IObjectReference CreateCCWForObject(object obj)
{
IntPtr ccw = ComWrappers.GetOrCreateComInterfaceForObject(obj, CreateComInterfaceFlags.TrackerSupport);
return ObjectReference<IUnknownVftbl>.Attach(ref ccw);
return ObjectReference<IUnknownVftbl>.Attach(ref ccw, InterfaceIIDs.IUnknown_IID);
}

internal static IntPtr CreateCCWForObjectForABI(object obj, Guid iid)
Expand Down Expand Up @@ -350,8 +350,7 @@ public unsafe static void Init(
// otherwise the new instance will be used. Since the inner was composed
// it should answer immediately without going through the outer. Either way
// the reference count will go to the new instance.
Guid iid = IReferenceTrackerVftbl.IID;
int hr = Marshal.QueryInterface(objRef.ThisPtr, ref iid, out referenceTracker);
int hr = Marshal.QueryInterface(objRef.ThisPtr, ref Unsafe.AsRef(IReferenceTrackerVftbl.IID), out referenceTracker);
if (hr != 0)
{
referenceTracker = default;
Expand Down Expand Up @@ -450,9 +449,8 @@ public unsafe static void Init(
public unsafe static void Init(IObjectReference objRef, bool addRefFromTrackerSource = true)
{
if (objRef.ReferenceTrackerPtr == IntPtr.Zero)
{
Guid iid = IReferenceTrackerVftbl.IID;
int hr = Marshal.QueryInterface(objRef.ThisPtr, ref iid, out var referenceTracker);
{
int hr = Marshal.QueryInterface(objRef.ThisPtr, ref Unsafe.AsRef(IReferenceTrackerVftbl.IID), out var referenceTracker);
if (hr == 0)
{
// WinUI scenario
Expand Down
1 change: 1 addition & 0 deletions src/WinRT.Runtime/ExceptionHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ public static void ReportUnhandledError(Exception ex)
if (restrictedErrorInfoRef != null)
{
roReportUnhandledError(restrictedErrorInfoRef.ThisPtr);
GC.KeepAlive(restrictedErrorInfoRef);
}
}
}
Expand Down
3 changes: 1 addition & 2 deletions src/WinRT.Runtime/Marshalers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1581,8 +1581,7 @@ public static T FromAbi(IntPtr ptr)
IntPtr iunknownPtr = IntPtr.Zero;
try
{
Guid iid_iunknown = IUnknownVftbl.IID;
Marshal.QueryInterface(ptr, ref iid_iunknown, out iunknownPtr);
Marshal.QueryInterface(ptr, ref Unsafe.AsRef(IUnknownVftbl.IID), out iunknownPtr);
if (IUnknownVftbl.IsReferenceToManagedObject(iunknownPtr))
{
return (T)ComWrappersSupport.FindObject<object>(iunknownPtr);
Expand Down
7 changes: 6 additions & 1 deletion src/WinRT.Runtime/MatchingRefApiCompatBaseline.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,9 @@ MembersMustExist : Member 'public System.String WinRT.WindowsRuntimeTypeAttribut
TypesMustExist : Type 'WinRT.WinRTExposedTypeAttribute' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public T ABI.System.Nullable<T>.GetValue(WinRT.IInspectable)' does not exist in the reference but it does exist in the implementation.
TypesMustExist : Type 'WinRT.EventRegistrationTokenTable<T>' does not exist in the reference but it does exist in the implementation.
Total Issues: 132
MembersMustExist : Member 'public System.Boolean WinRT.IObjectReference.IsFreeThreaded.get()' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public System.Boolean WinRT.IObjectReference.IsInCurrentContext.get()' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public WinRT.ObjectReference<T> WinRT.ObjectReference<T>.Attach(System.IntPtr, System.Guid)' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public WinRT.ObjectReference<T> WinRT.ObjectReference<T>.FromAbi(System.IntPtr, System.Guid)' does not exist in the reference but it does exist in the implementation.
MembersMustExist : Member 'public WinRT.ObjectReference<T> WinRT.ObjectReference<T>.FromAbi(System.IntPtr, T, System.Guid)' does not exist in the reference but it does exist in the implementation.
Total Issues: 137
Loading

0 comments on commit b207988

Please sign in to comment.