コード例 #1
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        static object ComInterfaceToObjectInternal_NoManagedUnboxing(
            IntPtr pComItf,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            CreateComObjectFlags flags)
        {
            if (pComItf == default(IntPtr))
            {
                return(null);
            }

            //
            // Is this a CCW?
            //
            ComCallableObject ccw;

            if (ComCallableObject.TryGetCCW(pComItf, out ccw))
            {
                return(ccw.TargetObject);
            }

            //
            // This pointer is not a CCW, but we need to do one additional check here for aggregation
            // In case the COM pointer is a interface implementation from native, but the outer object is a
            // managed object
            //
            IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown);

            if (pComIdentityIUnknown == default(IntPtr))
            {
                throw new InvalidCastException();
            }

            try
            {
                //
                // Check whether the identity COM pointer to see if it is a aggregating CCW
                //
                if (ComCallableObject.TryGetCCW(pComIdentityIUnknown, out ccw))
                {
                    return(ccw.TargetObject);
                }

                //
                // Nope, not a CCW - let's go down our RCW creation code path
                //
                return(ComInterfaceToComObjectInternal(
                           pComItf,
                           pComIdentityIUnknown,
                           interfaceTypeInfo,
                           classInfoInSignature,
                           ContextCookie.Default,
                           flags
                           ));
            }
            finally
            {
                McgMarshal.ComRelease(pComIdentityIUnknown);
            }
        }
コード例 #2
0
        public static IntPtr /* IUnknown* */ GetComInterfaceForObject(Object o, Type t)
        {
            if (o == null)
            {
                throw new ArgumentNullException("o");
            }

            if (t == null)
            {
                throw new ArgumentNullException("type");
            }

            RuntimeTypeHandle interfaceTypeHandle = t.TypeHandle;
            McgTypeInfo       secondTypeInfo;
            McgTypeInfo       mcgTypeInfo = McgModuleManager.GetTypeInfoFromTypeHandle(interfaceTypeHandle, out secondTypeInfo);

            if (mcgTypeInfo.IsNull)
            {
#if CORECLR
                return(default(IntPtr));
#else
                throw new MissingInteropDataException(SR.ComTypeMarshalling_MissingInteropData, t);
#endif
            }
            return(McgMarshal.ObjectToComInterface(o, mcgTypeInfo));
        }
コード例 #3
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <summary>
        /// Converts a COM interface pointer to a managed object
        /// This either gets back a existing CCW, or a existing RCW, or create a new RCW
        /// </summary>
        internal static object ComInterfaceToObjectInternal(
            IntPtr pComItf,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            CreateComObjectFlags flags)
        {
            bool needUnboxing = (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0;

            object ret = ComInterfaceToObjectInternal_NoManagedUnboxing(pComItf, interfaceTypeInfo, classInfoInSignature, flags);

            if (ret != null && needUnboxing)
            {
                return(UnboxManagedWrapperIfBoxed(ret));
            }

            return(ret);
        }
コード例 #4
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <summary>
        /// Returns the existing RCW or create a new RCW from the COM interface pointer
        /// NOTE: Don't use this overload if you already have the identity IUnknown
        /// </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 ComInterfaceToComObject(
            IntPtr pComItf,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSigature,
            ContextCookie expectedContext,
            CreateComObjectFlags flags
            )
        {
            Debug.Assert(expectedContext.IsDefault || expectedContext.IsCurrent);

            //
            // Get identity IUnknown for lookup
            //
            IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown);

            if (pComIdentityIUnknown == default(IntPtr))
            {
                throw new InvalidCastException();
            }

            try
            {
                object obj = ComInterfaceToComObjectInternal(
                    pComItf,
                    pComIdentityIUnknown,
                    interfaceTypeInfo,
                    classInfoInSigature,
                    expectedContext,
                    flags
                    );

                return(obj);
            }
            finally
            {
                McgMarshal.ComRelease(pComIdentityIUnknown);
            }
        }
コード例 #5
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
 internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, McgTypeInfo itfTypeInfo)
 {
     Guid itfGuid = itfTypeInfo.ItfGuid;
     return ManagedObjectToComInterfaceInternal(obj, ref itfGuid, itfTypeInfo);
 }
コード例 #6
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        private static unsafe IntPtr ManagedObjectToComInterfaceInternal(Object obj, ref Guid iid, McgTypeInfo itfTypeInfo)
        {
            if (obj == null)
            {
                return default(IntPtr);
            }

            //
            // Look up ComCallableObject from the cache
            // If couldn't find one, create a new one
            //
            ComCallableObject ccw = null;

            try
            {
                //
                // Either return existing one or create a new one
                // In either case, the returned CCW is addref-ed to avoid race condition
                //
                IntPtr dummy;

                ccw = CCWLookupMap.GetOrCreateCCW(obj, McgTypeInfo.Null, out dummy);
                Debug.Assert(ccw != null);

                return ccw.GetComInterfaceForIID(ref iid, itfTypeInfo);
            }
            finally
            {
                //
                // Free the extra ref count added by GetOrCreateCCW (to protect the CCW from being collected)
                //
                if (ccw != null)
                    ccw.Release();
            }
        }
