Beispiel #1
0
 // Private. Objects must be created with CreateProxy.
 ComInteropProxy(Type t)
     : base(t)
 {
     // object only created here
     // .ctor is called later
     com_object = __ComObject.CreateRCW(t);
 }
Beispiel #2
0
 internal static T Call <T>(
     System.IntPtr pfn,
     __ComObject arg0,
     System.IntPtr arg1)
 {
     return(default(T));
 }
Beispiel #3
0
        private static __ComObject CreateComObjectInternal(RuntimeTypeHandle classType, IntPtr pComItf)
        {
            Debug.Assert(!classType.IsNull());

            if (classType.Equals(McgModule.s_DependencyReductionTypeRemovedTypeHandle))
            {
                // We should filter out the strongly typed RCW in TryGetClassInfoFromName step
#if !RHTESTCL
                Environment.FailFast(McgTypeHelpers.GetDiagnosticMessageForMissingType(classType));
#else
                Environment.FailFast("We should never see strongly typed RCW discarded here");
#endif
            }

            //Note that this doesn't run the constructor in RH but probably do in your reflection based implementation.
            //If this were a real RCW, you would actually 'new' the RCW which is wrong. Fortunately in CoreCLR we don't have
            //this scenario so we are OK, but we should figure out a way to fix this by having a runtime API.
            object newClass = InteropExtensions.RuntimeNewObject(classType);

            Debug.Assert(newClass is __ComObject);

            __ComObject newObj = InteropExtensions.UncheckedCast <__ComObject>(newClass);

            IntPtr pfnCtor = AddrOfIntrinsics.AddrOf <AddrOfIntrinsics.AddrOfAttachingCtor>(__ComObject.AttachingCtor);
            CalliIntrinsics.Call <int>(pfnCtor, newObj, pComItf, classType);

            return(newObj);
        }
Beispiel #4
0
 internal static T Call <T>(
     System.IntPtr pfn,
     __ComObject arg0,
     System.IntPtr arg1,
     RuntimeTypeHandle arg2)
 {
     return(default(T));
 }
Beispiel #5
0
 internal static T Call <T>(
     System.IntPtr pfn,
     __ComObject arg0,
     System.IntPtr arg1,
     McgClassInfo arg2)
 {
     return(default(T));
 }
        public bool CanCastTo(Type fromType, object o)
        {
            __ComObject _ComObject = o as __ComObject;

            if (_ComObject == null)
            {
                throw new NotSupportedException("Only RCWs are currently supported");
            }
            return((fromType.Attributes & TypeAttributes.Import) != TypeAttributes.NotPublic && !(_ComObject.GetInterface(fromType, false) == IntPtr.Zero));
        }
