Esempio n. 1
0
        static object ComInterfaceToObjectInternal_NoManagedUnboxing(
            IntPtr pComItf,
            RuntimeTypeHandle interfaceType,
            RuntimeTypeHandle classTypeInSignature,
            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,
                           interfaceType,
                           classTypeInSignature,
                           ContextCookie.Default,
                           flags
                           ));
            }
            finally
            {
                McgMarshal.ComRelease(pComIdentityIUnknown);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Returns whether the IUnknown* is a free-threaded COM object
        /// </summary>
        /// <param name="pUnknown"></param>
        internal static unsafe bool IsFreeThreaded(IntPtr pUnknown)
        {
            //
            // Does it support IAgileObject?
            //
            IntPtr pAgileObject = McgMarshal.ComQueryInterfaceNoThrow(pUnknown, ref Interop.COM.IID_IAgileObject);

            if (pAgileObject != default(IntPtr))
            {
                // Anything that implements IAgileObject is considered to be free-threaded
                // NOTE: This doesn't necessarily mean that the object is free-threaded - it only means
                // we BELIEVE it is free-threaded
                McgMarshal.ComRelease_StdCall(pAgileObject);
                return(true);
            }

            IntPtr pMarshal = McgMarshal.ComQueryInterfaceNoThrow(pUnknown, ref Interop.COM.IID_IMarshal);

            if (pMarshal == default(IntPtr))
            {
                return(false);
            }

            try
            {
                //
                // Check the un-marshaler
                //
                Interop.COM.__IMarshal *pIMarshalNativePtr = (Interop.COM.__IMarshal *)(void *) pMarshal;

                fixed(Guid *pGuid = &Interop.COM.IID_IUnknown)
                {
                    Guid clsid;
                    int  hr = CalliIntrinsics.StdCall__int(
                        pIMarshalNativePtr->vtbl->pfnGetUnmarshalClass,
                        new IntPtr(pIMarshalNativePtr),
                        pGuid,
                        default(IntPtr),
                        (uint)Interop.COM.MSHCTX.MSHCTX_INPROC,
                        default(IntPtr),
                        (uint)Interop.COM.MSHLFLAGS.MSHLFLAGS_NORMAL,
                        &clsid);

                    if (hr >= 0 && InteropExtensions.GuidEquals(ref clsid, ref Interop.COM.CLSID_InProcFreeMarshaler))
                    {
                        // The un-marshaller is indeed the unmarshaler for the FTM so this object
                        // is free threaded.
                        return(true);
                    }
                }

                return(false);
            }
            finally
            {
                McgMarshal.ComRelease_StdCall(pMarshal);
            }
        }
Esempio n. 3
0
        public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv)
        {
            int hr = 0;

            ppv = McgMarshal.ComQueryInterfaceNoThrow(pUnk, ref iid, out hr);
#if CORECLR
            if (ppv == default(IntPtr))
            {
                return(Marshal.QueryInterface(pUnk, ref iid, out ppv));
            }
#endif
            return(hr);
        }
Esempio n. 4
0
        /// <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,
            RuntimeTypeHandle interfaceType,
            RuntimeTypeHandle classTypeInSigature,
            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,
                    interfaceType,
                    classTypeInSigature,
                    expectedContext,
                    flags
                    );

                return(obj);
            }
            finally
            {
                McgMarshal.ComRelease(pComIdentityIUnknown);
            }
        }
