Exemplo n.º 1
0
        static void ValidateExternalWrapperCacheCleanUp()
        {
            Console.WriteLine($"Running {nameof(ValidateExternalWrapperCacheCleanUp)}...");

            var cw = new TestComWrappers();

            // Get an object from a tracker runtime.
            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();

            // Create a wrapper for the object instance.
            var weakRef1 = CreateAndRegisterWrapper(cw, trackerObjRaw);

            // Run the GC to have the wrapper marked for collection.
            ForceGC();

            // Create a new wrapper for the same external object.
            var weakRef2 = CreateAndRegisterWrapper(cw, trackerObjRaw);

            // We are using a tracking resurrection WeakReference<T> so we should be able
            // to get back the objects as they are all continually re-registering for Finalization.
            Assert.True(weakRef1.TryGetTarget(out ITrackerObjectWrapper wrapper1));
            Assert.True(weakRef2.TryGetTarget(out ITrackerObjectWrapper wrapper2));

            // Check that the two wrappers aren't equal, meaning we created a new wrapper since
            // the first wrapper was removed from the internal cache.
            Assert.NotEqual(wrapper1, wrapper2);

            // Let the wrappers Finalize.
            wrapper1.ReregisterForFinalize = false;
            wrapper2.ReregisterForFinalize = false;
Exemplo n.º 2
0
        static void ValidateGlobalInstanceScenarios()
        {
            Console.WriteLine($"Running {nameof(ValidateGlobalInstanceScenarios)}...");
            Console.WriteLine($"Validate RegisterAsGlobalInstance()...");

            var wrappers1 = TestComWrappers.Global;

            wrappers1.RegisterAsGlobalInstance();

            Assert.Throws <InvalidOperationException>(
                () =>
            {
                wrappers1.RegisterAsGlobalInstance();
            }, "Should not be able to re-register for global ComWrappers");

            var wrappers2 = new TestComWrappers();

            Assert.Throws <InvalidOperationException>(
                () =>
            {
                wrappers2.RegisterAsGlobalInstance();
            }, "Should not be able to reset for global ComWrappers");

            Console.WriteLine($"Validate NotifyEndOfReferenceTrackingOnThread()...");

            int hr;
            var cw = TestComWrappers.Global;

            // Trigger the thread lifetime end API and verify the callback occurs.
            hr = MockReferenceTrackerRuntime.Trigger_NotifyEndOfReferenceTrackingOnThread();
            Assert.AreEqual(TestComWrappers.ReleaseObjectsCallAck, hr);
        }
Exemplo n.º 3
0
        static void ValidateFallbackQueryInterface()
        {
            Console.WriteLine($"Running {nameof(ValidateFallbackQueryInterface)}...");

            var testObj = new Test()
            {
                EnableICustomQueryInterface = true
            };

            var wrappers = new TestComWrappers();

            // Allocate a wrapper for the object
            IntPtr comWrapper = wrappers.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.None);

            testObj.ICustomQueryInterface_GetInterfaceResult = new IntPtr(0x2000000);

            IntPtr result;
            var    anyGuid = new Guid("1E42439C-DCB5-4701-ACBD-87FE92E785DE");

            testObj.ICustomQueryInterface_GetInterfaceIID = anyGuid;
            int hr = Marshal.QueryInterface(comWrapper, ref anyGuid, out result);

            Assert.AreEqual(hr, 0);
            Assert.AreEqual(result, testObj.ICustomQueryInterface_GetInterfaceResult);

            var anyGuid2 = new Guid("7996D0F9-C8DD-4544-B708-0F75C6FF076F");

            hr = Marshal.QueryInterface(comWrapper, ref anyGuid2, out result);
            const int E_NOINTERFACE = unchecked ((int)0x80004002);

            Assert.AreEqual(hr, E_NOINTERFACE);
            Assert.AreEqual(result, IntPtr.Zero);
        }