Beispiel #7
0
#pragma warning restore 649, 169

        /// <summary>
        /// This method gets called every time the WeakReference or WeakReference'1 set the Target.
        /// We can have 4 possible combination here.
        /// a. Target is a GC object and it is either getting set for the first time or previous object is also GC object.
        ///     In this case we do not need to do anything.
        ///
        /// b. Target is a GC object and previous target was __ComObject
        ///    i. We remove the element from ConditionalWeakTable.
        ///   ii. When the GC collects this ComWeakReference the finalizer will ensure that the native object is released.
        ///
        /// c. Target is a __ComObject and the previous target was null or GC object.
        ///    We simply add the new target to the dictionary.
        ///
        /// d. Target is a __COmObject and the previous object was __COmObject.
        ///    i. We first remove the element from the ConditionalWeakTable.
        ///   ii. When the GC collects the previous ComWeakReference the finalizer will ensure that the native object is released.
        ///  iii. We add the new ComWeakReference to the conditionalWeakTable.
        /// </summary>
        /// <param name="weakReference"></param>
        /// <param name="target"></param>
        public static unsafe void SetTarget(object weakReference, object target)
        {
            Contract.Assert(weakReference != null);

            // Check if this weakReference is already associated with a native target.
            ComWeakReference pOldComWeakReference;

            if (s_COMWeakReferenceTable.TryGetValue(weakReference, out pOldComWeakReference))
            {
                // Remove the previous target.
                // We do not have to release the native ComWeakReference since it will be done as part of the finalizer.
                s_COMWeakReferenceTable.Remove(weakReference);
            }

            // Now check whether the current target is __ComObject.
            // However, we don't want to pass the QI to a managed object deriving from native object - we
            // would end up passing the QI to back the CCW and end up stack overflow
            __ComObject comObject = target as __ComObject;

            if (comObject != null && !comObject.ExtendsComObject)
            {
                // Get the IWeakReferenceSource for the given object
                IntPtr pWeakRefSource = McgMarshal.ObjectToComInterface(comObject, McgModuleManager.IWeakReferenceSource);

                if (pWeakRefSource != IntPtr.Zero)
                {
                    IntPtr pWeakRef = IntPtr.Zero;
                    try
                    {
                        // Now that we have the IWeakReferenceSource , we need to call the GetWeakReference method to get the corresponding IWeakReference
                        __com_IWeakReferenceSource *pComWeakRefSource = (__com_IWeakReferenceSource *)pWeakRefSource;
                        int result = CalliIntrinsics.StdCall <int>(
                            pComWeakRefSource->pVtable->pfnGetWeakReference,
                            pWeakRefSource,
                            out pWeakRef);
                        if (result >= 0 && pWeakRef != IntPtr.Zero)
                        {
                            // Since we have already checked s_COMWeakReferenceTable for the weak reference, we can simply add the entry w/o checking.
                            // PS - We do not release the pWeakRef as it should be alive until the ComWeakReference is alive.
                            s_COMWeakReferenceTable.Add(weakReference, new ComWeakReference(ref pWeakRef));
                        }
                    }
                    finally
                    {
                        McgMarshal.ComSafeRelease(pWeakRef);
                        McgMarshal.ComRelease(pWeakRefSource);
                    }
                }
            }
        }
        /// <summary>
        /// Returns the activation factory without using the cache. Avoiding cache behavior is important
        /// for app that use this API because they need to deal with crashing broker scenarios where cached
        /// factories would be stale (pointing to a bad proxy)
        /// </summary>
        public static IActivationFactory GetActivationFactory(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            __ComObject factory = FactoryCache.Get().GetActivationFactory(
                type.FullName,
                InternalTypes.IUnknown,
                skipCache: true);

            return((IActivationFactory)factory);
        }
Beispiel #9
0
        public static object GetTypedObjectForIUnknown(IntPtr pUnk, Type t)
        {
            ComInteropProxy proxy = new ComInteropProxy(pUnk, t);
            __ComObject     co    = (__ComObject)proxy.GetTransparentProxy();

            foreach (Type itf in t.GetInterfaces())
            {
                if ((itf.Attributes & TypeAttributes.Import) == TypeAttributes.Import)
                {
                    if (co.GetInterface(itf) == IntPtr.Zero)
                    {
                        return(null);
                    }
                }
            }
            return(co);
        }
            // Get InstanceKey to use in the cache
            private static object GetInstanceKey(Action <EventRegistrationToken> removeMethod)
            {
                object target = removeMethod.Target;

                Debug.Assert(target == null || target is __ComObject, "Must be an RCW");

                if (target == null)
                {
                    // In .NET Native there is no good way to go from the static event to the declaring type, the instanceKey used for
                    // static events in desktop. Since the declaring type is only a way to organize the list of static events, we have
                    // chosen to use the dummyObject instead here.It flattens the hierarchy of static events but does not impact the functionality.
                    return(s_dummyStaticEventKey);
                }

                // Need the "Raw" IUnknown pointer for the RCW that is not bound to the current context
                __ComObject comObject = target as __ComObject;

                return((object)comObject.BaseIUnknown_UnsafeNoAddRef);
            }
Beispiel #11
0
        public bool CanCastTo(Type fromType, object o)
        {
            __ComObject co = o as __ComObject;

            if (co == null)
            {
                throw new NotSupportedException("Only RCWs are currently supported");
            }

            if ((fromType.Attributes & TypeAttributes.Import) == 0)
            {
                return(false);
            }

            if (co.GetInterface(fromType, false) == IntPtr.Zero)
            {
                return(false);
            }
            return(true);
        }
Beispiel #12
0
        public static object CreateWrapperOfType(object o, Type t)
        {
            __ComObject co = o as __ComObject;

            if (co == null)
            {
                throw new ArgumentException("o must derive from __ComObject", "o");
            }
            if (t == null)
            {
                throw new ArgumentNullException("t");
            }

            Type[] itfs = o.GetType().GetInterfaces();
            foreach (Type itf in itfs)
            {
                if (itf.IsImport && co.GetInterface(itf) == IntPtr.Zero)
                {
                    throw new InvalidCastException();
                }
            }

            return(ComInteropProxy.GetProxy(co.IUnknown, t).GetTransparentProxy());
        }
 private ComInteropProxy(Type t) : base(t)
 {
     this.com_object = __ComObject.CreateRCW(t);
 }