Esempio n. 5
0
        /// <summary>
        /// This method returns a new Exception object given the HR value.
        ///
        /// 1. We check whether we have our own LanguageException associated with this hr. If so we simply use it since it helps preserve the stacktrace, message and type.
        ///    This is done using GetLanguageException API on ILanguageExceptionErrorInfo from IRestrictedErrorInfo. Since ILanguageExceptionErrorInfo is available only on Windows Blue
        ///    we can only do this WindowsBlue and above. In desktop CLR we could use GetErroInfo and check whether we have our IErroInfo and retrieve our own exception.
        ///    For Win8 in .NET Native we simply create the exception using the RestrictedErrorInfo and hence only able to give the exception with restrictedErrorMsg.
        /// 2. In case we do not have the languageException we simply check RestrictedErrorInfo for errorMsg and create an exception using
        ///   <errorMsg>\r\n<restrictedErrorMsg>. This is done for only windows blue. To be backward compatible we only use errorMsg for creating exception in win8.
        /// 3. PS - This class puts all the logic in try, catch block to ensure that none of the exception helpers
        ///  throw exception themselves.
        /// </summary>
        /// <param name="hr"></param>
        /// <param name="isWinRTScenario"></param>
        internal static Exception GetExceptionForHRInternalNoThrow(int hr, bool isWinRTScenario, bool isClassicCOM)
        {
            Exception ex;
            IntPtr    pRestrictedErrorInfo = IntPtr.Zero;

            try
            {
                if (TryGetRestrictedErrorInfo(out pRestrictedErrorInfo))
                {
                    // This is to check whether we need to give post win8 behavior or not.
                    if (isWinRTScenario)
                    {
                        // Check whether the given IRestrictedErrorInfo object supports ILanguageExceptionErrorInfo
                        IntPtr pLanguageExceptionErrorInfo = McgMarshal.ComQueryInterfaceNoThrow(pRestrictedErrorInfo, ref Interop.COM.IID_ILanguageExceptionErrorInfo);
                        if (pLanguageExceptionErrorInfo != IntPtr.Zero)
                        {
                            // We have an LanguageExceptionErrorInfo.
                            IntPtr pUnk;
                            __com_ILanguageExceptionErrorInfo *pComLanguageExceptionErrorInfo = (__com_ILanguageExceptionErrorInfo *)pLanguageExceptionErrorInfo;
                            int result = CalliIntrinsics.StdCall <int>(pComLanguageExceptionErrorInfo->pVtable->pfnGetLanguageException, pLanguageExceptionErrorInfo, out pUnk);
                            McgMarshal.ComSafeRelease(pLanguageExceptionErrorInfo);

                            if (result >= 0 && pUnk != IntPtr.Zero)
                            {
                                try
                                {
                                    // Check whether the given pUnk is a managed exception.
                                    ComCallableObject ccw;
                                    if (ComCallableObject.TryGetCCW(pUnk, out ccw))
                                    {
                                        return(ccw.TargetObject as Exception);
                                    }
                                }
                                finally
                                {
                                    McgMarshal.ComSafeRelease(pUnk);
                                }
                            }
                        }
                    }
                    String message = null, errorInfoReference = null;
                    string errMsg, errCapSid, resErrMsg;
                    int    errHr;
                    object restrictedErrorInfo = null;

                    bool hasErrorInfo = false;
                    if (RestrictedErrorInfoHelper.GetErrorDetails(pRestrictedErrorInfo, out errMsg, out errHr, out resErrMsg, out errCapSid) && errHr == hr)
                    {
                        // RestrictedErrorInfo details can be used since the pRestrictedErrorInfo has the same hr value as the hr returned by the native code.
                        // We are in windows blue or above and hence the exceptionMsg is errMsg + "\r\n" + resErrMsg
                        message = String.IsNullOrEmpty(resErrMsg) ? errMsg : errMsg + "\r\n" + resErrMsg;
                        RestrictedErrorInfoHelper.GetReference(pRestrictedErrorInfo, out errorInfoReference);
                        restrictedErrorInfo = McgMarshal.ComInterfaceToObject(pRestrictedErrorInfo, InternalTypes.IRestrictedErrorInfo);

                        hasErrorInfo = true;
                    }

                    if (hr == Interop.COM.RO_E_CLOSED && isWinRTScenario)
                    {
                        hr = Interop.COM.COR_E_OBJECTDISPOSED;
                    }

                    // Now we simply need to set the description and the resDescription by adding an internal method.
                    ex = GetMappingExceptionForHR(hr, message, isClassicCOM, hasErrorInfo);

                    if (restrictedErrorInfo != null)
                    {
                        InteropExtensions.AddExceptionDataForRestrictedErrorInfo(ex, resErrMsg, errorInfoReference, errCapSid, restrictedErrorInfo);
                    }

                    return(ex);
                }
            }
            catch (Exception)
            {
                // We can't do any thing here and hence we swallow the exception and get the corresponding hr.
            }
            finally
            {
                McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
            }

            // We could not find any restrictedErrorInfo associated with this object and hence we simply use the hr to create the exception.
            return(GetMappingExceptionForHR(hr, null, isClassicCOM, hasErrorInfo: false));
        }
Esempio n. 6
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);
        }