Exemplo n.º 4
0
        static void ValidateComInterfaceCreation()
        {
            Console.WriteLine($"Running {nameof(ValidateComInterfaceCreation)}...");

            var testObj = new Test();

            var wrappers = new TestComWrappers();

            // Allocate a wrapper for the object
            IntPtr comWrapper = wrappers.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);

            Assert.AreNotEqual(comWrapper, IntPtr.Zero);

            // Get a wrapper for an object and verify it is the same one.
            IntPtr comWrapperMaybe = wrappers.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);

            Assert.AreEqual(comWrapper, comWrapperMaybe);

            // Release the wrapper
            int count = Marshal.Release(comWrapper);

            Assert.AreEqual(count, 1);
            count = Marshal.Release(comWrapperMaybe);
            Assert.AreEqual(count, 0);

            // Create a new wrapper
            IntPtr comWrapperNew = wrappers.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);

            // Once a wrapper is created for a managed object it is always present
            Assert.AreEqual(comWrapperNew, comWrapper);

            // Release the new wrapper
            count = Marshal.Release(comWrapperNew);
            Assert.AreEqual(count, 0);
        }
Exemplo n.º 5
0
        public DerivedObject(TestComWrappers comWrappersInstance)
        {
            IntPtr innerInstance = WeakReferenceNative.CreateAggregatedWeakReferenceObject(
                comWrappersInstance.GetOrCreateComInterfaceForObject(this, CreateComInterfaceFlags.None));

            inner = new WeakReferenceableWrapper(innerInstance, comWrappersInstance.Registration, releaseInFinalizer: false);
            comWrappersInstance.GetOrRegisterObjectForComInstance(innerInstance, CreateObjectFlags.Aggregation, this);
        }
Exemplo n.º 6
0
            static (WeakReference <WeakReferencableWrapper>, IntPtr) GetWeakReference()
            {
                var cw = new TestComWrappers();

                IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject();

                var obj = (WeakReferencableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None);

                return(new WeakReference <WeakReferencableWrapper>(obj), objRaw);
            }
Exemplo n.º 7
0
        static void ValidateRuntimeTrackerScenario()
        {
            Console.WriteLine($"Running {nameof(ValidateRuntimeTrackerScenario)}...");

            var cw = new TestComWrappers();

            // Get an object from a tracker runtime.
            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();

            // Create a managed wrapper for the native object.
            var trackerObj = (ITrackerObjectWrapper)cw.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);

            // Ownership has been transferred to the wrapper.
            Marshal.Release(trackerObjRaw);

            var testWrapperIds = new List <int>();

            for (int i = 0; i < 1000; ++i)
            {
                // Create a native wrapper for the managed object.
                IntPtr testWrapper = cw.GetOrCreateComInterfaceForObject(new Test(), CreateComInterfaceFlags.TrackerSupport);

                // Pass the managed object to the native object.
                int id = trackerObj.AddObjectRef(testWrapper);

                // Retain the managed object wrapper ptr.
                testWrapperIds.Add(id);

                Marshal.Release(testWrapper);
            }

            Assert.IsTrue(testWrapperIds.Count <= Test.InstanceCount);

            GC.Collect();
            GC.Collect();
            GC.Collect();
            GC.Collect();
            GC.Collect();

            Assert.IsTrue(testWrapperIds.Count <= Test.InstanceCount);

            // Remove the managed object ref from the native object.
            foreach (int id in testWrapperIds)
            {
                trackerObj.DropObjectRef(id);
            }

            testWrapperIds.Clear();

            GC.Collect();
            GC.Collect();
            GC.Collect();
            GC.Collect();
            GC.Collect();
        }
Exemplo n.º 8
0
        static void ValidateAggregationWithComObject()
        {
            Console.WriteLine($"Running {nameof(ValidateAggregationWithComObject)}...");

            using var allocTracker = MockReferenceTrackerRuntime.CountTrackerObjectAllocations();
            var cw = new TestComWrappers();
            WeakReference <Derived> weakRef = Derived.AllocateAndUseBaseType(cw, aggregateRefTracker: false);

            ForceGC();

            // Validate all instances were cleaned up
            Assert.IsFalse(weakRef.TryGetTarget(out _));
            Assert.AreEqual(0, allocTracker.GetCount());
        }
