--- /dev/null
+// 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
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ 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
+ }
+}
#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;
}
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;
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;
} 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;