Solved

Getting the Exceptions HResult value in .net 4 or earlier

Posted on 2015-02-18
20
818 Views
Last Modified: 2015-02-22
An exception has a HResult property.  From .net 4.5 onwards the getter is public but in .net 4 or earlier it is protected.
I want to trap an explicit (Microsoft) exception and suppress the default warning message so the obvious way is:
if(e.HResult == ....
but this won't compile in a .net 4 based app because the e.HResult is protected.

So is there a simple workaround to extract the HResult value in a .net 4 based app?  

(The app will run on English and non-English operating systems so I can't rely on the text of the message).
0
Comment
Question by:AndyAinscow
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 6
  • 6
20 Comments
 
LVL 34

Accepted Solution

by:
it_saige earned 450 total points
ID: 40619735
Use Marshal.GetHRForException() in System.Runtime.InteropServices.

-saige-
0
 
LVL 96

Assisted Solution

by:Bob Learned
Bob Learned earned 50 total points
ID: 40619741
I would use reflection to get that protected property value.

Here is an example:

            try
            {
                throw new InvalidOperationException("Test");
            }
            catch (Exception ex)
            {
                var property = ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance);

                var value = property.GetValue(ex, null);

                Console.WriteLine(value);
            }

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40619744
Marshal.GetHRForException slipped right out of my full brain.
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 34

Expert Comment

by:it_saige
ID: 40619752
@Bob - *in sarcastic voice* Oh I never have one of those moments...  ;)

@Andy - Example using bob's code -
using System;

namespace EE_Q28620045
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				throw new InvalidOperationException("Test");
			}
			catch (Exception ex)
			{
				Console.WriteLine(System.Runtime.InteropServices.Marshal.GetHRForException(ex));
			}
		}
	}
}

Open in new window

Produces the following output -Capture.JPG-saige-
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40620684
@it_saige
The System.Runtime.InteropServices.Marshal.GetHRForException worked without problems.  So my question is answered with that.  I'll leave it open for a short while should Bob wish to respond to ---


@Bob
                var property = ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance);

property was null after that line so the GetValue line faulted with an exception.
Do you want more info / to look into it further (out of academic interest)?
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40621191
I looked at a project with 3.5 framework set, and the Exception class had the HResult property as protected.  With that it worked for me, but if there is no property with that name, and only a private field, you would switch to use ex.GetType().GetField("_hResult", BindingFlags.NonPublic | BindingFlags.Instance) for example.  The specifics really depend on the class structure.
0
 
LVL 34

Expert Comment

by:it_saige
ID: 40621215
@Andy - I implemented Bob's code and did get the expected results:
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Reflection;

namespace EE_Q28620045
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				throw new InvalidOperationException("Test");
			}
			catch (Exception ex)
			{
				Console.WriteLine("Using linq to reflect Exception properties and get HResult property value:");
				var prop1 = (from prop in ex.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) where prop.Name.Equals("HResult") select prop).FirstOrDefault();
				Console.WriteLine("{0} = {1}", prop1.Name, prop1.GetValue(ex, null));

				Console.WriteLine();

				Console.WriteLine("Using reflection to get Exception HResult property value:");
				var prop2 = ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance);
				Console.WriteLine("{0} = {1}", prop2.Name, prop2.GetValue(ex, null));

				Console.WriteLine();

				Console.WriteLine("Using GetHRForException() to get Exception HResult property value:", ex.GetType().ToString());
				Console.WriteLine("HResult = {0}", Marshal.GetHRForException(ex));
			}
			Console.ReadLine();
		}
	}
}

Open in new window

Produced the following output -Capture.JPGP.S - Sorry, couldn't resist throwing in a bit of linq.  ;)

-saige-
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40621223
I'll look a little closer - I'm fighting to get the office ribbon to accept a custom image at present - but not certain if I have time today.
0
 
LVL 34

Expert Comment

by:it_saige
ID: 40621225
@Bob - In all honesty, if you are using reflection in order to get the values of private/protected members, I would imagine that it would, ultimately, make more sense to get the field value as opposed to the property value.  That is unless the property has some specialized logic in it.

-saige-
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40621382
<Image problem is temporarily solved.>

                var property = e.GetType().GetField("_hResult", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
Still has property as null.
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40621403
New console app.  .Net framework 4:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                throw new System.Security.Cryptography.CryptographicException(-2146233296); //  0x80131430;
            }
            catch (System.Security.Cryptography.CryptographicException e)
            {
                int i = System.Runtime.InteropServices.Marshal.GetHRForException(e);

                var property = e.GetType().GetProperty("HResult", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                //var property = e.GetType().GetField("_hResult", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
                var value = property.GetValue(e, null);
            }

        }
    }
}