Exemplo n.º 9
0
            static (WeakReference <WeakReferencableWrapper>, IntPtr) GetWeakReference()
            {
                var cw = new TestComWrappers();

                IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject();

                var obj = (WeakReferencableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None);

                // The returned WeakReferencableWrapper from ComWrappers takes ownership
                // of the ref returned from CreateWeakReferencableObject.
                // Call Marshal.AddRef to ensure that objRaw owns a reference.
                Marshal.AddRef(objRaw);

                return(new WeakReference <WeakReferencableWrapper>(obj), objRaw);
            }
Exemplo n.º 10
0
        static void ValidateWrappersInstanceIsolation()
        {
            Console.WriteLine($"Running {nameof(ValidateWrappersInstanceIsolation)}...");

            var cw1 = new TestComWrappers();
            var cw2 = new TestComWrappers();

            var testObj = new Test();

            // Allocate a wrapper for the object
            IntPtr comWrapper1 = cw1.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);
            IntPtr comWrapper2 = cw2.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);

            Assert.AreNotEqual(comWrapper1, IntPtr.Zero);
            Assert.AreNotEqual(comWrapper2, IntPtr.Zero);
            Assert.AreNotEqual(comWrapper1, comWrapper2);

            IntPtr comWrapper3 = cw1.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);
            IntPtr comWrapper4 = cw2.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.TrackerSupport);

            Assert.AreNotEqual(comWrapper3, comWrapper4);
            Assert.AreEqual(comWrapper1, comWrapper3);
            Assert.AreEqual(comWrapper2, comWrapper4);

            Marshal.Release(comWrapper1);
            Marshal.Release(comWrapper2);
            Marshal.Release(comWrapper3);
            Marshal.Release(comWrapper4);

            // Get an object from a tracker runtime.
            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();

            // Create objects for the COM instance
            var trackerObj1 = (ITrackerObjectWrapper)cw1.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);
            var trackerObj2 = (ITrackerObjectWrapper)cw2.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);

            Assert.AreNotEqual(trackerObj1, trackerObj2);

            var trackerObj3 = (ITrackerObjectWrapper)cw1.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);
            var trackerObj4 = (ITrackerObjectWrapper)cw2.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);

            Assert.AreNotEqual(trackerObj3, trackerObj4);
            Assert.AreEqual(trackerObj1, trackerObj3);
            Assert.AreEqual(trackerObj2, trackerObj4);

            Marshal.Release(trackerObjRaw);
        }
Exemplo n.º 11
0
        private static void ValidateNativeWeakReference(TestComWrappers cw)
        {
            Console.WriteLine($"  -- Validate weak reference creation");
            var(weakRef, nativeRef) = GetWeakReference(cw);

            // Make sure RCW is collected
            GC.Collect();
            GC.WaitForPendingFinalizers();

            // Non-globally registered ComWrappers instances do not support rehydration.
            // A weak reference to an RCW wrapping an IWeakReference can stay alive if the RCW was created through
            // a global ComWrappers instance. If the RCW was created throug a local ComWrappers instance, the weak
            // reference should be dead and stay dead once the RCW is collected.
            bool supportsRehydration = cw.Registration != WrapperRegistration.Local;

            Console.WriteLine($"    -- Validate RCW recreation");
            ValidateWeakReferenceState(weakRef, expectedIsAlive: supportsRehydration, cw);

            // Release the last native reference.
            Marshal.Release(nativeRef);
            GC.Collect();
            GC.WaitForPendingFinalizers();

            // After all native references die and the RCW is collected, the weak reference should be dead and stay dead.
            Console.WriteLine($"    -- Validate release");
            ValidateWeakReferenceState(weakRef, expectedIsAlive: false);

            // Reset the weak reference target
            Console.WriteLine($"  -- Validate target reset");
            nativeRef = SetWeakReferenceTarget(weakRef, cw);

            // Make sure RCW is collected
            GC.Collect();
            GC.WaitForPendingFinalizers();

            Console.WriteLine($"    -- Validate RCW recreation");
            ValidateWeakReferenceState(weakRef, expectedIsAlive: supportsRehydration, cw);

            // Release the last native reference.
            Marshal.Release(nativeRef);
            GC.Collect();
            GC.WaitForPendingFinalizers();

            // After all native references die and the RCW is collected, the weak reference should be dead and stay dead.
            Console.WriteLine($"    -- Validate release");
            ValidateWeakReferenceState(weakRef, expectedIsAlive: false);
        }
