VS2010 did not break debug on static constructor exception - c#

I have a Windows Forms application with a single Editor class (that inherits from Form).
public partial class Editor : Form
{
public Editor()
{
InitializeComponent();
Load += Editor_Load;
}
private void Editor_Load(object sender, EventArgs e)
{
cmbConnections.DataSource = ConnectionManager.Connections;
cmbConnections.Visible = false;
}
}
Other than designer-generated code, this is the only code for the form (that contains only a single Combo Box (cmbConnections).
The ConnectionManager class is a static class with a static constructor. It's constructor does some initialization and then tests for some critical condition. If the condition is met, the constructor throws an exception. However, this exception does not break in the debugging mode in Visual Studio 2010. To test this, I've put only throw new Exception() in the ConnectionManager's static constructor. The ConnectionManager is used and therefor initialized (for the first time) in the Editor_Load event handler. Static constructor is called and exception thrown (visible only in output window). The rest of the Editor_Load event handler (cmbConnections.Visible = false;) is not executed, just as expected.
But what I don't understand is why did my VS2010 swallow the exception? It did not break the debug. It is not enclosed in any try/catch block. It continued with program execution with the main window. It almost seems as if the Editor_Load was executed on another thread.
I can see the messages in output window:
A first chance exception of type 'System.InvalidOperationException' occurred in Editor.exe
A first chance exception of type 'System.TypeInitializationException' occurred in Editor.exe
but the execution simply did not break in debug mode.
Here are some of my options that I believe may influence this behavior:
Project Properties->Build->General-> Optimize code is UNCHECKED.
Tools->Options->Debugging->General-> Enable Just My Code is CHECKED.
In exception settings, the checkbox for the "user-unhandled" is CHECKED.
Am I missing something? Is this behavior normal? I thought that VS2010 will throw on ANY unhandled exception. And here this one is unhandled and still does not break.

I think it is by design that you need to enable Managed (.NET) Exceptions 'Thrown' in the Exceptions Dialog (Ctrl-Alt-E).1
To avoid many spurious (handled) exceptions, I usually try to get close to the point where the initializer will be run and then check that checkbox just before continueing.
Also, if there are loader exceptions, be sure to check the nested inner exceptions or loader information in the exception: the exception itself is usually not that informative. I have frequently had to dig through 2 or more layers of wrapping exceptions in order to get at the actual error.
1 I can only guess as to why that is; My feeling is that the static type initializers are not considered to be run deterministically (many things could trigger it and the order is often undefined; it is just guaranteed that a type's static constructor will have been run before it is used, but it can be used at almost any point in the code, without you knowing or explicitely triggering that).
Therefore, it would be hard for the runtime to establish whether it was 'handled by user code' (no user should expect to handle it, because it doesn't know - deterministically - when the initializer will run).
However, this is conjecture on my part.

Related

why does the instance method Controls.Find crash without an exception? [duplicate]

When I create a new project, I get a strange behavior for unhandled exceptions. This is how I can reproduce the problem:
1) create a new Windows Forms Application (C#, .NET Framework 4, VS2010)
2) add the following code to the Form1_Load handler:
int vara = 5, varb = 0;
int varc = vara / varb;
int vard = 7;
I would expect that VS breaks and shows an unhandled exception message at the second line. However, what happens is that the third line is just skipped without any message and the application keeps running.
I don't have this problem with my existing C# projects. So I guess that my new projects are created with some strange default settings.
Does anyone have an idea what's wrong with my project???
I tried checking the boxes in Debug->Exceptions. But then executions breaks even if I handle the exception in a try-catch block; which is also not what I want. If I remember correctly, there was a column called "unhandled exceptions" or something like this in this dialog box, which would do excatly what I want. But in my projects there is only one column ("Thrown").
This is a nasty problem induced by the wow64 emulation layer that allows 32-bit code to run on the 64-bit version of Windows 7. It swallows exceptions in the code that runs in response to a notification generated by the 64-bit window manager, like the Load event. Preventing the debugger from seeing it and stepping in. This problem is hard to fix, the Windows and DevDiv groups at Microsoft are pointing fingers back and forth. DevDiv can't do anything about it, Windows thinks it is the correct and documented behavior, mysterious as that sounds.
It is certainly documented but just about nobody understands the consequences or thinks it is reasonable behavior. Especially not when the window procedure is hidden from view of course, like it is in any project that uses wrapper classes to hide the window plumbing. Like any Winforms, WPF or MFC app. Underlying issue is Microsoft could not figure out how to flow exceptions from 32-bit code back to the 64-bit code that triggered the notification back to 32-bit code that tries to handle or debug the exception.
It is only a problem with a debugger attached, your code will bomb as usual without one.
Project > Properties > Build tab > Platform target = AnyCPU and untick Prefer 32-bit. Your app will now run as a 64-bit process, eliminating the wow64 failure mode. Some consequences, it disables Edit + Continue for VS versions prior to VS2013 and might not always be possible when you have a dependency on 32-bit code.
Other possible workarounds:
Debug > Exceptions > tick the Thrown box for CLR exceptions to force the debugger to stop at the line of code that throws the exception.
Write try/catch in the Load event handler and failfast in the catch block.
Use Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException) in the Main() method so that the exception trap in the message loop isn't disabled in debug mode. This however makes all unhandled exceptions hard to debug, the ThreadException event is pretty useless.
Consider if your code really belongs in the Load event handler. It is very rare to need it, it is however very popular in VB.NET and a swan song because it is the default event and a double-click trivially adds the event handler. You only ever really need Load when you are interested in the actual window size after user preferences and autoscaling is applied. Everything else belongs in the constructor.
Update to Windows 8 or later, they have this wow64 problem solved.
In my experience, I only see this issue when I'm running with a debugger attached. The application behaves the same when run standalone: the exception is not swallowed.
With the introduction of KB976038, you can make this work as you'd expect again. I never installed the hotfix, so I'm assuming it came as part of Win7 SP1.
This was mentioned in this post:
The case of the disappearing OnLoad exception – user-mode callback exceptions in x64
Here's some code that will enable the hotfix:
public static class Kernel32
{
public const uint PROCESS_CALLBACK_FILTER_ENABLED = 0x1;
[DllImport("Kernel32.dll")]
public static extern bool SetProcessUserModeExceptionPolicy(UInt32 dwFlags);
[DllImport("Kernel32.dll")]
public static extern bool GetProcessUserModeExceptionPolicy(out UInt32 lpFlags);
public static void DisableUMCallbackFilter() {
uint flags;
GetProcessUserModeExceptionPolicy(out flags);
flags &= ~PROCESS_CALLBACK_FILTER_ENABLED;
SetProcessUserModeExceptionPolicy(flags);
}
}
Call it at the beginning of your application:
[STAThread]
static void Main()
{
Kernel32.DisableUMCallbackFilter();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
I've confirmed (with the the simple example shown below) that this works, just as you'd expect.
protected override void OnLoad(EventArgs e) {
throw new Exception("BOOM"); // This will now get caught.
}
So, what I don't understand, is why it was previously impossible for the debugger to handle crossing kernel-mode stack frames, but with this hotfix, they somehow figured it out.
As Hans mentions, compile the application and run the exe without a debugger attached.
For me the problem was changing a Class property name that a BindingSource control was bound to. Running without the IDE I was able to see the error:
Cannot bind to the property or column SendWithoutProofReading on the
DataSource. Parameter name: dataMember
Fixing the BindingSource control to bind to the updated property name resolved the problem:
I'm using WPF and ran into this same problem. I had tried Hans 1-3 suggestions already, but didn't like them because studio wouldn't stop at where the error was (so I couldn't view my variables and see what was the problem).
So I tried Hans' 4th suggestion. I was suprised at how much of my code could be moved to the MainWindow constructor without any issue. Not sure why I got in the habit of putting so much logic in the Load event, but apparently much of it can be done in the ctor.
However, this had the same problem as 1-3. Errors that occur during the ctor for WPF get wrapped into a generic Xaml exception. (an inner exception has the real error, but again I wanted studio to just break at the actual trouble spot).
What ended up working for me was to create a thread, sleep 50ms, dispatch back to main thread and do what I need...
void Window_Loaded(object sender, RoutedEventArgs e)
{
new Thread(() =>
{
Thread.Sleep(50);
CrossThread(() => { OnWindowLoaded(); });
}).Start();
}
void CrossThread(Action a)
{
this.Dispatcher.BeginInvoke(a);
}
void OnWindowLoaded()
{
...do my thing...
This way studio would break right where an uncaught exception occurs.
A simple work-around could be if you can move your init code to another event like as Form_Shown which called later than Form_Load, and use a flag to run startup code at first form shown:
bool firstLoad = true; //flag to detect first form_shown
private void Form1_Load(object sender, EventArgs e)
{
//firstLoad = true;
//dowork(); //not execute initialization code here (postpone it to form_shown)
}
private void Form1_Shown(object sender, EventArgs e)
{
if (firstLoad) //simulate Form-Load
{
firstLoad = false;
dowork();
}
}
void dowork()
{
var f = File.OpenRead(#"D:\NoSuchFile756.123"); //this cause an exception!
}

Better TypeInitializationException (innerException is also null)

Intro
When an user creates a mistake in the configuration of NLog (like invalid XML), We (NLog) throw a NLogConfigurationException. The exception contains the description what is wrong.
But sometimes this NLogConfigurationException is "eaten" by a System.TypeInitializationException if the first call to NLog is from a static field/property.
Example
E.g. if the user has this program:
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
namespace TypeInitializationExceptionTest
{
class Program
{
//this throws a NLogConfigurationException because of bad config. (like invalid XML)
private static Logger logger = LogManager.GetCurrentClassLogger();
static void Main()
{
Console.WriteLine("Press any key");
Console.ReadLine();
}
}
}
and there is a mistake in the config, NLog throws:
throw new NLogConfigurationException("Exception occurred when loading configuration from " + fileName, exception);
But the user will see:
"Copy exception details to the clipboard":
System.TypeInitializationException was unhandled
Message: An unhandled exception of type 'System.TypeInitializationException' occurred in mscorlib.dll
Additional information: The type initializer for 'TypeInitializationExceptionTest.Program' threw an exception.
So the message is gone!
Questions
Why is innerException not visible? (tested in Visual Studio 2013).
Can I send more info to the TypeInitializationException? Like a message? We already sending an innerException.
Can we use another exception or are there properties on Exception so that more info is reported?
Is there another way to give (more) feedback to the user?
Notes
of course we have no influence on the program written by the user.
I'm one of the maintainers of NLog.
Do you like to test it by yourself? Checkout https://github.com/NLog/NLog/tree/TypeInitializationException-tester and start NLog/src/NLog.netfx45.sln
Edit:
please note that I'm the library maintainer, not the user of the library. I cannot change the calling code!
I'll just point out the underlying problem you are dealing with here. You are fighting a bug in the debugger, it has a very simple workaround. Use Tools > Options > Debugging > General > tick the "Use Managed Compatibility Mode" checkbox. Also untick Just My Code for the most informative debugging report:
If Just My Code is ticked then the exception report is less informative but still can be drilled down easily by clicking the "View Detail" link.
The option name is unnecessarily cryptic. What it really does is tell Visual Studio to use an older version of the debugging engine. Anybody that uses VS2013 or VS2015 will have this trouble with the new engine, possibly VS2012. Also the basic reason that this issue did not have be addressed in NLog before.
While this is a very good workaround, it is not exactly easy to discover. Nor would programmers particularly like to use the old engine, shiny new features like return value debugging and E+C for 64-bit code are not supported by the old engine. Whether this is a truly a bug, an oversight or a technical limitation in the new engine is hard to guess. This is excessively ugly so don't hesitate to label it "bug", I strongly recommend you take this to connect.microsoft.com. Everybody will be ahead when it gets fixed, I scratched my head over this at least once that I remember. Drilled it down by using Debug > Windows > Exceptions > ticked CLR Exceptions at the time.
A workaround for this very unfortunate behavior is sure to be ugly. You do have to delay raising the exception until program execution has progressed far enough. I don't know your codebase well enough, but delaying parsing the config until the first logging command ought to take care of it. Or store the exception object and throw it on the first log command, probably easier.
The reason I see is because the Type initialization of Entry point class is failed. Since no type was initialized, so the Type loader has nothing to report about the failed type in TypeInitializationException.
But if you change the Static initializer of logger to other class and then refer that class in Entry method. you'll get the InnerException on TypeInitialization exception.
static class TestClass
{
public static Logger logger = LogManager.GetCurrentClassLogger();
}
class Program
{
static void Main(string[] args)
{
var logger = TestClass.logger;
Console.WriteLine("Press any key");
Console.ReadLine();
}
}
Now you'll get the InnerException because the Entry type was loaded to report the TypeInitializationException.
Hope now you get the idea to keep the Entry point clean and Bootstrap the application from Main() instead of static property of Entry point class.
Update 1
You can also utilize the Lazy<> to avoid the execution of configuration initialization at declaration.
class Program
{
private static Lazy<Logger> logger = new Lazy<Logger>(() => LogManager.GetCurrentClassLogger());
static void Main(string[] args)
{
//this will throw TypeInitialization with InnerException as a NLogConfigurationException because of bad config. (like invalid XML)
logger.Value.Info("Test");
Console.WriteLine("Press any key");
Console.ReadLine();
}
}
Alternatively, try Lazy<> in the LogManager for logger instantiation so that the configuration initialization happens when actually the first log statement occurs.
Update 2
I analyzed the source code of NLog and seems like it's already implemented and It make sense. According to the comments on property "NLog should not throw exception unless specified by property LogManager.ThrowExceptions in LogManager.cs".
Fix - In the LogFactory class the private method GetLogger() has the initialization statement which is causing the exception to happen. If you introduce a try catch with the check of property ThrowExceptions then you can prevent the initialization exception.
if (cacheKey.ConcreteType != null)
{
try
{
newLogger.Initialize(cacheKey.Name, this.GetConfigurationForLogger(cacheKey.Name, this.Configuration), this);
}
catch (Exception ex)
{
if(ThrowExceptions && ex.MustBeRethrown())
throw;
}
}
Also it would be great to have these exceptions/errors stored somewhere so that It can be traced why Logger initialization failed because the they were ignored due to ThrowException.
I said in an earlier comment that I'm unable to reproduce your issue. Then it occurred to me you were only looking for it in the popup exception dialog, which doesn't display a show details link.
So here's how you can get at the InnerException anyway, because it definitely is there, except Visual Studio doesn't report it for some reason (probably because it's in the entry point type as vendettamit figured out).
So, when you run the tester branch, you get the following dialog:
And it doesn't show the View Details link.
The Copy exception detail to the clipboard isn't particularly helpful either:
System.TypeInitializationException was unhandled
Message: An unhandled exception of type 'System.TypeInitializationException' occurred in mscorlib.dll
Additional information: The type initializer for 'TypeInitializationExceptionTest.Program' threw an exception.
Now, dismiss the dialog with the OK button and head towards the Locals debug window. Here's what you'll see:
See? The InnerException definitely is there, and you found a VS quirk :-)
Problem is the static initialization happens when the class is first referenced. In your Program it happens even before the Main() method. So as rule of thumb - avoid any code that can fail in static initialization method. As for your particular problem - use lazy approach instead:
private static Lazy<Logger> logger =
new Lazy<Logger>(() => LogManager.GetCurrentClassLogger());
static void Main() {
logger.Value.Log(...);
}
So the initialization of logger will happen (and possibly fail) when you'll first access the logger - not in some crazy static context.
UPDATE
It is ultimately burden of user of your library to stick to the best practices. So if it were me I'd keep it as it is. There are few options though if you really have to solve it on your end:
1) Don't throw exception - ever - this is valid approach in logging engine, and how log4net works - i.e.
static Logger GetCurrentClassLogger() {
try {
var logger = ...; // current implementation
} catch(Exception e) {
// let the poor guy now something is wrong - provided he is debugging
Debug.WriteLine(e);
// null logger - every single method will do nothing
return new NullLogger();
}
}
2) wrap the lazy approach around the implementation of Logger class (I know your Logger class is much more complex, for sake of this problem let's assume it has just one method Log and it takes string className to construct Logger instance.
class LoggerProxy : Logger {
private Lazy<Logger> m_Logger;
// add all arguments you need to construct the logger instance
public LoggerProxy(string className) {
m_Logger = new Lazy<Logger>(() => return new Logger(className));
}
public void Log(string message) {
m_Logger.Value.Log(message);
}
}
static Logger GetCurrentClassLogger() {
var className = GetClassName();
return new LoggerProxy(className);
}
You'll get rid of this problem (the real initialization will happen while first log method is called and it is backward-compatible approach); only problem is you've added another layer (I don't expect any drastic downgrade of performance, but some logging engines are really into micro-optimization).
The only solution I see now is:
move the static initializes (fields) to a static constructor with a try catch
System.TypeInitializationException is always or almost always occurred from not correct initialisation the static members of a class.
You have to check LogManager.GetCurrentClassLogger() via debugger. I'm sure the error is occurred inside that part of code.
//go into LogManager.GetCurrentClassLogger() method
private static Logger logger = LogManager.GetCurrentClassLogger();
Also i suggest you double check your app.config and make sure you haven't included anything wrong.
System.TypeInitializationException is thrown whenever a static constructor throws an exception, or whenever you attempt to access a class where the static constructor threw an exception.
When .NET loads the type, it must prepare all it's static fields before the first time that you use the type. Sometimes, initialization requires running code. It is when that code fails that you get a System.TypeInitializationException.
According the docs
When a class initializer fails to initialize a type, a TypeInitializationException is created and passed a reference to the exception thrown by the type's class initializer. The InnerException property of TypeInitializationException holds the underlying exception.
TypeInitializationException uses the HRESULT COR_E_TYPEINITIALIZATION, that has the value 0x80131534.
For a list of initial property values for an instance of TypeInitializationException, see the TypeInitializationException constructors.
1) The InnerException is not visible it is very typical for this type of Exception. The version of Visual Studio doesn't matter (ensure that the "Enable the exception assistant" option is checked - Tools> Options>Debugging>General)
2) Usually the TypeInitializationException hides the real exception which can be viewed via InnerException. But the test example below shows how you can populate inner exception info:
public class Test {
static Test() {
throw new Exception("InnerExc of TypeInitializationExc");
}
static void Main(string[] args) {
}
}
But sometimes this NLogConfigurationException is "eaten" by an
System.TypeInitializationException if the first call to NLog is from a
static field/property.
Nothing strange. Someone missed the try catch block somewhere.

Why are exceptions in a static constructor wrapped in TypeInitializationException

The exception from a static constructor is wrapped in a TypeInitializationException. Consider the example below
using System;
namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
try
{
new MyClass();
}
catch (Exception e)
{
Console.WriteLine(e.GetType().ToString());
}
}
public class MyClass
{
static MyClass()
{
throw new Exception();
}
}
}
}
The output of the program is
System.TypeInitializationException
What are the reasons for wrapping the exception in a TypeInitializationException ?
Why is the original exception not returned ?
What are the reasons for wrapping the exception in a TypeInitializationException ?
Exceptions in static constructors are difficult. Basic issue is that the execution context of the exception is very vague. The CLI does not give any specific promise exactly when the constructor runs. Only guarantee is that it will run soon enough, how soon is unspecified.
So a dooms-day scenario without the exception being wrapped is that you get a vague bug report from a user like "I get a NullReferenceException when I click the Save button". You'll study your SaveButton_Click() event handler but no matter how hard you look, you'll never find a good reason for that exception. It occurred in code that's far removed from the event handler method, code that ran at an unpredictable time.
By wrapping it in TypeInitializationException, you'll know where to look.
Why is the original exception not returned ?
It is returned, it will be the InnerException of the TIE. Forgetting to look at it is a standard oversight. If you ever write try/catch code then never make the mistake of only displaying Message property of the exception you caught. The InnerException is important too. Strongly favor displaying the string generated by the exception object's ToString() method. It is gobbledegooky to the user but essential to you. Avoid the gobble with logging or hiding details that can be revealed with "Details" button in the error dialog.
Static constructors are called on initialization, so although it's your static constructor that's failing, it's the type initalizer that's calling that, so that's the exception you get: https://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx

How can I handle the exception which throws on an external dll?

I have developed a project which uses an external dll as FTPServer, I have created the FTP Server on my project like this:
private ClsFTPServer _ClsFTPServer;
_ClsFTPServer = new ClsFTPServer(FTPUserName, FTPPassword, FTPPath);
The Code above creates an instance of FTP server class, the class starts the FTPserver on it's constructor, it works fine independently as a module while the clients send their request correctly, but when an incorrect request comes to FTP server it throws an exception and cause my application to crash.
How can I handle the exception thrown by the external dll to prevent my application from crashing?
I recently answered a similar (ish) question which may prove useful -
Catch completely unexpected error
EDIT. I have to agree with Hans' comment above - might be an idea to find another FTP server.
Just for completeness, here's the appdomain/thread exception setup from - http://msdn.microsoft.com/en-GB/library/system.windows.forms.application.threadexception.aspx
Application.ThreadException += new ThreadExceptionEventHandler (ErrorHandlerForm.Form1_UIThreadException);
// Set the unhandled exception mode to force all Windows Forms errors to go through
// our handler.
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
// Add the event handler for handling non-UI thread exceptions to the event.
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
In case of using external unmanaged\unsafe code, .NET (above .net 4) by default cannot handle Memory Access Violation exceptions that happens inside of dll code.
in order to catch these kind of exceptions, there is three things to do. I did them and it worked for me:
Add these Attributes to the method that exception occurred inside of it :
(the method that calls the method of the unmanaged code.)
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
Add this tag to App.Config file below runtime tag :
<runtime>
<legacyCorruptedStateExceptionsPolicy enabled="true"/>
<!-- other tags -->
</runtime>
Catch these kind of exception by using System.AccessViolationException exception type :
try{
//Method call that cause Memory Access violation Exeption
}
catch (System.AccessViolationException exception)
{
//Handle the exception here
}
What i said is just the cure for these type of exception. for more information about this exception's ego and how this approach works, see System.AccessViolationException
You've probably already tried this, but just in case, have you tried wrapping it in a try catch?
try
{
_ClsFTPServer = new ClsFTPServer(FTPUserName, FTPPassword, FTPPath);
...
}
catch(Exception e)
{
...
}
By putting a try...catch block around every call into the object and its methods.
Something like:
try
{
// use the DLL in some way
}
catch (Exception e)
{
// Handle the exception, maybe display a warning, log an event, etc.)
}
Also note that while running under Visual Studio, if you go to the "Debug" menu and select "Exceptions..." it will allow the debugger to break on ALL exceptions if you start your program under the debugger, and not just unhandled exceptions. Just click the 'Thrown' checkbox next to "Common Language Runtime Exceptions".