コード例 #7
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        static object ComInterfaceToObjectInternal_NoManagedUnboxing(
            IntPtr pComItf,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            CreateComObjectFlags flags)
        {
            if (pComItf == default(IntPtr))
                return null;

            //
            // Is this a CCW?
            //
            ComCallableObject ccw;

            if (ComCallableObject.TryGetCCW(pComItf, out ccw))
            {
                return ccw.TargetObject;
            }

            //
            // This pointer is not a CCW, but we need to do one additional check here for aggregation
            // In case the COM pointer is a interface implementation from native, but the outer object is a
            // managed object
            //
            IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown);

            if (pComIdentityIUnknown == default(IntPtr))
                throw new InvalidCastException();

            try
            {
                //
                // Check whether the identity COM pointer to see if it is a aggregating CCW
                //
                if (ComCallableObject.TryGetCCW(pComIdentityIUnknown, out ccw))
                {
                    return ccw.TargetObject;
                }

                //
                // Nope, not a CCW - let's go down our RCW creation code path
                //
                return ComInterfaceToComObjectInternal(
                    pComItf,
                    pComIdentityIUnknown,
                    interfaceTypeInfo,
                    classInfoInSignature,
                    ContextCookie.Default,
                    flags
                    );
            }
            finally
            {
                McgMarshal.ComRelease(pComIdentityIUnknown);
            }
        }
