Почему Environment.Exit() не завершает программу больше?

Это то, что я обнаружил всего несколько дней назад, я получил подтверждение, что это не ограничивается моей машиной из этого вопроса.

Самый простой способ его воспроизвести - запустить приложение Windows Forms, добавить кнопку и написать этот код:

    private void button1_Click(object sender, EventArgs e) {
        MessageBox.Show("yada");
        Environment.Exit(1);         // Kaboom!
    }

Программа выходит из строя после выполнения оператора Exit(). В Windows Forms вы получите "Ошибка создания дескриптора окна".

Включение неуправляемой отладки делает несколько ясными, что происходит. Выполняется COM- модальный цикл и позволяет передать сообщение WM_PAINT. Это смертельно опасная форма.

Единственные факты, которые я собрал до сих пор:

  • Это не просто работает с отладчиком. Это тоже не удается. Скорее плохо также, диалог сбоя WER появляется дважды.
  • Это не имеет ничего общего с битностью процесса. Уровень wow64 довольно печально известен, но сборка AnyCPU сбрасывается одинаково.
  • Это не имеет ничего общего с версией.NET, 4.5 и 3.5 сбой аналогичным образом.
  • Код выхода не имеет значения.
  • Вызов Thread.Sleep() перед вызовом Exit() не исправляет его.
  • Это происходит в 64-разрядной версии Windows 8, и Windows 7, похоже, не затрагивается одинаково.
  • Это должно быть относительно новое поведение, я этого раньше не видел. Я не вижу соответствующих обновлений, предоставляемых через Центр обновления Windows, хотя история обновлений на моей машине не является точной.
  • Это сильно нарушает поведение. Вы должны написать такой код в обработчике событий для AppDomain.UnhandledException, и он сбой аналогичным образом.

Меня особенно интересует то, что вы могли бы сделать, чтобы избежать этого краха. В частности, сценарий AppDomain.UnhandledException обрушивает меня; существует много способов прекратить работу.NET-программы. Обратите внимание, что вызов Application.Exit() или Form.Close() недействителен в обработчике событий для UnhandledException, поэтому они не обходные пути.


ОБНОВЛЕНИЕ: Мехрдад отметил, что поток финализатора может быть частью проблемы. Я думаю, что я вижу это, и я также вижу некоторые доказательства для 2-секундного таймаута, которые CLR дает финализатору, чтобы закончить выполнение.

Финализатор находится внутри NativeWindow.ForceExitMessageLoop(). Там есть функция IsWindow() Win32, которая примерно соответствует расположению кода, смещение 0x3c при просмотре машинного кода в 32-битном режиме. Кажется, что IsWindow() является взаимоблокировкой. Я не могу получить хорошую трассировку стека для внутренних компонентов, однако отладчик считает, что только что возвращенный вызов P/Invoke. Это трудно объяснить. Если вы можете получить лучшую трассировку стека, я бы с удовольствием ее увидел. Мой:

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
[email protected]@12()  + 0xe bytes
[email protected]()  + 0x27 bytes
[email protected]()  + 0x1b bytes

Ничто не выше вызова ForceExitMessageLoop, включен неуправляемый отладчик.

Ответ 1

Я связался с Microsoft по этой проблеме и, похоже, окупился. По крайней мере, я бы хотел подумать, что это было:). Хотя у меня не было подтверждения разрешения от них, группе Windows трудно связаться напрямую, и мне пришлось использовать посредника.

Обновление, поставленное через Центр обновления Windows, решило проблему. Заметная 2-секундная задержка перед сбоем больше не присутствует, что настоятельно указывает на то, что тупик IsWindow() был решен. И программа отключается чисто и надежно. Обновление установило исправления для Защитника Windows, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll и wintrust.dll

Uxtheme.dll - нечетная утка. Он реализует API-интерфейс визуальных стилей и используется этой тестовой программой. Я не могу быть уверен, но мои деньги находятся на этом как источник проблемы. Копия в C:\WINDOWS\system32 имеет номер версии 6.2.9200.16660, созданный 14 августа 2013 г. на моей машине.

Дело закрыто.

Ответ 2

Я не знаю, почему это не работает "больше", но я думаю, что Environment.Exit выполняет ожидающие финализаторы. Environment.FailFast не работает.

Возможно, что (по какой-то причудливой причине) у вас есть странные ожидающие финализаторы, которые должны запускаться позже, в результате чего это произойдет.

Ответ 3

Это не объясняет, почему это происходит, но я бы не назвал Environment.Exit в обработчике событий кнопки, как ваш образец, - вместо этого закройте основную форму, как предложено в ответить.

Что касается обработчика AppDomain.UnhandledException, возможно, вы могли бы просто установить Environment.ExitCode вместо вызова Environment.Exit.

Я не уверен, чего вы пытаетесь достичь здесь. Почему вы хотите вернуть код выхода из приложения Windows Forms? Обычно коды завершения используются консольными приложениями.

Я особенно заинтересован в том, что вы могли бы сделать, чтобы избежать этого краха Вызов Environment.Exit() необходим для предотвращения отображения диалогового окна WER.

У вас есть попытка/улов в основном методе? Для приложений Windows Forms у меня всегда есть try/catch вокруг цикла сообщений, а также необработанные обработчики исключений.

Ответ 4

Я нашел ту же проблему в нашем приложении, мы решили ее со следующей конструкцией:

Environment.ExitCode=1;
Application.Exit();