Необработанные исключения из управляемого пользовательского элемента управления C#, используемого в диалоговом окне MFC

Наше основное приложение построено в MFC C++, но мы пытаемся написать новый код в .NET и создали пользовательский элемент управления в .NET, который будет использоваться в существующем диалоговом окне MFC.

Однако когда неожиданное/необработанное исключение выдается из пользовательского элемента управления, это приводит к сбою приложения MFC (недопустимый стиль операции) без возможности восстановления.

я добавил

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

В конструктор пользовательского элемента управления .NET, но он, похоже, ничего не улавливает.

Есть ли способ добавить событие в MFC для их обработки?

Быстрый гугл ничего полезного не дал.

Спасибо.


Изменить: до сих пор не удалось решить эту проблему так, как я хотел бы, похоже, что лучший способ сделать это, попытаться перехватить весь код .NET, поэтому исключения не всплывают. .


person PostMan    schedule 27.07.2009    source источник
comment
Проверьте мое редактирование. Я использую его в каждом обработчике событий; так ты можешь.   -  person John Saunders    schedule 27.07.2009
comment
Вам нужно только попробовать/отловить самый внешний код .NET — обработчики событий и общедоступные точки входа.   -  person John Saunders    schedule 01.08.2009
comment
О да, это то, что я должен был сделать, но он охватывает весь код .NET, прямо или косвенно.   -  person PostMan    schedule 03.08.2009


Ответы (4)


Я задал этот же вопрос некоторое время назад: Последнее управляемое исключение обработчик в смешанном собственном/управляемом исполняемом файле?

Я обнаружил, что события управляемого необработанного исключения срабатывают ТОЛЬКО при работе в управляемом потоке. В управляемом WndProc происходит волшебство.

У вас есть несколько вариантов: вы можете разместить низкоуровневое переопределение в CWinApp и перехватить Exception^. Это может иметь непреднамеренные побочные эффекты. Или вы можете использовать структурированную обработку исключений (SEH), которая даст вам возможность взломать /все/необработанные исключения. Это не легкий путь.

person Aidan Ryan    schedule 27.07.2009

Я думаю, вы хотите иметь обработчик необработанных исключений на стороне MFC:

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

[то же самое для Application.ThreadException]

Посмотрите на этот похожий вопрос на форумах MSDN: Необработанное исключение в приложении смешанного режима

person Judah Gabriel Himango    schedule 27.07.2009
comment
Код в предоставленной ссылке на самом деле не работает, и приведенный пример, к сожалению, не работает. Компилируется на 100%, но результат тот же - person PostMan; 27.07.2009
comment
Действительно, это не работает. Кроме того, почему контекст, в котором выполняется регистрация события, может влиять на регистрацию? В теме, на которую вы ссылаетесь, принят неверный ответ, более поздние ответы подтверждают проблему с Аскером. - person Aidan Ryan; 27.07.2009

Конечно, лучше было бы либо обработать исключение в коде C#, либо выяснить, что его вызывает, и исправить его, чтобы исключение никогда не вызывалось. Что этому мешает?

В каждом обработчике событий пользовательского элемента управления поместите блок try/catch:

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
    }
}

Вот что я использую:

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;
        }
    }
}

Я называю это так:

private void _copyButton_Click(object sender, EventArgs e)
{
    UI.PerformUIAction(
        this, () =>
                  {
                  // Your code here
                  });
}
person John Saunders    schedule 27.07.2009
comment
Суть исключений в том, что мы не знаем, когда они появятся и почему. Так что это невозможно. А также в пользовательском элементе управления довольно много событий и методов. Я закодировал возможные исключения, но я хочу поймать другие - person PostMan; 27.07.2009
comment
Кажется, это довольно много работы, и мне действительно нужно решение, которое не требует от меня добавления дополнительного кода каждый раз, когда мне нужно поймать исключение (кроме тех, которые я могу ожидать) - person PostMan; 28.07.2009
comment
Как тебе нравится. Но обратите внимание, что вы добавляете три строки кода после open { и одну строку перед end }. Вы можете сделать это, используя поиск и замену, если вы не возражаете против некоторых простых регулярных выражений. Кроме того, вы могли не заметить; вы можете получить доступ к sender и e внутри блока вашего кода здесь. Код, который вы упаковываете, не меняется. - person John Saunders; 28.07.2009
comment
Не поймите меня неправильно, это отличное решение, но, к сожалению, не подходит для моей проблемы. Если бы я мог опубликовать больше кода, я бы это сделал, но из-за того, что это связано с работой и всем остальным. - person PostMan; 28.07.2009
comment
Без проблем. Я не обижаюсь. :-) Мне было бы любопытно узнать, в какой ситуации этот шаблон не подходит, просто потому, что он подходил для стольких ситуаций на протяжении многих лет. Впервые я использовал его с .NET 1.1, где для делегатов приходилось использовать явные имена методов. Это было ужасно! Лямбды решают все проблемы, которые у меня были с 2003 года! - person John Saunders; 28.07.2009

Я добавил обработчик необработанных исключений в конструктор пользовательского элемента управления .NET.

Я не думаю, что это сработает; Я считаю, что обработчик исключений должен быть настроен до вызова Application.Run. Есть ли в вашем приложении вызовы Application.Run?

Как насчет чего-то подобного на стороне MFC, прежде чем инициализировать какие-либо элементы управления .NET:

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

Посмотрите, вызывается ли обработчик ThreadException.

person Judah Gabriel Himango    schedule 27.07.2009
comment
Интересная идея, поделитесь результатом, если попробуете. - person Aidan Ryan; 27.07.2009
comment
Должен ли я вызывать исключение потока как событие .NET или код MFC? Извините, новичок во всем этом программировании .... - person PostMan; 28.07.2009
comment
Имейте это на стороне MFC. Вам потребуется скомпилировать код C++ как C++/CLI (управляемый код C++). - person Judah Gabriel Himango; 28.07.2009