Globally handle WPF exceptions without a WPF Application object - c#

WPF provides a very convenient way to handle unexpected exceptions: I can just attach a handler to the Application.DispatcherUnhandledException event and all unhandled exceptions go this way:
Application.Current.DispatcherUnhandledException += (sender, e) => {
// Show message, log exception, etc.
};
This works great for WPF application projects. Now, I have a library with WPF windows, which is called from a non-WPF application (it's a legacy VBA app, and the WPF library is made accessible via COM interop).
So, the thing is: I can create, open and show WPF windows (this works fine), but I don't have an Application instance. Application.Current is null. I use the WPF classes, but I operate them outside the WPF application framework.
Currently, the only drawback of this solution is that exceptions in WPF window event handler code are silently swallowed:
void Button_click(sender as object, e as RoutedEventArgs) {
...
// some exception occurs here, but nobody hears her scream
...
}
I don't like that. I'd like to log them and show error messages.
My question: Is there a way to globally catch unhandled exceptions in this scenario or do I have to add a gerneric try-catch-log block to every WPF window event handler code I write?
What I have tried:
Attaching to AppDomain.CurrentDomain.UnhandledException. Doesn't work. Exceptions don't get there.
Reading the relevant parts of MSDN regarding WPF and Win32 interop (Ref 1, Ref 2, Ref 3). Exceptions are not mentioned there.

Attach to the Dispatcher instead:
Dispatcher.CurrentDispatcher.DispatcherUnhandledException += (sender, e) => {
// Show message, log exception, etc.
};
If no dispatcher exists yet, accessing CurrentDispatcher automatically creates a singleton Dispatcher which will also be used by the WPF windows.

Related

How to call WinRT from MAUI code-behind in the right thread?

I am trying to use a GraphicsCapturePicker from the code-behind in a MAUI app and am hitting a COM exception implying I am calling this from the wrong thread. Typically code in WPF/XAML code-behind files are dispatched from the main thread so I am a bit confused about what's going wrong here:
// A regular button event handler in MainPage.xaml.cs
private void OnScreenCaptureClicked(object sender, EventArgs e)
{
var picker = new GraphicsCapturePicker();
GraphicsCaptureItem item = picker.PickSingleItemAsync().GetResults();
}
Throws exception:
"The application called an interface that was marshalled for a different thread"
Exception thrown: 'System.Runtime.InteropServices.COMException' in System.Private.CoreLib.dll
Note: In the above example I am calling the method syncronously as a test to make it easier to catch the exception, the same thing happens when it's wrapped in a task.
This exact code works fine in a regular non-MAUI UWP/C# project.

How to catch exceptions for objects defined in XAML in WPF

Is there a way to catch Exceptions from Objects declared in XAML such as a StoryBoard and keep the application from crashing completely?
In this particular case users will rarely encounter an exception relating to an un-animatable or unaccessible property path. I am working to address these issues but in general the app is critical and I would like to prevent it from simply crashing in these instances.
The app is a UserControl that is Hosted in a windows forms app via ElementHost.
How do you handle these types of exceptions and keep the app running?
Some additional info
I tried using something like:
Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;
as a means of catching the exceptions but Application.Current is always null so I can't use it.
In a nutshell I need to ensure that no matter what happens the app itself continues to run.
Oh the horror when you get xaml related crash errors! :) I don't have the full receipt in my head here right now, and I need more information about your issue, but make sure to hook on to all following error handlers(App.xaml.cs in WPF, check link below for forms).
DispatcherUnhandledException += UnhandledDispatcherException;
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
private void UnhandledDispatcherException(Object sender, DispatcherUnhandledExceptionEventArgs e)
{
// do your stuff here!
e.Handled = true; // Ex is now handled and will not crash your app
}
This one is forms only I think(dont have my devbox here).
Application.ThreadException += UnhandledThreadException
Add your handlers and log/System.Diagnostics.Trace.WriteLine/breakpoint away!
Check this example from MSDN regarding AppDomain. Verify that AppDomain.Current is not null when starting as well.
Snippet:
public class Example
{
[SecurityPermission(SecurityAction.Demand,Flags=SecurityPermissionFlag.ControlAppDomain)]
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);
...
}
}
You may also do this after your InitializeComponents, if Application.Current is null.
if (System.Windows.Application.Current == null)
new System.Windows.Application();
And ofc check your debug output! :)
Hope it helps,
Cheers
Stian

Exception Handling in SCSF

I have a SCSF application i am trying to handle most of the exceptions using
Application.ThreadException += new ThreadExceptionEventHandler(new ThreadExceptionHandler().ApplicationThreadException);
The event handler :-
public class ThreadExceptionHandler
{
public void ApplicationThreadException(object sender, ThreadExceptionEventArgs e)
{
MessageBox.Show(e.Exception.Message, "An exception occurred:", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Works fine . I can catch all the application exceptions in this block.
But the problem is after handling the exception the code again goes and executes the same exception generating code again. This happens till the time I get a windows message windows to send the error info to microsoft.
Could any one please help in telling me where I might be going wrong.
Thanks in Advance
Vikram
Note :- Currently i am throwing
New Exception("Test Exception"); from a button event. I am doing this to provide event handling in my application.
You have to set
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
See this MSDN page for example code
But note that this kind of catch-all exception handling is not a good replacement for exception handling inside your logic. It is a good backup, but the best thing to do in a global handler is to log the information and exit. Your app could be in an unsafe/undefined state.
After some banging my head against the code I found that the problem was due to the fact that my SCSF solution had a winforms Shell and on that shell there were WPF usercontrols.
When the exception where generated on these WPF usercontrol (mostly the case) they are not caught by
Application.ThreadException coz Application class for WPF is different than that for Winforms.
In WPF application one need to handle Application.DispacherUnhandledException event.
Just my little finding ...
you would be surprised by just handling the Application.DispatcherUnhandledException. I have worked with SCSF which had WPF user controls. Read through this post . http://social.msdn.microsoft.com/forums/en-US/wpf/thread/c57cac13-f960-49a1-94b5-a3fd316ac4bc/ i would recommend handling AppDomain.UnhandledException too.

Any way to remove notify icon in event of a crash?

Is there any way to automatically remove a NotifyIcon in the event of a crash? (I know you can mouse-over to remove it)
I'm running windows xp.
For C#, try handling the UnhandledException event from the AppDomain, so, in your Main() method add:
AppDomain.CurrentDomain.UnhandledException +=
new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
And then add the following method:
static void CurrentDomain_UnhandledException(object sender,
UnhandledExceptionEventArgs e)
{
// .... Remove Notification icon here
}
Unfortunately the answer is no - Rob's answer actually detects the crash and attempts to remove the icon in the crash handler which has its own set of issues (for instance it assumes that enough of the CLR is running at the time of the crash to execute the unhandled exception, that's not always the case).
The problem here is that the shell (which runs the Shell_NotifyIcon code) gets out of sync with your application.

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