Почему 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, поэтому они не являются обходными путями.


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

Финализатор находится внутри NativeWindow.ForceExitMessageLoop(). Там есть функция Win32 IsWindow(), которая примерно соответствует расположению кода, смещение 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]
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

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

4 ответа

Решение

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

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

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

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

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

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

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

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

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

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

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

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

Environment.ExitCode=1;
Application.Exit();
Другие вопросы по тегам