views:

563

answers:

4

Our core application is built in MFC C++, but we are trying to write new code in .NET, and have created a User Control in .NET, which will be used on an existing MFC Dialog.

However, when a unexpected/unhandled exception is thrown from the User Control, it causes the MFC app to crash (illegal op style), with no ability to recover.

I've added

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(currentDomain_UnhandledException);
Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

To the Constructor of the .NET user control, but it doesn't seem to catch anything.

Is there any way to add an event in MFC to handle these?

Quick google didn't return anything useful.

Thanks.


Edit: Still haven't been able to resolve this the way I'd like, looks like the best way to do it, is try and catch around all the .NET code, so no exceptions bubble up.

A: 

I think you want to have the unhandled exception handler in the MFC side of things:

AppDomain::CurrentDomain->UnhandledException += gcnew UnhandledExceptionEventHandler(&CurrentDomain_UnhandledException);

[same for Application.ThreadException]

Have a look at this similar question on the MSDN forums: Unhandled Exception in Mixed Mode application

Judah Himango
The code in the link provided doesn't actually work, nor does the example provided sadly. Compiles 100%, but still the same result
PostMan
Indeed, this does not work. Also, why would the context the event registration runs under have any effect on the registration?The thread you linked has a bad answer accepted, the later responses confirm this Asker's issue.
Aidan Ryan
A: 

Of course, the better idea would be either to handle the exception in the C# code, or else to find out what's causing it, and fix it so that the exception is never thrown. What's preventing that?

In every event handler of the user control, place a try/catch block:

private void btnOk_Click(object sender, EventArgs e) {
    try {
        // real code here
    }
    catch (Exception ex) {
        LogException(ex);
        // do whatever you must in order to shut down the control, maybe just
    }
}

Here's what I use:

public static class UI
{
    public static void PerformUIAction(Control form, Action action)
    {
        PerformUIAction(form, action, (string) null);
    }

    public static void PerformUIAction(
        Control form, Action action, string message)
    {
        PerformUIAction(form, action, () => message);
    }

    public static void PerformUIAction(
        Control form, Action action, Func<string> messageHandler)
    {
        var saveCursor = form.Cursor;
        form.Cursor = Cursors.WaitCursor;
        try
        {
            action();
        }
        catch (Exception ex)
        {
            MessageBox.Show(
                messageHandler() ?? ex.Message, "Exception!",
                MessageBoxButtons.OK, MessageBoxIcon.Error,
                MessageBoxDefaultButton.Button1,
                MessageBoxOptions.DefaultDesktopOnly);
            Debug.WriteLine(ex.ToString(), "Exception");
            throw;
        }
        finally
        {
            form.Cursor = saveCursor;
        }
    }
}

I call it like this:

private void _copyButton_Click(object sender, EventArgs e)
{
    UI.PerformUIAction(
        this, () =>
                  {
                  // Your code here
                  });
}
John Saunders
The thing with exceptions is we don't know when they are coming, or why. So this isn't possible.And also the User Control has quite a few events and methods.I've coded for the exceptions that are possible, but it's the other ones I want to catch
PostMan
Seems to be quite a bit of work, and really need a solution that doesn't require me adding in extra code every where I need to catch an exception (Other than the ones I can expect)
PostMan
As you like. But notice you're adding three lines of code after the open "{" and one line before the end "}". You can do that using search and replace, if you don't mind some simple regular expressions. Also, you might not have noticed; you can access "sender" and "e" inside the "your code here" block. The code you're wrapping does not change.
John Saunders
Don't get me wrong, its a great solution, but doesn't fit my problem sadly. If I could post more code I would, but due to it being work related and all.
PostMan
No problem. I'm not offended. :-) I'd be curious to know what situation this pattern didn't fit, simply because it has fit so many situations over the years. I first used it with .NET 1.1, where you had to use explicit method names for delegates. _That_ was ugly! Lambdas solve all the problems I had since 2003!
John Saunders
A: 

I added the unhandled exception handler to the constructor of the .NET user control

I don't think that will work; I believe the exception handler has to be setup before a call to Application.Run. Do you have any Application.Run calls in your app?

How about something like this on the MFC side of things before you initialize any .NET controls:

Application.SetUnhandledExceptionMode(System.Windows.Forms.UnhandledExceptionMode.CatchException);
Application.ThreadException += ...;

See if the ThreadException handler is called.

Judah Himango
Interesting idea, please share the result if you give it a try.
Aidan Ryan
Should I have the thread exception call a .NET event, or MFC code? Sorry new to this whole programming thing....
PostMan
Have this on the MFC side of things. You'll need to have your C++ code compiled as C++/CLI (managed C++ code).
Judah Himango
+1  A: 

I asked this same question a while ago: http://stackoverflow.com/questions/8704/final-managed-exception-handler-in-a-mixed-native-managed-executable

What I have found is that the managed unhandled exception events ONLY fire when running in a managed thread. The managed WndProc is where the magic happens.

You have a few options: you could place a low-level override in CWinApp and catch Exception^. This could have unintended side-effects. Or, you could go with Structured Exception Handling (SEH) which will give you a hack at /all/ unhandled exceptions. This is not an easy road.

Aidan Ryan