Esempio n. 1
0
            internal static void GetReference(System.IntPtr pRestrictedErrorInfo, out string errReference)
            {
                Debug.Assert(pRestrictedErrorInfo != IntPtr.Zero);
                IntPtr pReference = IntPtr.Zero;

                errReference = null;

                try
                {
                    __com_IRestrictedErrorInfo *pComRestrictedErrorInfo = (__com_IRestrictedErrorInfo *)pRestrictedErrorInfo;
                    int result = CalliIntrinsics.StdCall <int>(pComRestrictedErrorInfo->pVtable->pfnGetReference, pRestrictedErrorInfo, out pReference);
                    if (result >= 0)
                    {
                        errReference = Interop.COM.ConvertBSTRToString(pReference);
                    }
                    else
                    {
                        errReference = null;
                    }
                }
                finally
                {
                    if (pReference != IntPtr.Zero)
                    {
                        ExternalInterop.SysFreeString(pReference);
                    }
                }
            }
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,
                        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
            internal static bool GetErrorDetails(System.IntPtr pRestrictedErrorInfo, out string errMsg, out int hr, out string resErrMsg, out string errCapSid)
            {
                Debug.Assert(pRestrictedErrorInfo != IntPtr.Zero);
                IntPtr pErrDes, pResErrDes, pErrCapSid;

                pErrDes = pResErrDes = pErrCapSid = IntPtr.Zero;
                int result;

                try
                {
                    // Get the errorDetails associated with the restrictedErrorInfo.
                    __com_IRestrictedErrorInfo *pComRestrictedErrorInfo = (__com_IRestrictedErrorInfo *)pRestrictedErrorInfo;
                    result = CalliIntrinsics.StdCall <int>(
                        pComRestrictedErrorInfo->pVtable->pfnGetErrorDetails,
                        pRestrictedErrorInfo,
                        out pErrDes,
                        out hr,
                        out pResErrDes,
                        out pErrCapSid);

                    if (result >= 0)
                    {
                        // RestrictedErrorInfo details can be used since the pRestrictedErrorInfo has the same hr value as the hr returned by the native code.
                        errMsg    = Interop.COM.ConvertBSTRToString(pErrDes);
                        resErrMsg = Interop.COM.ConvertBSTRToString(pResErrDes);
                        errCapSid = Interop.COM.ConvertBSTRToString(pErrCapSid);
                    }
                    else
                    {
                        errMsg = resErrMsg = errCapSid = null;
                        hr     = 0;
                    }
                }
                finally
                {
                    if (pErrDes != IntPtr.Zero)
                    {
                        ExternalInterop.SysFreeString(pErrDes);
                    }
                    if (pResErrDes != IntPtr.Zero)
                    {
                        ExternalInterop.SysFreeString(pResErrDes);
                    }
                    if (pErrCapSid != IntPtr.Zero)
                    {
                        ExternalInterop.SysFreeString(pErrCapSid);
                    }
                }

                return(result >= 0);
            }
Esempio n. 4
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);
                    }
                }
            }
        }
Esempio n. 5
0
        /// <summary>
        /// Given a IStream*, change its size
        /// </summary>
        internal static unsafe bool SetStreamSize(IntPtr pStream, ulong lSize)
        {
            Interop.COM.__IStream *pStreamNativePtr = (Interop.COM.__IStream *)(void *) pStream;
            UInt64 newPosition;

            int hr = CalliIntrinsics.StdCall <int>(
                pStreamNativePtr->vtbl->pfnSetSize,
                pStreamNativePtr,
                lSize,
                (uint)Interop.COM.STREAM_SEEK.STREAM_SEEK_SET,
                &newPosition);

            return(hr >= 0);
        }
Esempio n. 6
0
        /// <summary>
        /// Given a IStream*, seek to its beginning
        /// </summary>
        internal static unsafe bool SeekStreamToBeginning(IntPtr pStream)
        {
            Interop.COM.__IStream *pStreamNativePtr = (Interop.COM.__IStream *)(void *) pStream;
            UInt64 newPosition;

            int hr = CalliIntrinsics.StdCall <int>(
                pStreamNativePtr->vtbl->pfnSeek,
                pStreamNativePtr,
                0UL,
                (uint)Interop.COM.STREAM_SEEK.STREAM_SEEK_SET,
                &newPosition);

            return(hr >= 0);
        }
Esempio n. 7
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));
        }