Exemplo n.º 12
0
        static void ValidateQueryInterfaceAfterManagedObjectCollected()
        {
            Console.WriteLine($"Running {nameof(ValidateQueryInterfaceAfterManagedObjectCollected)}...");

            var cw = new TestComWrappers();

            {
                // Activate the Reference Tracker system in the .NET runtime by consuming an IReferenceTracker instance.
                IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();
                var    trackerObj    = (ITrackerObjectWrapper)cw.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);
                Marshal.Release(trackerObjRaw);
            }

            int    refCount;
            IntPtr refTrackerTarget;

            {
                // Create a native wrapper over a managed object.
                IntPtr testWrapper = CreateWrapper(cw);

                refTrackerTarget = MockReferenceTrackerRuntime.TrackerTarget_AddRefFromReferenceTrackerAndReturn(testWrapper);

                // Ownership has been transferred to the IReferenceTrackerTarget instance.
                // The COM reference count should be 0 and indicates to the GC the managed object
                // can be collected.
                refCount = Marshal.Release(testWrapper);
                Assert.AreEqual(0, refCount);
            }

            ForceGC();

            // Calling QueryInterface on an IReferenceTrackerTarget instance is permitted when
            // the wrapper lifetime has been extended. However, the QueryInterface may fail
            // if the associated managed object was collected. The failure here is an important
            // part of the contract for a Reference Tracker runtime.
            var    iid = typeof(ITest).GUID;
            IntPtr iTestComObject;
            int    hr = Marshal.QueryInterface(refTrackerTarget, ref iid, out iTestComObject);

            const int COR_E_ACCESSING_CCW = unchecked ((int)0x80131544);

            Assert.AreEqual(COR_E_ACCESSING_CCW, hr);

            // Release the IReferenceTrackerTarget instance.
            refCount = MockReferenceTrackerRuntime.TrackerTarget_ReleaseFromReferenceTracker(refTrackerTarget);
            Assert.AreEqual(0, refCount);
Exemplo n.º 13
0
        static void ValidateSuppliedInnerNotAggregation()
        {
            Console.WriteLine($"Running {nameof(ValidateSuppliedInnerNotAggregation)}...");

            var cw = new TestComWrappers();

            // Attempt to register a non-zero instance with a non-zero inner value without
            // indicating the scenario is aggregaion.
            var invalidInstance = new IntPtr(1);
            var invalidInner    = new IntPtr(2);

            Assert.Throws <InvalidOperationException>(
                () =>
            {
                cw.GetOrRegisterObjectForComInstance(invalidInstance, CreateObjectFlags.None, new object(), invalidInner);
            });
        }
Exemplo n.º 14
0
        static void ValidateAggregationWithReferenceTrackerObject()
        {
            Console.WriteLine($"Running {nameof(ValidateAggregationWithReferenceTrackerObject)}...");

            using var allocTracker = MockReferenceTrackerRuntime.CountTrackerObjectAllocations();
            var cw = new TestComWrappers();
            WeakReference <Derived> weakRef = Derived.AllocateAndUseBaseType(cw, aggregateRefTracker: true);

            ForceGC();

            // Validate all instances were cleaned up.
            Assert.IsFalse(weakRef.TryGetTarget(out _));

            // Reference counter cleanup requires additional GCs since the Finalizer is used
            // to clean up the Reference Tracker runtime references.
            ForceGC();

            Assert.AreEqual(0, allocTracker.GetCount());
        }
