示例#1
0
#pragma warning restore 649, 169

        /// <summary>
        /// This method gets the mapping hr for the exception. and also does the right thing to propogate the hr correctly to the native layer.
        ///
        /// We check if the exception is a pure managed exception or an exception created from an hr that entered the system from native.
        /// a. If it is a pure managed exception we create an IUnknown ptr from the exception and RoOriginateLanguageException on it.
        ///    This helps us to preserve our managed exception and throw the same exception in case this exception roundtrips and hence preserve the call stack.
        ///    Since the API RoOriginateLanguageException is available only on windows blue, we can't do the same in win8. In desktop CLR we use the non-modern SDK API
        ///    GetErroInfo\SetErrorInfo combination to preserve managed exception but unfortunately we can't do this in .NET Native and hence we only our able to preserve the exception message and
        ///    type and end up getting a rough stacktrace PS - Even this behavior in win8 is possible only in debug mode as RoSetErrorReportingFlags is set to UseSetErrorInfo only in debug mode.
        ///
        /// b. In case the exception is created due to an hr that entered managed world via native call, we will have restrictederrorInfo associated with it. In this case
        ///    we do not RoOriginateLanguageException\RoOriginateError and rather preserve the exception stack trace by simply calling the SetRestrictedErrorInfo.
        ///
        /// c. PS - Due to the use of modern SDK we have no way to round trip exceptions in classicCOM scenarios any more.
        ///     This is because we can't use SetErrorInfo\GetErrorInfo APIs at all. Unfortunately we have no workaround for this even in windowsBlue!
        ///    With the use of IRestrictedErrorInfo has some disadvantages as we lose other info available with IErrorInfo in terms of HelpFile etc.
        ///
        /// d. This class puts all the logic in try, catch block to ensure that none of the exception helpers.
        ///  throw exception themselves.
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="isWinRTScenario"></param>
        /// <returns></returns>
        internal static int GetHRForExceptionWithErrorPropogationNoThrow(Exception ex, bool isWinRTScenario)
        {
            int hr = ex.HResult;

            if (hr == Interop.COM.COR_E_OBJECTDISPOSED && isWinRTScenario)
            {
                // Since ObjectDisposedException is projected to RO_E_CLOSED in WINRT we make sure to use the correct hr while updating the CRuntimeError object of Windows.
                hr = Interop.COM.RO_E_CLOSED;
            }

            try
            {
                // Check whether the exception has an associated RestrictedErrorInfo associated with it.
                if (isWinRTScenario)
                {
                    IntPtr pRestrictedErrorInfo;
                    object restrictedErrorInfo;
                    if (InteropExtensions.TryGetRestrictedErrorObject(ex, out restrictedErrorInfo) && restrictedErrorInfo != null)
                    {
                        // We have the restricted errorInfo associated with this object and hence this exception was created by an hr entering managed through native.
                        pRestrictedErrorInfo = McgMarshal.ObjectToComInterface(restrictedErrorInfo, InternalTypes.IRestrictedErrorInfo);
                        if (pRestrictedErrorInfo != IntPtr.Zero)
                        {
                            // We simply call SetRestrictedErrorInfo since we do not want to originate the exception again.
                            ExternalInterop.SetRestrictedErrorInfo(pRestrictedErrorInfo);
                            McgMarshal.ComSafeRelease(pRestrictedErrorInfo);
                        }
                    }
                    else
                    {
                        // we are in windows blue and hence we can preserve our exception so that we can reuse this exception in case it comes back and provide richer exception support.
                        OriginateLanguageException(ex);
                    }
                }
                else
                {
                    // We are either pre WinBlue or in classicCOM scenario and hence we can only RoOriginateError at this point.
                    // Desktop CLR uses SetErrorInfo and preserves the exception object which helps us give the same support as winBlue.
                    // Since .NET Native can only use modern SDK we have a compatibility break here by only preserving the restrictederrorMsg and exception type but the stack trace will be incorrect.

                    // Also RoOriginateError works only under the debugger since RoSetErrorReportingFlags is set to RO_ERROR_REPORTING_USESETERRORINFO.
                    // If we are not under the debugger we can't set this API since it is not part of the modernSDK and hence this will not work
                    // and will result in different behavior than the desktop.
                    HSTRING errorMsg = McgMarshal.StringToHString(ex.Message);
                    ExternalInterop.RoOriginateError(ex.HResult, errorMsg);
                    ExternalInterop.WindowsDeleteString(errorMsg.handle.ToPointer());
                }
            }
            catch (Exception)
            {
                // We can't throw an exception here and hence simply swallow it.
            }

            return(hr);
        }