@@ -108,7 +108,15 @@ internal static WindowsRuntimeObjectReference InitializeFromManagedTypeUnsafe(
108108 // will have the 'IReferenceTracker' implementation. Otherwise, the new instance will be used. Since the
109109 // inner was composed, it should answer immediately without going through the outer. Either way, the
110110 // reference count will go to the new instance.
111- _ = IUnknownVftbl . QueryInterfaceUnsafe ( externalComObject , in WellKnownWindowsInterfaceIIDs . IID_IReferenceTracker , out void * referenceTracker ) ;
111+ HRESULT isReferenceTracker = IUnknownVftbl . QueryInterfaceUnsafe ( externalComObject , in WellKnownWindowsInterfaceIIDs . IID_IReferenceTracker , out void * referenceTracker ) ;
112+
113+ // We have seen scenarios where 'QueryInterface' is not set to 'null' on failure (for instance, both UWP XAML
114+ // and WinUI 3 objects don't do this), so if the call failed we manually set the resulting pointer to 'null'.
115+ // This allows the following code to rely on the pointer value to determine how to handle reference tracking.
116+ if ( isReferenceTracker . Failed )
117+ {
118+ referenceTracker = null ;
119+ }
112120
113121 // Determine the flags needed for the native object wrapper (ie. RCW) creation.
114122 // These are the ones we'll pass to 'ComWrappers' to register the new object.
@@ -296,9 +304,9 @@ internal static WindowsRuntimeObjectReference InitializeObjectReferenceUnsafe(vo
296304 Marshal . ThrowExceptionForHR ( isFreeThreaded ) ;
297305
298306 // Try to resolve an 'IReferenceTracker' pointer (see detailed notes above)
299- _ = IUnknownVftbl . QueryInterfaceUnsafe ( externalComObject , in WellKnownWindowsInterfaceIIDs . IID_IReferenceTracker , out void * referenceTracker ) ;
307+ HRESULT isReferenceTracker = IUnknownVftbl . QueryInterfaceUnsafe ( externalComObject , in WellKnownWindowsInterfaceIIDs . IID_IReferenceTracker , out void * referenceTracker ) ;
300308
301- if ( referenceTracker is not null )
309+ if ( isReferenceTracker . Succeeded )
302310 {
303311 // If we have a reference tracker, we should report an 'AddRef' on it,
304312 // as we're wrapping the native object in a managed object reference.
@@ -309,6 +317,11 @@ internal static WindowsRuntimeObjectReference InitializeObjectReferenceUnsafe(vo
309317 // This matches the handling of non aggregation scenarios above.
310318 _ = IUnknownVftbl . ReleaseUnsafe ( referenceTracker ) ;
311319 }
320+ else
321+ {
322+ // Ensure the 'IReferenceTracker' pointer is 'null' in case of failure (see notes above)
323+ referenceTracker = null ;
324+ }
312325
313326 // We're going to store the input object, so increment its ref count
314327 _ = IUnknownVftbl . AddRefUnsafe ( externalComObject ) ;
@@ -351,15 +364,20 @@ private static WindowsRuntimeObjectReference InitializeObjectReferenceUnsafe(ref
351364 }
352365
353366 // Try to resolve an 'IReferenceTracker' pointer (see detailed notes above)
354- _ = IUnknownVftbl . QueryInterfaceUnsafe ( acquiredExternalComObject , in WellKnownWindowsInterfaceIIDs . IID_IReferenceTracker , out void * referenceTracker ) ;
367+ HRESULT isReferenceTracker = IUnknownVftbl . QueryInterfaceUnsafe ( acquiredExternalComObject , in WellKnownWindowsInterfaceIIDs . IID_IReferenceTracker , out void * referenceTracker ) ;
355368
356369 // If we resolved a reference tracker, set it up (see notes above)
357- if ( referenceTracker is not null )
370+ if ( isReferenceTracker . Succeeded )
358371 {
359372 _ = IReferenceTrackerVftbl . AddRefFromTrackerSourceUnsafe ( referenceTracker ) ;
360373
361374 _ = IUnknownVftbl . ReleaseUnsafe ( referenceTracker ) ;
362375 }
376+ else
377+ {
378+ // Ensure the 'IReferenceTracker' pointer is 'null' in case of failure (see notes above)
379+ referenceTracker = null ;
380+ }
363381
364382 // Special case for free-threaded object references (see notes above)
365383 if ( isFreeThreaded == WellKnownErrorCodes . S_OK )
0 commit comments