Необработанное исключение NullReference при закрытии приложения WPF

Я получаю необработанное исключение в моем приложении, когда я закрываю последнее окно:

Необработанное исключение типа 'System.NullReferenceException' произошел в PresentationFramework.dll

Дополнительная информация: Ссылка на объект не установлена ​​в экземпляр объект.

Это происходит только в том случае, если в течение жизненного цикла приложения я открываю дочернее окно через определенный процесс, который я настроил. Окно существует в другой сборке, которая динамически загружается во время выполнения с помощью MEF, а затем создается экземпляр с помощью Castle. Если я затем вызываю определенный метод, он создает новый поток STA и открывает диалоговое окно WPF.

Некоторые оговорки:

  • Это происходит только на некоторых компьютерах/средах (я не могу распознать шаблон, хотя)
  • У меня есть обработчик UnhandledException для диспетчера для приложения, которое ловит все необработанные исключения. Это не связано с этим.

Стек вызова:

PresentationFramework.dll!MS.Internal.Controls.ConnectionPointCookie.Disconnect()
PresentationFramework.dll!MS.Internal.Controls.ConnectionPointCookie.Finalize()

Кто-нибудь видел это раньше, или кто-нибудь знает, как отладить это? Странно, что нет стека вызовов, и это происходит правильно, когда программа выходит.

Ответ 1

В вашем вопросе нет подробностей, и трассировка стека коротка, но дает много подсказок в отношении основной проблемы. Некоторые видимые факты:

  • исключение возникает в потоке финализатора, причина, по которой трассировка стека настолько коротка. Необработанное исключение в финализаторе является фатальным, они всегда будут прерывать программу. Причина, по которой попытка использования try/catch в вашем коде не имела никакого эффекта.
  • cookie-точка соединения - это термин COM, вы получаете его, когда подписываетесь на COM-событие. Этот файл cookie должен использоваться снова, когда вы отмените подписку на событие, которое происходит в финализаторе. В WPF используется только один класс - элемент управления WebBrowser. Класс WPF представляет собой оболочку обозревателя Internet Explorer, COM-компонента.
  • исключение, в то время как оно имеет управляемое имя исключения, не вызвано управляемым кодом. Финализатор уже проверяет наличие нулевых ссылок, это Internet Explorer, который бросает неуправляемое AccessViolationException под капотом. Они обрабатываются точно так же с помощью CLR, поскольку у них есть та же самая причина, финализатор не делает ничего другого, чтобы сделать различие более ясным. Неуправляемый код так же уязвим, как и управляемый код, для нулевых указателей. Более того, куча коррупции является очень распространенной причиной.
  • финализатор уже ловит все исключения, NRE - это критическое исключение, поэтому он возвращает его, что конец вашей программы.

Использование WebBrowser - это ответственность, браузеры в целом скорее подвержены риску. Это усиливается, когда вы используете элемент управления в своем приложении, он запускается в процессе и не имеет вида защиты от сбоев, который сам использует Internet Explorer. Так что все, что пойдет не так в браузере, напрямую повлияет на стабильность вашего приложения, часто с очень сложной задачей диагностики причины сбоя, поскольку это неуправляемый код, который бомбит.

И такие сбои повторяются очень плохо, основная причина, по которой вам не удается воспроизвести ее самостоятельно. Наиболее распространенными нарушителями в браузерах являются надстройки, элементы управления ActiveX (например, Flash) и антивирусные программы. У вас возникнут дополнительные проблемы, если вы не сможете контролировать типы веб-сайтов, которые находятся в режиме навигации, есть много, которые преднамеренно исследуют браузер для уязвимостей.

Существует одна конкретная контрмера, которую вы можете использовать, вызов метода Dispose(), когда вы больше не используете его. Обычно в обработчике событий закрытия окна. Это немедленно отменит регистрацию COM-события и вызовет сбой, теперь вы можете его поймать. Обязательно решите закрыть свою программу, когда это произойдет, у вас есть мертвый труп в вашем процессе, который превратится в зомби, когда вы попытаетесь его оживить.

Ответ 2

У меня была одна и та же проблема в одном из моих приложений, и я не нашел реальной проблемы. Но я нашел обходное решение для этого приложения. В событии закрытия основного окна я реализовал цикл, который раньше закрывал все остальные окна. Тогда это сработало. Возможно, это может сработать и для вас. Если вы найдете причину, это будет еще лучше.