Open in new window


with a breakpoint on the var value.... line the var property is null for both wheras the value of i is that of the HResult put into the exception
0
 
LVL 34

Expert Comment

by:it_saige
ID: 40621448
@Andy - I found the problem.  You had mentioned that in .NET 4, the HResult is a public property.  This means that you need to add a BindingFlag for the public properties in order to retrieve it:
using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Reflection;

namespace EE_Q28620045
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				//throw new InvalidOperationException("Test");
				throw new System.Security.Cryptography.CryptographicException(-2146233296);
			}
			catch (Exception ex)
			{
				Console.WriteLine("Using linq to reflect Exception properties and get HResult property value:");
				var prop1 = (from prop in ex.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public) where prop.Name.Equals("HResult") select prop).FirstOrDefault();
				Console.WriteLine("{0} = {1}", prop1.Name, prop1.GetValue(ex, null));

				Console.WriteLine();

				Console.WriteLine("Using reflection to get Exception HResult property value:");
				var prop2 = ex.GetType().GetProperty("HResult", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
				Console.WriteLine("{0} = {1}", prop2.Name, prop2.GetValue(ex, null));

				Console.WriteLine();

				Console.WriteLine("Using GetHRForException() to get Exception HResult property value:", ex.GetType().ToString());
				Console.WriteLine("HResult = {0}", Marshal.GetHRForException(ex));
			}
			Console.ReadLine();
		}
	}
}

Open in new window

Produces the following output (regardless of using Framework 3.5 or 4):Capture.JPG-saige-
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40621450
I would suggest using what works (Marshal.GetHRForException, but if you are interested in the reflection issue, the specifics depends on the specific implementation.

The reflection example that I showed you attempted to the get HResult property from the Exception.  I threw an InvalidOperationException, and use F12 to Go to Definition, until I got down to the base Exception class.

Here is the screen shot of the properties available for the class.  Fields are not shown in this view, which is why I reflected against property, and not field.  You would need to use a disassembler, like Reflector or Just Decompile to get the real field names.

Exception class properties
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40621452
If it is a public property, then you certainly don't need to use anything heavy like reflection.
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40621462
@it_saige.  It is only public in .net 4.5 and later and this is for a previous version of .net.
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40621466
Or according to the documentation it is - and mine didn't compile when attempting to access the HResult directly.
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 40621475
Another approach is to use Exception.GetType().GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) to get a list of all properties, so that you can see the entire list.  Then, you can pick out the property name that you want.
0
 
LVL 34

Expert Comment

by:it_saige
ID: 40621477
@Andy - That may definately be true.  In testing for .NET 4, I received this output for the properties of Exception without the Public BindingFlag:Capture.JPGAnd this output with the Public BindingFlag:Capture.JPG
Conversely using .NET 3.5, I recieve this output for the properties of Exception without the Public BindingFlag:Capture.JPGAnd this output with the Public BindingFlag:Capture.JPG
-saige-
0
 
LVL 44

Author Comment

by:AndyAinscow
ID: 40623947
This is rather wierd - I suspect a bug somewhere in VS or .net.

The code from Bob works with .net 3.5 but not with .net 4
Changing the flags to include public properties then the code from Bob works with .net 4
HOWEVER the HResult is still unavailable due to its protection level in .net 4 - ie still as protected (as the documentation states).

In any case the Marshal.GetHRForException works in all instances that I have tested.
0
 
LVL 44

Author Closing Comment

by:AndyAinscow
ID: 40623950
Thanks.
For anyone reading this note my final summary comment.
0

Featured Post

Why You Need a DevOps Toolchain

IT needs to deliver services with more agility and velocity. IT must roll out application features and innovations faster to keep up with customer demands, which is where a DevOps toolchain steps in. View the infographic to see why you need a DevOps toolchain.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
parse string in c# 5 40
VB.net Filesystem watcher not working 5 55
What are MicroServices? 4 66
Why am I losing my session variable value 11 35
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
In a recent question (https://www.experts-exchange.com/questions/29004105/Run-AutoHotkey-script-directly-from-Notepad.html) here at Experts Exchange, a member asked how to run an AutoHotkey script (.AHK) directly from Notepad++ (aka NPP). This video…

738 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question