From: Eberhard Beilharz Date: Thu, 13 Mar 2014 17:55:39 +0000 (+0100) Subject: Set ErrorInfo in Marshal.GetHRForException X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=2d420bfb7a394884b7f8f52368907db186b855d9;p=mono.git Set ErrorInfo in Marshal.GetHRForException Marshal.GetHRForException had a MonoTODO because it needs to set the errorinfo object so that exceptions get properly passed to unmanaged code. Since not all managed exceptions have a corresponding HR value but we might need to get to the original thrown exception we implement a ManagedErrorInfo helper class that implements the IErrorInfo interface but also stores the exception. In GetExceptionForHR we check if the errorinfo we get is a ManagedErrorInfo. If it is we return the exception stored in there (if it converts to the same error code), otherwise we construct a new exception. --- diff --git a/mcs/class/corlib/System.Runtime.InteropServices/ManagedErrorInfo.cs b/mcs/class/corlib/System.Runtime.InteropServices/ManagedErrorInfo.cs new file mode 100644 index 00000000000..c77857c9db4 --- /dev/null +++ b/mcs/class/corlib/System.Runtime.InteropServices/ManagedErrorInfo.cs @@ -0,0 +1,63 @@ +// ManagedErrorInfo class +// +// Eberhard Beilharz (eb1@sil.org) +// +// Copyright (C) 2012 SIL International +using System; +using System.Runtime.CompilerServices; +using System.Security; + +namespace System.Runtime.InteropServices +{ + /// + /// Helper class that allows to pass an exception as an IErrorInfo object. This is useful + /// when we get an exception in managed code that is called from unmanaged code that is called + /// from managed code and we want to get to the exception in the outer managed code. + /// + internal class ManagedErrorInfo: IErrorInfo + { + private Exception m_Exception; + public ManagedErrorInfo (Exception e) + { + m_Exception = e; + } + + public Exception Exception { + get { return m_Exception; } + } + + #region IErrorInfo + public int GetGUID (out Guid guid) + { + // not supported + guid = Guid.Empty; + return 0; + } + + public int GetSource (out string source) + { + source = m_Exception.Source; + return 0; + } + + public int GetDescription (out string description) + { + description = m_Exception.Message; + return 0; + } + + public int GetHelpFile (out string helpFile) + { + helpFile = m_Exception.HelpLink; + return 0; + } + + public int GetHelpContext(out uint helpContext) + { + // not supported + helpContext = 0; + return 0; + } + #endregion + } +} diff --git a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs index bddd71f12b5..95df86a7c8f 100644 --- a/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs +++ b/mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs @@ -414,9 +414,11 @@ namespace System.Runtime.InteropServices #endif // !FULL_AOT_RUNTIME #if !FULL_AOT_RUNTIME - [MonoTODO ("SetErrorInfo")] public static int GetHRForException (Exception e) { + var errorInfo = new ManagedErrorInfo(e); + SetErrorInfo (0, errorInfo); + return e.hresult; } @@ -1520,12 +1522,36 @@ namespace System.Runtime.InteropServices return null; } + [DllImport ("oleaut32.dll", CharSet=CharSet.Unicode, EntryPoint = "SetErrorInfo")] + static extern int _SetErrorInfo (int dwReserved, + [MarshalAs(UnmanagedType.Interface)] IErrorInfo pIErrorInfo); + [DllImport ("oleaut32.dll", CharSet=CharSet.Unicode, EntryPoint = "GetErrorInfo")] static extern int _GetErrorInfo (int dwReserved, [MarshalAs(UnmanagedType.Interface)] out IErrorInfo ppIErrorInfo); + static bool SetErrorInfoNotAvailable; static bool GetErrorInfoNotAvailable; + internal static int SetErrorInfo (int dwReserved, IErrorInfo errorInfo) + { + int retVal = 0; + errorInfo = null; + + if (SetErrorInfoNotAvailable) + return -1; + + try { + retVal = _SetErrorInfo (dwReserved, errorInfo); + } + catch (Exception) { + // ignore any exception - probably there's no suitable SetErrorInfo + // method available. + SetErrorInfoNotAvailable = true; + } + return retVal; + } + internal static int GetErrorInfo (int dwReserved, out IErrorInfo errorInfo) { int retVal = 0; @@ -1552,10 +1578,8 @@ namespace System.Runtime.InteropServices public static Exception GetExceptionForHR (int errorCode, IntPtr errorInfoPtr) { - Exception e = ConvertHrToException (errorCode); - - if (errorInfoPtr != (IntPtr)(-1) && e != null) { - IErrorInfo errorInfo = null; + IErrorInfo errorInfo = null; + if (errorInfoPtr != (IntPtr)(-1)) { if (errorInfoPtr == IntPtr.Zero) { if (GetErrorInfo (0, out errorInfo) != 0) { errorInfo = null; @@ -1563,22 +1587,27 @@ namespace System.Runtime.InteropServices } else { errorInfo = Marshal.GetObjectForIUnknown (errorInfoPtr) as IErrorInfo; } + } - if (errorInfo != null) { - uint helpContext; - errorInfo.GetHelpContext (out helpContext); - string str; - errorInfo.GetSource (out str); - e.Source = str; - errorInfo.GetDescription (out str); - e.SetMessage (str); - errorInfo.GetHelpFile (out str); - - if (helpContext == 0) { - e.HelpLink = str; - } else { - e.HelpLink = string.Format ("{0}#{1}", str, helpContext); - } + if (errorInfo is ManagedErrorInfo && ((ManagedErrorInfo)errorInfo).Exception.hresult == errorCode) { + return ((ManagedErrorInfo)errorInfo).Exception; + } + + Exception e = ConvertHrToException (errorCode); + if (errorInfo != null && e != null) { + uint helpContext; + errorInfo.GetHelpContext (out helpContext); + string str; + errorInfo.GetSource (out str); + e.Source = str; + errorInfo.GetDescription (out str); + e.SetMessage (str); + errorInfo.GetHelpFile (out str); + + if (helpContext == 0) { + e.HelpLink = str; + } else { + e.HelpLink = string.Format ("{0}#{1}", str, helpContext); } } return e; diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index 1a874b863d1..0bf28c2287d 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -818,6 +818,7 @@ System.Runtime.InteropServices/InvalidOleVariantTypeException.cs System.Runtime.InteropServices/LCIDConversionAttribute.cs System.Runtime.InteropServices/LIBFLAGS.cs System.Runtime.InteropServices/LayoutKind.cs +System.Runtime.InteropServices/ManagedErrorInfo.cs System.Runtime.InteropServices/Marshal.cs System.Runtime.InteropServices/MarshalAsAttribute.cs System.Runtime.InteropServices/MarshalDirectiveException.cs