Skip to content

Commit

Permalink
Set ErrorInfo in Marshal.GetHRForException
Browse files Browse the repository at this point in the history
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.

Change-Id: Ib400636ee3caa54c9db8f41dbd40f15710024a63
  • Loading branch information
ermshiperete committed Jan 19, 2012
1 parent aa39994 commit c442c61
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 20 deletions.
@@ -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
{
/// <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
}
}
54 changes: 34 additions & 20 deletions mcs/class/corlib/System.Runtime.InteropServices/Marshal.cs
Expand Up @@ -363,9 +363,16 @@ public static IntPtr GetHINSTANCE (Module m)
}
#endif // !NET_2_1

[MonoTODO ("SetErrorInfo")]
public static int GetHRForException (Exception e)
{
try {
var errorInfo = new ManagedErrorInfo(e);
SetErrorInfo (0, errorInfo);
} catch (Exception ee) {
// ignore any exception - probably there's no suitable SetErrorInfo
// method available.
}

return e.hresult;
}

Expand Down Expand Up @@ -1242,6 +1249,10 @@ private static Exception ConvertHrToException (int errorCode)
return null;
}

[DllImport ("oleaut32.dll", CharSet=CharSet.Unicode)]
internal static extern int SetErrorInfo (int dwReserved,
[MarshalAs(UnmanagedType.Interface)] IErrorInfo pIErrorInfo);

[DllImport ("oleaut32.dll", CharSet=CharSet.Unicode)]
internal static extern int GetErrorInfo (int dwReserved,
[MarshalAs(UnmanagedType.Interface)] out IErrorInfo ppIErrorInfo);
Expand All @@ -1253,10 +1264,8 @@ public static Exception GetExceptionForHR (int errorCode)

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) {
try {
if (GetErrorInfo (0, out errorInfo) != 0) {
Expand All @@ -1270,22 +1279,27 @@ public static Exception GetExceptionForHR (int errorCode, IntPtr errorInfoPtr)
} 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;
Expand Down
1 change: 1 addition & 0 deletions mcs/class/corlib/corlib.dll.sources
Expand Up @@ -774,6 +774,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
Expand Down

0 comments on commit c442c61

Please sign in to comment.