Beispiel #14
0
        internal static __ComGenericInterfaceDispatcher CreateGenericComDispatcher(RuntimeTypeHandle genericDispatcherDef, RuntimeTypeHandle[] genericArguments, __ComObject comThisPointer)
        {
#if !RHTESTCL && !CORECLR && !CORERT
            Debug.Assert(genericDispatcherDef.IsGenericTypeDefinition());
            Debug.Assert(genericArguments != null && genericArguments.Length > 0);

            RuntimeTypeHandle instantiatedDispatcherType;
            if (!Internal.Runtime.TypeLoader.TypeLoaderEnvironment.Instance.TryGetConstructedGenericTypeForComponents(genericDispatcherDef, genericArguments, out instantiatedDispatcherType))
            {
                return(null);    // ERROR
            }
            __ComGenericInterfaceDispatcher dispatcher = (__ComGenericInterfaceDispatcher)InteropExtensions.RuntimeNewObject(instantiatedDispatcherType);
            dispatcher.m_comObject = comThisPointer;

            return(dispatcher);
#else
            return(null);
#endif
        }
Beispiel #15
0
        /// <summary>
        /// Returns the existing RCW or create a new RCW from the COM interface pointer
        /// NOTE: This does not do any unboxing at all.
        /// </summary>
        /// <param name="expectedContext">
        /// The current context of this thread. If it is passed and is not Default, we'll check whether the
        /// returned RCW from cache matches this expected context. If it is not a match (from a different
        /// context, and is not free threaded), we'll go ahead ignoring the cached entry, and create a new
        /// RCW instead - which will always end up in the current context
        /// We'll skip the check if current == ContextCookie.Default.
        /// </param>
        private static object ComInterfaceToComObjectInternal_NoCache(
            IntPtr pComItf,
            IntPtr pComIdentityIUnknown,
            RuntimeTypeHandle interfaceType,
            RuntimeTypeHandle classTypeInSignature,
            ContextCookie expectedContext,
            CreateComObjectFlags flags,
            out string className
            )
        {
            className = null;

            //
            // Lookup RCW in global RCW cache based on the identity IUnknown
            //
            __ComObject comObject = ComObjectCache.Lookup(pComIdentityIUnknown);

            if (comObject != null)
            {
                bool useThisComObject = true;

                if (!expectedContext.IsDefault)
                {
                    //
                    // Make sure the returned RCW matches the context we specify (if any)
                    //
                    if (!comObject.IsFreeThreaded &&
                        !comObject.ContextCookie.Equals(expectedContext))
                    {
                        //
                        // This is a mismatch.
                        // We only care about context for WinRT factory RCWs (which is the only place we are
                        // passing in the context right now).
                        // When we get back a WinRT factory RCW created in a different context. This means the
                        // factory is a singleton, and the returned IActivationFactory could be either one of
                        // the following:
                        // 1) A raw pointer, and it acts like a free threaded object
                        // 2) A proxy that is used across different contexts. It might maintain a list of contexts
                        // that it is marshaled to, and will fail to be called if it is not marshaled to this
                        // context yet.
                        //
                        // In this case, it is unsafe to use this RCW in this context and we should proceed
                        // to create a duplicated one instead. It might make sense to have a context-sensitive
                        // RCW cache but I don't think this case will be common enough to justify it
                        //
                        // @TODO: Check for DCOM proxy as well
                        useThisComObject = false;
                    }
                }

                if (useThisComObject)
                {
                    //
                    // We found one - AddRef and return
                    //
                    comObject.AddRef();
                    return(comObject);
                }
            }

            string winrtClassName = null;

            bool isSealed = false;

            if (!classTypeInSignature.IsNull())
            {
                isSealed = classTypeInSignature.IsSealed();
            }

            //
            // Only look at runtime class name if the class type in signature is not sealed
            // NOTE: In the case of System.Uri, we are not pass the class type, only the interface
            //
            if (!isSealed &&
                (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0)
            {
                IntPtr pInspectable;

                bool needRelease = false;

                if (interfaceType.IsSupportIInspectable())
                {
                    //
                    // Use the interface pointer as IInspectable as we know it is indeed a WinRT interface that
                    // derives from IInspectable
                    //
                    pInspectable = pComItf;
                }
                else if ((flags & CreateComObjectFlags.IsWinRTObject) != 0)
                {
                    //
                    // Otherwise, if someone tells us that this is a WinRT object, but we don't have a
                    // IInspectable interface at hand, we'll QI for it
                    //
                    pInspectable = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IInspectable);
                    needRelease  = true;
                }
                else
                {
                    pInspectable = default(IntPtr);
                }

                try
                {
                    if (pInspectable != default(IntPtr))
                    {
                        className      = McgComHelpers.GetRuntimeClassName(pInspectable);
                        winrtClassName = className;
                    }
                }
                finally
                {
                    if (needRelease && pInspectable != default(IntPtr))
                    {
                        McgMarshal.ComRelease(pInspectable);
                        pInspectable = default(IntPtr);
                    }
                }
            }

            //
            // 1. Prefer using the class returned from GetRuntimeClassName
            // 2. Otherwise use the class (if there) in the signature
            // 3. Out of options - create __ComObject
            //
            RuntimeTypeHandle classTypeToCreateRCW  = default(RuntimeTypeHandle);
            RuntimeTypeHandle interfaceTypeFromName = default(RuntimeTypeHandle);

            if (!String.IsNullOrEmpty(className))
            {
                if (!McgModuleManager.TryGetClassTypeFromName(className, out classTypeToCreateRCW))
                {
                    //
                    // If we can't find the class name in our map, try interface as well
                    // Such as IVector<Int32>
                    // This apparently won't work if we haven't seen the interface type in MCG
                    //
                    McgModuleManager.TryGetInterfaceTypeFromName(className, out interfaceTypeFromName);
                }
            }

            if (classTypeToCreateRCW.IsNull())
            {
                classTypeToCreateRCW = classTypeInSignature;
            }

            // Use identity IUnknown to create the new RCW
            // @TODO: Transfer the ownership of ref count to the RCW
            if (classTypeToCreateRCW.IsNull())
            {
                //
                // Create a weakly typed RCW because we have no information about this particular RCW
                // @TODO - what if this RCW is not seen by MCG but actually exists in WinMD and therefore we
                // are missing GCPressure and ComMarshallingType information for this object?
                //
                comObject = new __ComObject(pComIdentityIUnknown, default(RuntimeTypeHandle));
            }
            else
            {
                //
                // Create a strongly typed RCW based on RuntimeTypeHandle
                //
                comObject = CreateComObjectInternal(classTypeToCreateRCW, pComIdentityIUnknown);            // Use identity IUnknown to create the new RCW
            }

#if DEBUG
            //
            // Remember the runtime class name for debugging purpose
            // This way you can tell what the class name is, even when we failed to create a strongly typed
            // RCW for it
            //
            comObject.m_runtimeClassName = className;
#endif

            //
            // Make sure we QI for that interface
            //
            if (!interfaceType.IsNull())
            {
                comObject.QueryInterface_NoAddRef_Internal(interfaceType, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
            }

            return(comObject);
        }
Beispiel #16
0
        /// <summary>
        /// Returns the existing RCW or create a new RCW from the COM interface pointer
        /// NOTE: This does unboxing unless CreateComObjectFlags.SkipTypeResolutionAndUnboxing is specified
        /// </summary>
        /// <param name="expectedContext">
        /// The current context of this thread. If it is passed and is not Default, we'll check whether the
        /// returned RCW from cache matches this expected context. If it is not a match (from a different
        /// context, and is not free threaded), we'll go ahead ignoring the cached entry, and create a new
        /// RCW instead - which will always end up in the current context
        /// We'll skip the check if current == ContextCookie.Default.
        /// </param>
        internal static object ComInterfaceToComObjectInternal(
            IntPtr pComItf,
            IntPtr pComIdentityIUnknown,
            RuntimeTypeHandle interfaceType,
            RuntimeTypeHandle classTypeInSignature,
            ContextCookie expectedContext,
            CreateComObjectFlags flags
            )
        {
            string className;
            object obj = ComInterfaceToComObjectInternal_NoCache(
                pComItf,
                pComIdentityIUnknown,
                interfaceType,
                classTypeInSignature,
                expectedContext,
                flags,
                out className
                );

            //
            // The assumption here is that if the classInfoInSignature is null and interfaceTypeInfo
            // is either IUnknow and IInspectable we need to try unboxing.
            //
            bool doUnboxingCheck =
                (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0 &&
                obj != null &&
                classTypeInSignature.IsNull() &&
                (interfaceType.Equals(InternalTypes.IUnknown) ||
                 interfaceType.IsIInspectable());

            if (doUnboxingCheck)
            {
                //
                // Try unboxing
                // Even though this might just be a IUnknown * from the signature, we still attempt to unbox
                // if it implements IInspectable
                //
                // @TODO - We might need to optimize this by pre-checking the names to see if they
                // potentially represents a boxed type, but for now let's keep it simple and I also don't
                // want to replicate the knowledge here
                // @TODO2- We probably should skip the creating the COM object in the first place.
                //
                // NOTE: the RCW here could be a cached one (for a brief time if GC doesn't kick in. as there
                // is nothing to hold the RCW alive for IReference<T> RCWs), so this could save us a RCW
                // creation cost potentially. Desktop CLR doesn't do this. But we also paying for unnecessary
                // cache management cost, and it is difficult to say which way is better without proper
                // measuring
                //
                object unboxedObj = McgMarshal.UnboxIfBoxed(obj, className);
                if (unboxedObj != null)
                {
                    return(unboxedObj);
                }
            }

            //
            // In order for variance to work, we save the incoming interface pointer as specified in the
            // signature into the cache, so that we know this RCW does support this interface and variance
            // can take advantage of that later
            // NOTE: In some cases, native might pass a WinRT object as a 'compatible' interface, for example,
            // pass IVector<IFoo> as IVector<Object> because they are 'compatible', but QI for IVector<object>
            // won't succeed. In this case, we'll just believe it implements IVector<Object> as in the
            // signature while the underlying interface pointer is actually IVector<IFoo>
            //
            __ComObject comObject = obj as __ComObject;

            if (comObject != null)
            {
                McgMarshal.ComAddRef(pComItf);

                try
                {
                    comObject.InsertIntoCache(interfaceType, ContextCookie.Current, ref pComItf, true);
                }
                finally
                {
                    //
                    // Only release when a exception is thrown or we didn't 'swallow' the ref count by
                    // inserting it into the cache
                    //
                    McgMarshal.ComSafeRelease(pComItf);
                }
            }

            return(obj);
        }
Beispiel #17
0
 internal ComInteropProxy(IntPtr pUnk, Type t)
     : base(t)
 {
     com_object = new __ComObject(pUnk, this);
     CacheProxy();
 }
Beispiel #18
0
        internal static unsafe IntPtr ObjectToComInterfaceInternal(Object obj, RuntimeTypeHandle typeHnd)
        {
            if (obj == null)
            {
                return(default(IntPtr));
            }

#if ENABLE_WINRT
            //
            // Try boxing if this is a WinRT object
            //
            if (typeHnd.Equals(InternalTypes.IInspectable))
            {
                object unboxed = McgMarshal.BoxIfBoxable(obj);

                //
                // Marshal ReferenceImpl<T> to WinRT as IInspectable
                //
                if (unboxed != null)
                {
                    obj = unboxed;
                }
                else
                {
                    //
                    // Anything that can be casted to object[] will be boxed as object[]
                    //
                    object[] objArray = obj as object[];
                    if (objArray != null)
                    {
                        unboxed = McgMarshal.BoxIfBoxable(obj, typeof(object[]).TypeHandle);
                        if (unboxed != null)
                        {
                            obj = unboxed;
                        }
                    }
                }
            }
#endif //ENABLE_WINRT

            //
            // If this is a RCW, and the RCW is not a base class (managed class deriving from RCW class),
            // QI on the RCW
            //
            __ComObject comObject = obj as __ComObject;

            if (comObject != null && !comObject.ExtendsComObject)
            {
                IntPtr pComPtr = comObject.QueryInterface_NoAddRef_Internal(typeHnd, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
                if (pComPtr == default(IntPtr))
                {
                    return(default(IntPtr));
                }

                McgMarshal.ComAddRef(pComPtr);
                GC.KeepAlive(comObject); // make sure we don't collect the object before adding a refcount.

                return(pComPtr);
            }

            //
            // Otherwise, go down the CCW code path
            //
            return(ManagedObjectToComInterface(obj, typeHnd));
        }