@@ -261,6 +261,56 @@ static void ValidatePrecreatedExternalWrapper()
261261 } ) ;
262262 }
263263
264+ static void ValidateExternalWrapperCacheCleanUp ( )
265+ {
266+ Console . WriteLine ( $ "Running { nameof ( ValidateExternalWrapperCacheCleanUp ) } ...") ;
267+
268+ var cw = new TestComWrappers ( ) ;
269+
270+ // Get an object from a tracker runtime.
271+ IntPtr trackerObjRaw = MockReferenceTrackerRuntime . CreateTrackerObject ( ) ;
272+
273+ // Create a wrapper for the object instance.
274+ var weakRef1 = CreateAndRegisterWrapper ( cw , trackerObjRaw ) ;
275+
276+ // Run the GC to have the wrapper marked for collection.
277+ ForceGC ( ) ;
278+
279+ // Create a new wrapper for the same external object.
280+ var weakRef2 = CreateAndRegisterWrapper ( cw , trackerObjRaw ) ;
281+
282+ // We are using a tracking resurrection WeakReference<T> so we should be able
283+ // to get back the objects as they are all continually re-registering for Finalization.
284+ Assert . IsTrue ( weakRef1 . TryGetTarget ( out ITrackerObjectWrapper wrapper1 ) ) ;
285+ Assert . IsTrue ( weakRef2 . TryGetTarget ( out ITrackerObjectWrapper wrapper2 ) ) ;
286+
287+ // Check that the two wrappers aren't equal, meaning we created a new wrapper since
288+ // the first wrapper was removed from the internal cache.
289+ Assert . AreNotEqual ( wrapper1 , wrapper2 ) ;
290+
291+ // Let the wrappers Finalize.
292+ wrapper1 . ReregisterForFinalize = false ;
293+ wrapper2 . ReregisterForFinalize = false ;
294+
295+ static WeakReference < ITrackerObjectWrapper > CreateAndRegisterWrapper ( ComWrappers cw , IntPtr trackerObjRaw )
296+ {
297+ // Manually create a wrapper
298+ var iid = typeof ( ITrackerObject ) . GUID ;
299+ IntPtr iTestComObject ;
300+ int hr = Marshal . QueryInterface ( trackerObjRaw , ref iid , out iTestComObject ) ;
301+ Assert . AreEqual ( 0 , hr ) ;
302+ var nativeWrapper = new ITrackerObjectWrapper ( iTestComObject ) ;
303+
304+ nativeWrapper = ( ITrackerObjectWrapper ) cw . GetOrRegisterObjectForComInstance ( trackerObjRaw , CreateObjectFlags . None , nativeWrapper ) ;
305+
306+ // Set this on the return instead of during creation since the returned wrapper may be the one from
307+ // the internal cache and not the one passed in above.
308+ nativeWrapper . ReregisterForFinalize = true ;
309+
310+ return new WeakReference < ITrackerObjectWrapper > ( nativeWrapper , trackResurrection : true ) ;
311+ }
312+ }
313+
264314 static void ValidateIUnknownImpls ( )
265315 => TestComWrappers . ValidateIUnknownImpls ( ) ;
266316
@@ -477,6 +527,7 @@ static int Main(string[] doNotUse)
477527 ValidateCreateObjectCachingScenario ( ) ;
478528 ValidateWrappersInstanceIsolation ( ) ;
479529 ValidatePrecreatedExternalWrapper ( ) ;
530+ ValidateExternalWrapperCacheCleanUp ( ) ;
480531 ValidateIUnknownImpls ( ) ;
481532 ValidateBadComWrapperImpl ( ) ;
482533 ValidateRuntimeTrackerScenario ( ) ;
0 commit comments