Exemplo n.º 15
0
        static void ValidatePrecreatedExternalWrapper()
        {
            Console.WriteLine($"Running {nameof(ValidatePrecreatedExternalWrapper)}...");

            var cw = new TestComWrappers();

            // Get an object from a tracker runtime.
            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();

            // Manually create a wrapper
            var    iid = typeof(ITrackerObject).GUID;
            IntPtr iTestComObject;
            int    hr = Marshal.QueryInterface(trackerObjRaw, ref iid, out iTestComObject);

            Assert.AreEqual(hr, 0);
            var nativeWrapper = new ITrackerObjectWrapper(iTestComObject);

            // Register wrapper, but supply the wrapper.
            var nativeWrapper2 = (ITrackerObjectWrapper)cw.GetOrRegisterObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject, nativeWrapper);

            Assert.AreEqual(nativeWrapper, nativeWrapper2);

            // Ownership has been transferred to the wrapper.
            Marshal.Release(trackerObjRaw);

            // Validate reuse of a wrapper fails.
            IntPtr trackerObjRaw2 = MockReferenceTrackerRuntime.CreateTrackerObject();

            Assert.Throws <NotSupportedException>(
                () =>
            {
                cw.GetOrRegisterObjectForComInstance(trackerObjRaw2, CreateObjectFlags.None, nativeWrapper2);
            });
            Marshal.Release(trackerObjRaw2);

            // Validate passing null wrapper fails.
            Assert.Throws <ArgumentNullException>(
                () =>
            {
                cw.GetOrRegisterObjectForComInstance(trackerObjRaw, CreateObjectFlags.None, null);
            });
        }
Exemplo n.º 16
0
        static void ValidateCreateObjectCachingScenario()
        {
            Console.WriteLine($"Running {nameof(ValidateCreateObjectCachingScenario)}...");

            var cw = new TestComWrappers();

            // Get an object from a tracker runtime.
            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();

            var trackerObj1 = (ITrackerObjectWrapper)cw.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);
            var trackerObj2 = (ITrackerObjectWrapper)cw.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);

            Assert.AreEqual(trackerObj1, trackerObj2);

            // Ownership has been transferred to the wrapper.
            Marshal.Release(trackerObjRaw);

            var trackerObj3 = (ITrackerObjectWrapper)cw.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject | CreateObjectFlags.UniqueInstance);

            Assert.AreNotEqual(trackerObj1, trackerObj3);
        }
Exemplo n.º 17
0
        static void ValidateComInterfaceCreationRoundTrip()
        {
            Console.WriteLine($"Running {nameof(ValidateComInterfaceCreationRoundTrip)}...");

            var testObj = new Test();

            var wrappers = new TestComWrappers();

            // Allocate a wrapper for the object
            IntPtr comWrapper = wrappers.GetOrCreateComInterfaceForObject(testObj, CreateComInterfaceFlags.None);

            Assert.AreNotEqual(IntPtr.Zero, comWrapper);

            var testObjUnwrapped = wrappers.GetOrCreateObjectForComInstance(comWrapper, CreateObjectFlags.Unwrap);

            Assert.AreEqual(testObj, testObjUnwrapped);

            // Release the wrapper
            int count = Marshal.Release(comWrapper);

            Assert.AreEqual(0, count);
        }
Exemplo n.º 18
0
 static void ValidateIUnknownImpls()
 => TestComWrappers.ValidateIUnknownImpls();
Exemplo n.º 19
0
 static IntPtr CreateWrapper(TestComWrappers cw)
 {
     return(cw.GetOrCreateComInterfaceForObject(new Test(), CreateComInterfaceFlags.TrackerSupport));
 }
Exemplo n.º 20
0
        private static void ValidateWeakReferenceState(WeakReference <WeakReferenceableWrapper> wr, bool expectedIsAlive, TestComWrappers sourceWrappers = null)
        {
            WeakReferenceableWrapper target;
            bool isAlive = wr.TryGetTarget(out target);

            Assert.AreEqual(expectedIsAlive, isAlive);

            if (isAlive && sourceWrappers != null)
            {
                Assert.AreEqual(sourceWrappers.Registration, target.Registration);
            }
        }
Exemplo n.º 21
0
        private static (WeakReference <WeakReferenceableWrapper>, IntPtr) GetWeakReference(TestComWrappers cw)
        {
            IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject();
            var    obj    = (WeakReferenceableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None);
            var    wr     = new WeakReference <WeakReferenceableWrapper>(obj);

            ValidateWeakReferenceState(wr, expectedIsAlive: true, cw);
            return(wr, objRaw);
        }
Exemplo n.º 22
0
        private static IntPtr SetWeakReferenceTarget(WeakReference <WeakReferenceableWrapper> wr, TestComWrappers cw)
        {
            IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject();
            var    obj    = (WeakReferenceableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None);

            wr.SetTarget(obj);
            ValidateWeakReferenceState(wr, expectedIsAlive: true, cw);
            return(objRaw);
        }