To jest coś, co odkryłem zaledwie kilka dni temu, otrzymałem potwierdzenie, że nie ogranicza się to tylko do mojej maszyny z tego pytania .
Najłatwiejszym sposobem odtworzenia tego jest uruchomienie aplikacji Windows Forms, dodanie przycisku i napisanie tego kodu:
private void button1_Click(object sender, EventArgs e) {
MessageBox.Show("yada");
Environment.Exit(1); // Kaboom!
}
Program kończy się niepowodzeniem po wykonaniu instrukcji Exit (). W Windows Forms pojawia się komunikat „Błąd podczas tworzenia uchwytu okna”.
Włączenie niezarządzanego debugowania sprawia, że jest nieco jasne, co się dzieje. COM pętla modalna jest wykonywany i pozwala na wiadomość WM_PAINT mają być dostarczone. To śmiertelne w przypadku wyrzuconej postaci.
Jedyne fakty, które do tej pory zebrałem, to:
- Nie ogranicza się tylko do uruchomienia z debugerem. To również się nie powiedzie bez jednego. Raczej kiepsko, okno dialogowe awarii WER pojawia się dwukrotnie .
- Nie ma to nic wspólnego z drobiazgowością procesu. Warstwa wow64 jest dość znana, ale kompilacja AnyCPU ulega awarii w ten sam sposób.
- Nie ma to nic wspólnego z tą samą awarią wersji .NET, 4.5 i 3.5.
- Kod wyjścia nie ma znaczenia.
- Wywołanie Thread.Sleep () przed wywołaniem Exit () nie naprawia tego.
- Dzieje się tak w 64-bitowej wersji systemu Windows 8 i wydaje się, że nie ma to takiego samego wpływu na system Windows 7.
- To powinno być stosunkowo nowe zachowanie, nie widziałem tego wcześniej. Nie widzę odpowiednich aktualizacji dostarczanych za pośrednictwem usługi Windows Update , chociaż historia aktualizacji nie jest już dokładna na moim komputerze.
- To jest rażąco łamiące zachowanie. Możesz napisać taki kod w procedurze obsługi zdarzeń dla AppDomain.UnhandledException i ulega awarii w ten sam sposób.
Jestem szczególnie zainteresowany tym, co możesz zrobić, aby uniknąć tej awarii. Szczególnie scenariusz AppDomain.UnhandledException mnie przytłacza; nie ma wielu sposobów na zakończenie programu .NET. Należy pamiętać, że wywołanie Application.Exit () lub Form.Close () nie jest poprawne w procedurze obsługi zdarzeń dla UnhandledException, więc nie są one obejściem.
UPDATE: Mehrdad wskazał, że wątek finalizatora może być częścią problemu. Myślę, że widzę to i widzę również dowody na 2-sekundowy limit czasu, że CLR daje wątek finalizatora do zakończenia wykonywania.
Finalizator znajduje się w NativeWindow.ForceExitMessageLoop (). Jest tam funkcja IsWindow () Win32, która z grubsza odpowiada lokalizacji kodu, przesunięcie 0x3c podczas patrzenia na kod maszynowy w trybie 32-bitowym. Wygląda na to, że IsWindow () jest zakleszczona. Nie mogę uzyskać dobrego śladu stosu dla elementów wewnętrznych, jednak debuger uważa, że wywołanie P / Invoke właśnie zostało zwrócone. Trudno to wyjaśnić. Jeśli możesz uzyskać lepszy ślad stosu, chciałbym to zobaczyć. Kopalnia:
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
Nic powyżej wywołania ForceExitMessageLoop, włączony niezarządzany debugger.
This happens on the 64-bit version of Windows 8
Hans tak powiedział!Exit(0)
trochę temu z jakimś 64-bitowym Win7, zmianaExitCode
nie pomogła teraz, używającProcess.GetCurrentProcess().Kill()
bez problemu, działaOdpowiedzi:
Skontaktowałem się z firmą Microsoft w sprawie tego problemu i wydawało się, że to się opłaciło. Przynajmniej tak mi się wydaje :). Chociaż nie otrzymałem od nich potwierdzenia rozwiązania, z grupą Windows trudno się bezpośrednio skontaktować i musiałem skorzystać z pośrednika.
Aktualizacja dostarczona za pośrednictwem witryny Windows Update rozwiązała problem. Zauważalne 2-sekundowe opóźnienie przed awarią już nie występuje, co zdecydowanie sugeruje, że zakleszczenie IsWindow () zostało rozwiązane. Program zamyka się czysto i niezawodnie. Aktualizacja zainstalowała poprawki dla Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll i wintrust.dll
Uxtheme.dll jest dziwnym rozwiązaniem. Implementuje interfejs API do tworzenia motywów wizualnych i jest używany przez ten program testowy. Nie jestem pewien, ale to właśnie na nim biorę moje pieniądze, jako źródło problemu. Kopia w C: \ WINDOWS \ system32 ma numer wersji 6.2.9200.16660, utworzoną 14 sierpnia 2013 na moim komputerze.
Sprawa zamknięta.
źródło
Nie wiem, dlaczego to już „nie działa ” , ale myślę, że
Environment.Exit
wykonuje oczekujące finalizatory.Environment.FailFast
nie.Możliwe, że (z jakiegoś dziwnego powodu) masz dziwne oczekujące finalizatory, które muszą działać później, powodując to.
źródło
NativeWindow.ForceExitMessageLoop
utknęło w kodzie zarządzanym lub niezarządzanym? Czy w ogóle utknął, czy jest zajęty czekaniem lub czekaniem na wiadomość lub coś innego?To nie wyjaśnia, dlaczego tak się dzieje, ale nie wywołałbym
Environment.Exit
programu obsługi zdarzeń przycisku, takiego jak twoja próbka - zamiast tego zamknij główny formularz, jak zasugerowano w odpowiedzi rene .A jeśli chodzi o program
AppDomain.UnhandledException
obsługi, może mógłbyś po prostu ustawićEnvironment.ExitCode
zamiast dzwonićEnvironment.Exit
.Nie jestem pewien, co próbujesz tutaj osiągnąć. Dlaczego chcesz zwrócić kod zakończenia z aplikacji Windows Forms? Kody zakończenia są zwykle używane przez aplikacje konsolowe.
Czy masz próbę / złapanie w metodzie głównej? W przypadku aplikacji Windows Forms zawsze mam try / catch wokół pętli komunikatów, a także nieobsługiwane programy obsługi wyjątków.
źródło
Application.Exit
zamiast tego powinieneś zadzwonićEnvironment.Exit
.Znalazłem ten sam problem w naszej aplikacji, rozwiązaliśmy go za pomocą następującej konstrukcji:
źródło