How to get local variables and object instance that threw unhandled exception
-
A coworker and I are working on a logging system for unhandled exceptions in our code (screenshots, logging system information, detailed exception info, etc) using the
Application.ThreadException
handler (our main app is in WinForms). From the exception, I can get theMethodInfo
for the method that threw the exception, and from that get theDeclaringType
of the class, and from that get all the class member variables and their values. Only one problem...I need to pass an instance of the class to theFieldInfo.GetValue
method, but I can't find a way to get access to that instance in theThreadException
event handler. I spent a few hours this evening going over theSystem.Reflection
documentation and put toegether a small console app to test a few theories, but I haven't found anything for getting a reference to a class instance from aMethodInfo
,MethodBody
, orModule
object (and yes, I used theAppDomain.UnhandledException
event for the console test app instead ofApplication.ThreadException
). Knowing the values of the class variables when the exception occurs would be very useful for debugging. Any ideas? I'm also trying to find a way to get the current values for the function parameters and local variables when the exception occurs. I know, Reflection won't help since these values are all on the stack at runtime, and Reflection works off of compile-time metadata, but there must be some way to get this information. I found this thread[^] that mentions using the Debugging API, but I didn't see anything in that documentation that looked like it would help either. Any suggestions on this one? I'm using VS2005 SP1 on XP Pro SP3 and Win7 Pro. Thanks, DybsThe shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen
-
A coworker and I are working on a logging system for unhandled exceptions in our code (screenshots, logging system information, detailed exception info, etc) using the
Application.ThreadException
handler (our main app is in WinForms). From the exception, I can get theMethodInfo
for the method that threw the exception, and from that get theDeclaringType
of the class, and from that get all the class member variables and their values. Only one problem...I need to pass an instance of the class to theFieldInfo.GetValue
method, but I can't find a way to get access to that instance in theThreadException
event handler. I spent a few hours this evening going over theSystem.Reflection
documentation and put toegether a small console app to test a few theories, but I haven't found anything for getting a reference to a class instance from aMethodInfo
,MethodBody
, orModule
object (and yes, I used theAppDomain.UnhandledException
event for the console test app instead ofApplication.ThreadException
). Knowing the values of the class variables when the exception occurs would be very useful for debugging. Any ideas? I'm also trying to find a way to get the current values for the function parameters and local variables when the exception occurs. I know, Reflection won't help since these values are all on the stack at runtime, and Reflection works off of compile-time metadata, but there must be some way to get this information. I found this thread[^] that mentions using the Debugging API, but I didn't see anything in that documentation that looked like it would help either. Any suggestions on this one? I'm using VS2005 SP1 on XP Pro SP3 and Win7 Pro. Thanks, DybsThe shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen
-
Eddy, Thanks for the reply. In my case that won't really work because I need this information in the UnhandledException handler, and by the time I get to this point (the first time I actually have an exception to look at), I no longer have access to the object that threw the exception. I can certainly use this where I can handle an exception more gracefully and still want to log it with more details, but my goal is to get as much info as I can for unhandled exceptions. Thanks, Dybs
The shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen
-
Eddy, Thanks for the reply. In my case that won't really work because I need this information in the UnhandledException handler, and by the time I get to this point (the first time I actually have an exception to look at), I no longer have access to the object that threw the exception. I can certainly use this where I can handle an exception more gracefully and still want to log it with more details, but my goal is to get as much info as I can for unhandled exceptions. Thanks, Dybs
The shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen
dybs wrote:
my goal is to get as much info as I can for unhandled exceptions
Ditto, and you're right - if the information contained helps with the debugging-proces. There's no easy anwer to your question, once one says that it's technically possible one has to answer whether it's worth the effort.
dybs wrote:
In my case that won't really work because I need this information in the UnhandledException handler, and by the time I get to this point (the first time I actually have an exception to look at), I no longer have access to the object that threw the exception.
I have created a small console-application to test with;
class Program
{
static Form myForm = new Form();
static Button myButton = new Button();\[STAThread\] public static void Main(string\[\] args) { myButton.Click += delegate { new MyTextCache().DoLoadStuff(); }; myForm.Controls.Add(myButton); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(logEx); Application.Run(myForm); } static void logEx(object sender, UnhandledExceptionEventArgs e) { Exception ex = (Exception)e.ExceptionObject; Console.WriteLine("Exception: " + e.ExceptionObject.GetType().ToString()); if (ex.Data.Count > 0) { foreach(var item in ex.Data) { var entry = (System.Collections.DictionaryEntry)item; Console.WriteLine("Parameter: " + entry.Value.ToString()); } } }
}
Rather simple, just creates a form with a button and logs any exceptions on the console. The key here is looping the
Data
property. We know that we can fill it when we throw an exception ourselves. Now, imagine that there's an unexpected exception thrown by a .NET class in theMyTextCache.DoLoadStuff
method. To add the info, we'd need to catch it, attach the desired information, and rethrow it. The MyTextCache could be adapted like shown below. There's a local exception-handler that doesn't handle the FileNotFound-exception, but instead adds a reference to the object;using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;[Serializable()]
class MyTextCache: ISerializable
{
#region variable -
dybs wrote:
my goal is to get as much info as I can for unhandled exceptions
Ditto, and you're right - if the information contained helps with the debugging-proces. There's no easy anwer to your question, once one says that it's technically possible one has to answer whether it's worth the effort.
dybs wrote:
In my case that won't really work because I need this information in the UnhandledException handler, and by the time I get to this point (the first time I actually have an exception to look at), I no longer have access to the object that threw the exception.
I have created a small console-application to test with;
class Program
{
static Form myForm = new Form();
static Button myButton = new Button();\[STAThread\] public static void Main(string\[\] args) { myButton.Click += delegate { new MyTextCache().DoLoadStuff(); }; myForm.Controls.Add(myButton); AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(logEx); Application.Run(myForm); } static void logEx(object sender, UnhandledExceptionEventArgs e) { Exception ex = (Exception)e.ExceptionObject; Console.WriteLine("Exception: " + e.ExceptionObject.GetType().ToString()); if (ex.Data.Count > 0) { foreach(var item in ex.Data) { var entry = (System.Collections.DictionaryEntry)item; Console.WriteLine("Parameter: " + entry.Value.ToString()); } } }
}
Rather simple, just creates a form with a button and logs any exceptions on the console. The key here is looping the
Data
property. We know that we can fill it when we throw an exception ourselves. Now, imagine that there's an unexpected exception thrown by a .NET class in theMyTextCache.DoLoadStuff
method. To add the info, we'd need to catch it, attach the desired information, and rethrow it. The MyTextCache could be adapted like shown below. There's a local exception-handler that doesn't handle the FileNotFound-exception, but instead adds a reference to the object;using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;[Serializable()]
class MyTextCache: ISerializable
{
#region variableThanks for the detailed response! I'm looking more into the data dictionary now and serializing the objects. One other question. I notices after you throw add the values to the Data dictionary, you use
throw e;
Doesn't this "reset" the stack track to the line where you rethrow the exception? Can you just use
throw;
instead? Or would a simple
throw
not include your changes to the dictionary? Thanks, DybsThe shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen
-
Thanks for the detailed response! I'm looking more into the data dictionary now and serializing the objects. One other question. I notices after you throw add the values to the Data dictionary, you use
throw e;
Doesn't this "reset" the stack track to the line where you rethrow the exception? Can you just use
throw;
instead? Or would a simple
throw
not include your changes to the dictionary? Thanks, DybsThe shout of progress is not "Eureka!" it's "Strange... that's not what i expected". - peterchen
dybs wrote:
Thanks for the detailed response! I'm looking more into the data dictionary now and serializing the objects.
My pleasure. Tracking the items in a dictionary would indeed be a nice alternative :)
dybs wrote:
Doesn't this "reset" the stack track to the line where you rethrow the exception?
It does! That was sloppiness in my example.
dybs wrote:
Or would a simple throw not include your changes to the dictionary?
It also includes the change if you omit the exception variable. Just verified it, just to be on the safe side.
I are Troll :suss: