How can I throw an Exception with a certain HResult?
Asked Answered
B

2

17

I want to test the following code:

private bool TestException(Exception ex)
{
    if ((Marshal.GetHRForException(ex) & 0xFFFF) == 0x4005)
    {
        return true;
    }
    return false;
}

I'd like to set up the Exception object somehow to return the correct HResult, but I can't see a field in the Exception class which allows this.

How would I do this?

Biltong answered 22/6, 2012 at 14:37 Comment(1)
The base exception class for these kind of exceptions is ExternalException. It has a public ErrorCode property with a constructor to set it. The COMException class' default HRESULT already is 0x80004005 (E_FAIL).Sinful
B
23

I found three ways to do this:

  1. Use the System.Runtime.InteropServices.ExternalException class, passing in the error code as a parameter:

    var ex = new ExternalException("-", 0x4005);
    

    Thanks to @HansPassant for his comment explaining this.

  2. Pass a mock exception using inheritance to access a protected field:

    private class MockException : Exception
    {
        public MockException() { HResult = 0x4005; }
    }
    
    var ex = new MockException();
    
  3. Use .NET Reflection to set the underlying field:

    BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
    FieldInfo hresultFieldInfo = typeof(Exception).GetField("_HResult", flags);
    
    var ex = new Exception();
    hresultFieldInfo.SetValue(ex, 0x4005);
    

Passing any one of these exceptions to the method in the question, will result in that method returning true. I suspect the first method is most useful.

Biltong answered 22/6, 2012 at 15:35 Comment(0)
T
2

I find it useful to create an extension to do this.

using System.Reflection;

namespace Helper
{
    public static class ExceptionHelper 
    {
       public static Exception SetCode(this Exception e, int value)
       {
           BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic;
           FieldInfo fieldInfo = typeof(Exception).GetField("_HResult", flags);

           fieldInfo.SetValue(e, value);

           return e;
        }
}

Then throw exception:

using Helper;

public void ExceptionTest()
{
    try
    {
        throw new Exception("my message").SetCode(999);
    }
    catch (Exception e)
    {
        string message = e.Message;
        int code = e.HResult;
    }
}
Temporize answered 13/9, 2013 at 2:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.