How does SetUnhandledExceptionFilter work in .NET WinForms applications?

I am working on a project to enhance our production debugging capabilities. Our goal is to reliably produce a minidump on any unhandled exception, whether the exception is managed or unmanaged, and whether it occurs on a managed or unmanaged thread.
We use the excellent ClrDump library for this currently, but it does not quite provide the exact features we need, and I'd like to understand the mechanisms behind exception filtering, so I set out to try this for myself.
I started out by following this blog article to install an SEH handler myself: http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx. This technique works for console applications, but when I try the same thing from a WinForms application, my filter is not called for any variety of unmanaged exceptions.
What can ClrDump be doing that I'm not doing? ClrDump produces dumps in all cases, so its exception filter must still be called...
Note: I'm aware of ADPlus's capabilities, and we've also considered using the AeDebug registry keys... These are also possibilities, but also have their tradeoffs.
Thanks,
Dave
// Code adapted from <http://blogs.microsoft.co.il/blogs/sasha/archive/2007/12.aspx>
LONG WINAPI MyExceptionFilter(__in struct _EXCEPTION_POINTERS *ExceptionInfo)
{
printf("Native exception filter: %X\n",ExceptionInfo->ExceptionRecord->ExceptionCode);
Beep(1000,1000);
Sleep(500);
Beep(1000,1000);
if(oldFilter_ == NULL)
{
return EXCEPTION_CONTINUE_SEARCH;
}
LONG ret = oldFilter_(ExceptionInfo);
printf("Other handler returned %d\n",ret);
return ret;
}
#pragma managed
namespace SEHInstaller
{
public ref class SEHInstall
{
public:
static void InstallHandler()
{
oldFilter_ = SetUnhandledExceptionFilter(MyExceptionFilter);
printf("Installed handler old=%x\n",oldFilter_);
}
};
}
Windows Forms has a built-in exception handler that does the following by default:
Catches an unhandled managed exception when:
no debugger attached, and
exception occurs during window message processing, and
jitDebugging = false in App.Config.
Shows dialog to user and prevents app termination.
You can disable the first behaviour by setting jitDebugging = true in App.Config. This means that your last chance to stop the app terminating is to catch the unhandled exception by registering for the event Application.ThreadException, e.g. in C#:
Application.ThreadException += new Threading.ThreadExceptionHandler(CatchFormsExceptions);
If you decide not to catch the unhandled exception here, then you will need to check and/or change the registry setting DbgJitDebugLaunchSetting under HKLM\Software.NetFramework. This has one of three values of which I'm aware:
0: shows user dialog asking "debug or terminate".
1: lets exception through for CLR to deal with.
2: launches debugger specified in DbgManagedDebugger registry key.
In Visual Studio, go to Tools>Options>Debugging>JIT to set this key to 0 or 2. But a value of 1 is usually what you want on an end-user's machine. Note that this registry key is acted on before the CLR unhandled exception event that you discuss.
Then you can set the native exception filter that you discussed.
If you want your GUI thread exceptions to work just like your-non GUI ones, so that they get handled the same way, you can do this:
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.ThrowException);
Here's the background:
In a manged GUI app, by default, exceptions that originate in the GUI thread are handled by whatever is assigned to the Application.ThreadException, which you can customize like this:
Application.ThreadException +=
new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Exceptions that originate in the other threads are handled by AppDomain.CurrentDomain.UnhandledException, which you can customize like this:
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(Program.CurrentDomain_UnhandledException);
Assigning to UnHandledException works exactly like calling Win32 SetUnhandledExceptionFilter.
If you goal is to create minidumps and then use them, you'll need to use Debugging Tools for Windows, sos.dll. You'll need to produce minidumps MiniDumpWithFullMemory.
And then, even then, you probably won't have everything you might want. System.Diagnostics.StackTrace to get the call managed call stack.
SetUnhandledExceptionFilter installs a handler that is invoked when a Win32-excpetion reaches the top of a threads callstack without being handled.
In many language runtimes including managed, language exceptions are implemented using Win32 exceptions. But, the managed runtime will have a top level __try __catch(...) block at the top of each thread that will catch any win32 to runtime exceptions and process them without letting them escape to Win32's top level handler.
Knowledge of the specific runtime would be necessary to inject a handler at this level because the exceptions will never be allowed to escape to Win32's TheadProc handler.

Categories

Resources