Environment.Exit () neden programı artık sonlandırmıyor?


134

Bu sadece birkaç gün önce keşfettiğim bir şey, bu sorudan sadece makinemle sınırlı olmadığını doğruladım .

Yeniden oluşturmanın en kolay yolu bir Windows Forms uygulaması başlatmak, bir düğme eklemek ve şu kodu yazmaktır:

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

Exit () ifadesi çalıştırıldıktan sonra program başarısız olur . Windows Forms'da "Pencere tutamacı oluşturulurken hata oluştu" iletisi görüntülenir.

Yönetilmeyen hata ayıklamayı etkinleştirmek, neler olup bittiğini biraz netleştirir. COM kalıcı döngü yürütme ve WM_PAINT mesajı teslim edilecek olanak tanır. Bertaraf edilmiş bir formda ölümcüldür.

Şimdiye kadar topladığım tek gerçekler:

  • Sadece hata ayıklayıcı ile çalışmakla sınırlı değildir. Bu da olmadan başarısız olur. Aksine kötü yanı, WER iletişim gösterileri yukarı çökmesine iki kez .
  • Sürecin bitliği ile ilgisi yoktur. Wow64 katmanı oldukça kötü şöhretlidir, ancak AnyCPU derlemesi aynı şekilde çöker.
  • .NET sürümü ile ilgisi yoktur, 4.5 ve 3.5 aynı şekilde çöküyor.
  • Çıkış kodu önemli değil.
  • Exit () öğesini çağırmadan önce Thread.Sleep () öğesini çağırmak sorunu çözmez.
  • Bu, Windows 8'in 64 bit sürümünde gerçekleşir ve Windows 7 aynı şekilde etkilenmez.
  • Bu nispeten yeni bir davranış olmalı, bunu daha önce görmedim. Güncelleme geçmişinin makinemde artık doğru olmamasına rağmen, Windows Update aracılığıyla hiçbir alakalı güncelleme görmüyorum .
  • Bu son derece kırıcı bir davranıştır. AppDomain.UnhandledException için bir olay işleyicisine böyle bir kod yazarsınız ve aynı şekilde kilitlenir.

Özellikle bu çökmeyi önlemek için neler yapabileceğinizle ilgileniyorum. Özellikle AppDomain.UnhandledException senaryosu beni yoruyor; .NET programını sonlandırmanın pek bir yolu yoktur. UnutulmazException için bir olay işleyicisinde Application.Exit () veya Form.Close () öğesinin çağrılmasının geçerli olmadığına, bu nedenle geçici çözüm olmadığına dikkat edin.


GÜNCELLEME: Mehrdad, sonlandırıcı ipliğin sorunun bir parçası olabileceğine dikkat çekti. Ben bunu görüyorum ve ayrıca CLR sonlandırıcı iplik yürütme bitirmek için verir 2 saniye zaman aşımı için bazı kanıt görüyorum düşünüyorum.

Sonlandırıcı NativeWindow.ForceExitMessageLoop () içinde. 32 bit modunda makine koduna bakarken yaklaşık olarak kod konumuna karşılık gelen bir IsWindow () Win32 işlevi var, 0x3c ofset. Görünüşe göre IsWindow () kilitlenmiyor. Ancak iç için iyi bir yığın izleme alamıyorum, hata ayıklayıcı P / Invoke çağrısı sadece geri döndü düşünüyor. Bunu açıklamak zor. Eğer daha iyi bir yığın izleme alabilirsiniz o zaman görmek isterim. Benim:

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 çağrısının üstünde hiçbir şey yok, yönetilmeyen hata ayıklayıcı etkin değil.


2
Bunu sadece .NET 4, 4 İstemci Profili, 3.5, 3.5 İstemci Profili, 3.0 ve 2.0 ile denedim ve hiçbirinde hata almadım. VS2010 kullanan 64-bit Windows 7 işletim sistemim.
Steve

2
@Steve This happens on the 64-bit version of Windows 8Hans bunu söyledi!
Parimal Raj

7
Bunu kopyalayabilirim (Win 8, 64 bit), kodunuzu kopyalayabilir / yapıştırabilir ve bir düğmeyi bağlayabilirim ve tam olarak belirtilen belirtileri alıyorum.
keyboardP

3
Bir konsol modu uygulaması bu sorunu gösteremedi, Çıkış () iletileri pompalamaya devam ettiğinde hiçbir şey yanlış gidemez.
Hans Passant

3
Exit(0)64bit Win7 ile biraz önce bu tür davranışlarla karşılaştım , Değişen ExitCodeartık Process.GetCurrentProcess().Kill()işe yaradığı herhangi bir sorun olmadan kullanmanıza yardımcı olmuyor
Sriram Sakthivel

Yanıtlar:


85

Bu sorunla ilgili olarak Microsoft ile iletişim kurdum ve bu işe yaramış gibi görünüyordu. En azından öyle olduğunu düşünmek istiyorum :). Onlardan bir çözüm onayı almama rağmen, Windows grubuyla doğrudan iletişim kurmak zordur ve bir aracı kullanmak zorunda kaldım.

