Ejemplo 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;
Ejemplo n.º 2
0
        private static void ValidateMarshalAPIs(bool validateUseRegistered)
        {
            string scenario = validateUseRegistered ? "use registered wrapper" : "fall back to runtime";

            Console.WriteLine($"Running {nameof(ValidateMarshalAPIs)}: {scenario}...");

            GlobalComWrappers registeredWrapper = GlobalComWrappers.Instance;

            registeredWrapper.ReturnInvalid = !validateUseRegistered;

            Console.WriteLine($" -- Validate Marshal.GetIUnknownForObject...");

            var    testObj     = new Test();
            IntPtr comWrapper1 = Marshal.GetIUnknownForObject(testObj);

            Assert.AreNotEqual(IntPtr.Zero, comWrapper1);
            Assert.AreEqual(testObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called");

            IntPtr comWrapper2 = Marshal.GetIUnknownForObject(testObj);

            Assert.AreEqual(comWrapper1, comWrapper2);

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

            Console.WriteLine($" -- Validate Marshal.GetIDispatchForObject...");

            Assert.Throws <InvalidCastException>(() => Marshal.GetIDispatchForObject(testObj));

            if (validateUseRegistered)
            {
                var    dispatchObj     = new TestEx(IID_IDISPATCH);
                IntPtr dispatchWrapper = Marshal.GetIDispatchForObject(dispatchObj);
                Assert.AreNotEqual(IntPtr.Zero, dispatchWrapper);
                Assert.AreEqual(dispatchObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called");
            }

            Console.WriteLine($" -- Validate Marshal.GetObjectForIUnknown...");

            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();
            object objWrapper1   = Marshal.GetObjectForIUnknown(trackerObjRaw);

            Assert.AreEqual(validateUseRegistered, objWrapper1 is FakeWrapper, $"GetObjectForIUnknown should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance");
            object objWrapper2 = Marshal.GetObjectForIUnknown(trackerObjRaw);

            Assert.AreEqual(objWrapper1, objWrapper2);

            Console.WriteLine($" -- Validate Marshal.GetUniqueObjectForIUnknown...");

            object objWrapper3 = Marshal.GetUniqueObjectForIUnknown(trackerObjRaw);

            Assert.AreEqual(validateUseRegistered, objWrapper3 is FakeWrapper, $"GetObjectForIUnknown should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance");

            Assert.AreNotEqual(objWrapper1, objWrapper3);

            Marshal.Release(trackerObjRaw);
        }
Ejemplo n.º 3
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();
        }
Ejemplo n.º 4
0
        private static void ValidateNotRegisteredForMarshalling()
        {
            Console.WriteLine($"Running {nameof(ValidateNotRegisteredForMarshalling)}...");

            var    testObj     = new Test();
            IntPtr comWrapper1 = Marshal.GetIUnknownForObject(testObj);

            Assert.IsNull(GlobalComWrappers.Instance.LastComputeVtablesObject, "ComWrappers instance should not have been called");

            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();
            object objWrapper    = Marshal.GetObjectForIUnknown(trackerObjRaw);

            Assert.IsFalse(objWrapper is FakeWrapper, $"ComWrappers instance should not have been called");
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
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);
Ejemplo n.º 7
0
        static void ValidateBadComWrapperImpl()
        {
            Console.WriteLine($"Running {nameof(ValidateBadComWrapperImpl)}...");

            var wrapper = new BadComWrappers();

            Assert.Throws <ArgumentException>(
                () =>
            {
                wrapper.ComputeVtablesMode = BadComWrappers.FailureMode.ReturnInvalid;
                wrapper.GetOrCreateComInterfaceForObject(new Test(), CreateComInterfaceFlags.None);
            });

            try
            {
                wrapper.ComputeVtablesMode = BadComWrappers.FailureMode.ThrowException;
                wrapper.GetOrCreateComInterfaceForObject(new Test(), CreateComInterfaceFlags.None);
            }
            catch (Exception e)
            {
                Assert.AreEqual(BadComWrappers.ExceptionErrorCode, e.HResult);
            }

            IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();

            Assert.Throws <ArgumentNullException>(
                () =>
            {
                wrapper.CreateObjectMode = BadComWrappers.FailureMode.ReturnInvalid;
                wrapper.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.None);
            });

            try
            {
                wrapper.CreateObjectMode = BadComWrappers.FailureMode.ThrowException;
                wrapper.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.None);
            }
            catch (Exception e)
            {
                Assert.AreEqual(BadComWrappers.ExceptionErrorCode, e.HResult);
            }

            Marshal.Release(trackerObjRaw);
        }
Ejemplo n.º 8
0
        static int Main(string[] doNotUse)
        {
            try
            {
                // The first test registers a global ComWrappers instance for tracker support.
                // Subsequents tests assume the global instance has already been registered.
                ValidateRegisterForTrackerSupport();
#if Windows
                ValidateNotRegisteredForMarshalling();
#endif

                IntPtr trackerObjRaw = MockReferenceTrackerRuntime.CreateTrackerObject();
                var    trackerObj    = GlobalComWrappers.Instance.GetOrCreateObjectForComInstance(trackerObjRaw, CreateObjectFlags.TrackerObject);
                Marshal.Release(trackerObjRaw);

                ValidateNotifyEndOfReferenceTrackingOnThread();
#if Windows
                // Register a global ComWrappers instance for marshalling.
                ValidateRegisterForMarshalling();

                ValidateMarshalAPIs(validateUseRegistered: true);
                ValidateMarshalAPIs(validateUseRegistered: false);

                ValidatePInvokes(validateUseRegistered: true);
                ValidatePInvokes(validateUseRegistered: false);

                // RegFree COM is not supported on Windows Nano Server
                if (!Utilities.IsWindowsNanoServer)
                {
                    ValidateComActivation(validateUseRegistered: true);
                    ValidateComActivation(validateUseRegistered: false);
                }
#endif
                ValidateNotifyEndOfReferenceTrackingOnThread();
            }
            catch (Exception e)
            {
                Console.WriteLine($"Test Failure: {e}");
                return(101);
            }

            return(100);
        }
Ejemplo n.º 9
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);
            });
        }
Ejemplo n.º 10
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);
        }