コード例 #8
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        internal unsafe static IntPtr ObjectToComInterfaceInternal(Object obj, McgTypeInfo typeInfo)
        {
            if (obj == null)
                return default(IntPtr);
#if ENABLE_WINRT
            //
            // Try boxing if this is a WinRT object
            //
            if (typeInfo == McgModuleManager.IInspectable)
            {
                object unboxed = McgModuleManager.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 = McgModuleManager.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(typeInfo,  /* 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
            //
            Guid itfGuid = typeInfo.ItfGuid;
            return ManagedObjectToComInterfaceInternal(obj, ref itfGuid, typeInfo);
        }
コード例 #9
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <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,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            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 (!classInfoInSignature.IsNull)
            {
                isSealed = classInfoInSignature.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 (interfaceTypeInfo.IsIInspectable)
                {
                    //
                    // 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
            //
            McgClassInfo classInfoToCreateRCW = McgClassInfo.Null;
            McgTypeInfo interfaceInfo = McgTypeInfo.Null;

            if (!String.IsNullOrEmpty(className))
            {
                if (!McgModuleManager.TryGetClassInfoFromName(className, out classInfoToCreateRCW))
                {
                    //
                    // 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.TryGetInterfaceTypeInfoFromName(className, out interfaceInfo);
                }
            }

            if (classInfoToCreateRCW.IsNull)
                classInfoToCreateRCW = classInfoInSignature;

            // Use identity IUnknown to create the new RCW
            // @TODO: Transfer the ownership of ref count to the RCW
            if (classInfoToCreateRCW.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, McgClassInfo.Null);
            }
            else
            {
                //
                // Create a strongly typed RCW based on McgClassInfo
                //
                comObject = CreateComObjectInternal(classInfoToCreateRCW, 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 (!interfaceInfo.IsNull)
            {
                comObject.QueryInterface_NoAddRef_Internal(interfaceInfo, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
            }

            return comObject;
        }
コード例 #10
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <summary>
        /// Converts a COM interface pointer to a managed object
        /// This either gets back a existing CCW, or a existing RCW, or create a new RCW
        /// </summary>
        internal static object ComInterfaceToObjectInternal(
            IntPtr pComItf,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            CreateComObjectFlags flags)
        {
            bool needUnboxing = (flags & CreateComObjectFlags.SkipTypeResolutionAndUnboxing) == 0;

            object ret = ComInterfaceToObjectInternal_NoManagedUnboxing(pComItf, interfaceTypeInfo, classInfoInSignature, flags);
            if (ret != null && needUnboxing)
            {
                return UnboxManagedWrapperIfBoxed(ret);
            }

            return ret;
        }
コード例 #11
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <summary>
        /// Returns the existing RCW or create a new RCW from the COM interface pointer
        /// NOTE: Don't use this overload if you already have the identity IUnknown
        /// </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 ComInterfaceToComObject(
            IntPtr pComItf,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSigature,
            ContextCookie expectedContext,
            CreateComObjectFlags flags
            )
        {
            Debug.Assert(expectedContext.IsDefault || expectedContext.IsCurrent);

            //
            // Get identity IUnknown for lookup
            //
            IntPtr pComIdentityIUnknown = McgMarshal.ComQueryInterfaceNoThrow(pComItf, ref Interop.COM.IID_IUnknown);

            if (pComIdentityIUnknown == default(IntPtr))
                throw new InvalidCastException();

            try
            {
                object obj = ComInterfaceToComObjectInternal(
                    pComItf,
                    pComIdentityIUnknown,
                    interfaceTypeInfo,
                    classInfoInSigature,
                    expectedContext,
                    flags
                    );

                return obj;
            }
            finally
            {
                McgMarshal.ComRelease(pComIdentityIUnknown);
            }
        }
コード例 #12
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <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,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            ContextCookie expectedContext,
            CreateComObjectFlags flags
            )
        {
            string className;
            object obj = ComInterfaceToComObjectInternal_NoCache(
                pComItf,
                pComIdentityIUnknown,
                interfaceTypeInfo,
                classInfoInSignature,
                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 &&
                classInfoInSignature.IsNull && 
                (interfaceTypeInfo == McgModuleManager.IUnknown ||
                 interfaceTypeInfo == McgModuleManager.IInspectable);

            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 = McgModuleManager.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(interfaceTypeInfo, 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;
        }
コード例 #13
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <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,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            ContextCookie expectedContext,
            CreateComObjectFlags flags
            )
        {
            string className;
            object obj = ComInterfaceToComObjectInternal_NoCache(
                pComItf,
                pComIdentityIUnknown,
                interfaceTypeInfo,
                classInfoInSignature,
                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 &&
                classInfoInSignature.IsNull &&
                (interfaceTypeInfo == McgModuleManager.IUnknown ||
                 interfaceTypeInfo == McgModuleManager.IInspectable);

            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 = McgModuleManager.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(interfaceTypeInfo, 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);
        }
コード例 #14
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        private static unsafe IntPtr ManagedObjectToComInterfaceInternal(Object obj, ref Guid iid, McgTypeInfo itfTypeInfo)
        {
            if (obj == null)
            {
                return(default(IntPtr));
            }

            //
            // Look up ComCallableObject from the cache
            // If couldn't find one, create a new one
            //
            ComCallableObject ccw = null;

            try
            {
                //
                // Either return existing one or create a new one
                // In either case, the returned CCW is addref-ed to avoid race condition
                //
                IntPtr dummy;

                ccw = CCWLookupMap.GetOrCreateCCW(obj, McgTypeInfo.Null, out dummy);
                Debug.Assert(ccw != null);

                return(ccw.GetComInterfaceForIID(ref iid, itfTypeInfo));
            }
            finally
            {
                //
                // Free the extra ref count added by GetOrCreateCCW (to protect the CCW from being collected)
                //
                if (ccw != null)
                {
                    ccw.Release();
                }
            }
        }
コード例 #15
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        internal static unsafe IntPtr ManagedObjectToComInterface(Object obj, McgTypeInfo itfTypeInfo)
        {
            Guid itfGuid = itfTypeInfo.ItfGuid;

            return(ManagedObjectToComInterfaceInternal(obj, ref itfGuid, itfTypeInfo));
        }
コード例 #16
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        internal unsafe static IntPtr ObjectToComInterfaceInternal(Object obj, McgTypeInfo typeInfo)
        {
            if (obj == null)
            {
                return(default(IntPtr));
            }
#if ENABLE_WINRT
            //
            // Try boxing if this is a WinRT object
            //
            if (typeInfo == McgModuleManager.IInspectable)
            {
                object unboxed = McgModuleManager.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 = McgModuleManager.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(typeInfo, /* 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
            //
            Guid itfGuid = typeInfo.ItfGuid;
            return(ManagedObjectToComInterfaceInternal(obj, ref itfGuid, typeInfo));
        }
コード例 #17
0
ファイル: McgComHelpers.cs プロジェクト: noahfalk/corert
        /// <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,
            McgTypeInfo interfaceTypeInfo,
            McgClassInfo classInfoInSignature,
            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 (!classInfoInSignature.IsNull)
            {
                isSealed = classInfoInSignature.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 (interfaceTypeInfo.IsIInspectable)
                {
                    //
                    // 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
            //
            McgClassInfo classInfoToCreateRCW = McgClassInfo.Null;
            McgTypeInfo  interfaceInfo        = McgTypeInfo.Null;

            if (!String.IsNullOrEmpty(className))
            {
                if (!McgModuleManager.TryGetClassInfoFromName(className, out classInfoToCreateRCW))
                {
                    //
                    // 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.TryGetInterfaceTypeInfoFromName(className, out interfaceInfo);
                }
            }

            if (classInfoToCreateRCW.IsNull)
            {
                classInfoToCreateRCW = classInfoInSignature;
            }

            // Use identity IUnknown to create the new RCW
            // @TODO: Transfer the ownership of ref count to the RCW
            if (classInfoToCreateRCW.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, McgClassInfo.Null);
            }
            else
            {
                //
                // Create a strongly typed RCW based on McgClassInfo
                //
                comObject = CreateComObjectInternal(classInfoToCreateRCW, 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 (!interfaceInfo.IsNull)
            {
                comObject.QueryInterface_NoAddRef_Internal(interfaceInfo, /* cacheOnly= */ false, /* throwOnQueryInterfaceFailure= */ false);
            }

            return(comObject);
        }