[C#] 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는 같은 방식으로 충돌하지 않습니다.
  • 종료 코드는 중요하지 않습니다.
  • Exit ()를 호출하기 전에 Thread.Sleep ()를 호출해도 문제가 해결되지 않습니다.
  • 이는 64 비트 버전의 Windows 8에서 발생하며 Windows 7은 동일한 방식으로 영향을받지 않는 것 같습니다.
  • 이것은 비교적 새로운 행동이어야합니다. 이전에 본 적이 없었습니다. 내 컴퓨터에서 업데이트 기록이 더 이상 정확하지 않지만 Windows Update를 통해 제공되는 관련 업데이트 는 없습니다.
  • 이것은 엄청나게 파괴적인 행동입니다. AppDomain.UnhandledException의 이벤트 처리기에서 이와 같은 코드를 작성하면 같은 방식으로 충돌합니다.

이 충돌을 피하기 위해 할 수있는 일에 특히 관심이 있습니다. 특히 AppDomain.UnhandledException 시나리오가 저를 방해합니다. .NET 프로그램을 종료하는 방법은 많지 않습니다. UnhandledException에 대한 이벤트 처리기에서는 Application.Exit () 또는 Form.Close () 호출이 유효하지 않으므로 해결 방법이 아닙니다.


업데이트 : Mehrdad는 finalizer 스레드가 문제의 일부일 수 있다고 지적했습니다. 나는 이것을보고 있다고 생각하고 CLR이 finalizer 스레드가 실행을 끝내게한다는 2 초 타임 아웃에 대한 증거를보고있다.

종료자는 NativeWindow.ForceExitMessageLoop () 안에 있습니다. 32 비트 모드에서 기계어 코드를 볼 때 코드 위치와 대략 0x3c 오프셋 인 IsWindow () Win32 함수가 있습니다. 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 호출 이상은 없습니다.



답변

나는이 문제에 대해 Microsoft에 연락했고 그 결과는 대가를 치렀습니다. 적어도 나는 그것이했다고 생각하고 싶다 :). 나는 그들로부터 해상도의 확인을 얻지 못했지만 Windows 그룹은 직접 연락하기가 어려우며 중개자를 사용해야했습니다.

Windows Update를 통해 제공되는 업데이트로 문제가 해결되었습니다. 충돌 전 2 초의 현저한 지연이 더 이상 존재하지 않으므로 IsWindow () 교착 상태가 해결되었음을 나타냅니다. 그리고 프로그램은 깨끗하고 안정적으로 종료됩니다. 이 업데이트는 Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll 및 wintrust.dll 용 패치를 설치했습니다.

Uxtheme.dll은 홀수입니다. 비주얼 스타일 테마 API를 구현하며이 테스트 프로그램에서 사용됩니다. 확신 할 수는 없지만 문제의 원인으로 돈이 있습니다. C : \ WINDOWS \ system32의 사본은 내 컴퓨터에서 2013 년 8 월 14 일에 작성된 버전 번호 6.2.9200.16660을 갖습니다.

경우 폐쇄.


답변

“더 이상” 작동하지 않는지 모르겠지만 Environment.Exit보류중인 종료자를 실행 한다고 생각 합니다. Environment.FailFast하지 않습니다.

(기괴한 이유로) 이후에 실행되어야하는 이상한 보류중인 종료자가있을 수 있습니다.


답변

이것은 왜 그런 일이 일어나고 있는지 설명하지 않지만 Environment.Exit샘플과 같은 버튼 이벤트 핸들러를 호출하지 않고 대신 rene ‘s answer 에서 제안 된 기본 양식을 닫으십시오 .

에 관해서는 AppDomain.UnhandledException핸들러, 어쩌면 당신은 설정할 수 Environment.ExitCode호출보다는 Environment.Exit.

나는 당신이 여기서 무엇을 성취하려고하는지 잘 모르겠습니다. Windows Forms 응용 프로그램에서 종료 코드를 반환하려는 이유는 무엇입니까? 일반적으로 종료 코드는 콘솔 응용 프로그램에서 사용됩니다.

이 충돌을 피하기 위해 할 수있는 일에 특히 관심이 있습니다. WER 대화 상자가 표시되지 않도록 Calling Environment.Exit ()가 필요합니다.

Main 메소드에 try / catch가 있습니까? Windows Forms 응용 프로그램의 경우 항상 메시지 루프와 처리되지 않은 예외 처리기 주위에 try / catch가 있습니다.


답변

앱에서 동일한 문제를 발견했으며 다음 구문으로 문제를 해결했습니다.

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


답변