Windows Update aracılığıyla gönderilen bir güncelleme sorunu çözdü. Çarpışmadan önce fark edilen 2 saniyelik gecikme artık mevcut değil, bu da IsWindow () kilitlenmesinin çözüldüğünü gösteriyor. Ve program temiz ve güvenilir bir şekilde kapanıyor. Güncelleştirme, Windows Defender, wdboot.sys, wdfilter.sys, tcpip.sys, rpcrt4.dll, uxtheme.dll, crypt32.dll ve wintrust.dll için yüklenen düzeltme ekleri

Uxtheme.dll dışarı tek ördek. Visual Styles tema API'sini uygular ve bu test programı tarafından kullanılır. Emin olamıyorum, ama param sorunun kaynağı olarak bu parada. C: \ WINDOWS \ system32 içindeki kopya, makinemde 14 Ağustos 2013 tarihinde oluşturulan 6.2.9200.16660 sürüm numarasına sahip.

Dava kapandı.


11
Windows Update geçmişi artık makinemde doğru değil. Tek bildiğim 14 Ağustos'ta kuruldu.
Hans Passant

51

Neden "artık" işe yaramıyor bilmiyorum , ama sanırım Environment.Exitbekleyen kesinleştiricileri yürütüyor. Environment.FailFastyapmaz.

(Tuhaf bir nedenden dolayı), daha sonra çalışması gereken ve bunun gerçekleşmesine neden olan garip bekleyen sonlandırıcılara sahip olabilirsiniz.


2
Bir şey üzerinde olabilirsiniz. Sonlandırıcı NativeWindow.ForceExitMessageLoop () öğesini çalıştırmakla meşgul. Garip bir şekilde herhangi bir çağrıda iç içe değil.
Hans Passant

@HansPassant: Keşke sorunu inceleyebilseydim, içine bakabilseydim, ama yapamam. NativeWindow.ForceExitMessageLoopYönetme veya yönetilmeyen koda takılma çağrısı var mı ? Takılı mı kalıyor yoksa meşgul bekliyor mu yoksa bir mesaj falan mı bekliyor?
user541686

Bu kesinlikle temel soruna işaret ediyor gibi görünüyor. Sorunun kökü olan IsWindow () winapi işlevi olduğunu düşünüyorum. Ben de finalizer iplik 2 saniye zaman aşımı görüyorum düşünüyorum, sonra tüm cehenneme gider. Hata ayıklayıcı , IsWindow () çağrısını yürüttüğünü göstermez , ancak Windows'un daha önce yığına sahip hileler oynadığını gördüm, Windows'un içine kritik kod girerken bunu değiştirdim.
Hans Passant

4
Ben işlenmeyen özel durumlar verilen durumda, Environment.FailFast () yöntemi, muhtemelen yine de kullanmak için en iyi yöntem olduğunu düşünüyorum. (Bunu bilmiyordum - teşekkürler!) Ancak ne yazık ki garip bir şekilde çökecek Environment.Exit () kullanacak bir sürü eski kod var :(
Ian Yates

2
Kesinlikle bir şeye bağlısınız. Benim durumumda, bazı entegrasyon testleri yapmak için IHost.StartAsync kullanarak bir IHost başlattım ve yine de IHost.StopAsync'i çağırdıktan sonra (ve elbette bekledikten sonra) işlem hala sona ermedi. Sadece IHost.Dispose çağrıldıktan sonra işlem sona erer. Tavsiye için teşekkürler
Malte R

6

Bu neden olduğunu açıklamıyor, ancak Environment.Exitörneğiniz gibi bir düğme olay işleyicisini çağırmazdım - bunun yerine rene cevabında önerildiği gibi ana formu kapatın .

Bir AppDomain.UnhandledExceptionişleyici gelince , belki Environment.ExitCodearamaktan ziyade ayarlayabilirsiniz Environment.Exit.

Burada neyi başarmaya çalıştığınızdan emin değilim. Neden bir Windows Forms uygulamasından çıkış kodu döndürmek istiyorsunuz? Normalde çıkış kodları konsol uygulamaları tarafından kullanılır.

Özellikle bu çökme önlemek için neler yapabileceğini ilgileniyorum WER iletişim kutusu görünmesini önlemek için gerekli Calling Environment.Exit () gereklidir.

Ana yöntemde bir deneme / yakalama var mı? Windows Forms uygulamaları için, her zaman ileti döngüsünün yanı sıra işlenmeyen özel durum işleyicilerinin yanında bir deneme / yakalama var.


Application.ExitBunun yerine aramak zorunda olduğunuzdan eminim Environment.Exit.
user541686

7
Üzgünüz, bu bir çözüm değil. WER iletişim kutusunun görüntülenmesini önlemek için Environment.Exit () öğesini çağırmak gerekir. "Bilinen gerçeği" de not edin, çıkış kodu önemli değil.
Hans Passant

7
@Hans: WER iletişim kutusunun meşru olmasını önlemek için AppDomain.UnhandledException yakalanıyor mu? Yani, ele alınmayan bir istisna varsa, WER iletişim kutusunun göstermesi gerekiyordu , değil mi?
Harry Johnston

2

Bizim app aynı sorunu buldum, biz aşağıdaki yapı ile çözdük:

Environment.ExitCode=1;
Application.Exit();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.