Pertanyaan VS2010 tidak menampilkan pesan pengecualian yang tidak tertangani dalam Aplikasi WinForms pada Windows versi 64-bit


Ketika saya membuat proyek baru, saya mendapatkan perilaku aneh untuk pengecualian yang tidak tertangani. Ini adalah bagaimana saya dapat mereproduksi masalah:

1) membuat Aplikasi Formulir Windows baru (C #, .NET Framework 4, VS2010)

2) tambahkan kode berikut ke Form1_Load handler:

int vara = 5, varb = 0;
int varc = vara / varb;
int vard = 7;

Saya berharap bahwa VS pecah dan menunjukkan pesan pengecualian yang tidak tertangani di baris kedua. Namun, yang terjadi adalah bahwa baris ketiga hanya dilewati tanpa pesan apa pun dan aplikasi tetap berjalan.

Saya tidak memiliki masalah ini dengan proyek C # yang ada. Jadi saya kira proyek-proyek baru saya dibuat dengan beberapa pengaturan default yang aneh.

Apakah ada yang tahu apa yang salah dengan proyek saya ???

Saya mencoba memeriksa kotak-kotak di Debug-> Exceptions. Tapi kemudian eksekusi istirahat bahkan jika saya menangani pengecualian dalam try-catch blok; yang juga bukan yang saya inginkan. Jika saya ingat dengan benar, ada kolom yang disebut "pengecualian tidak tertangani" atau sesuatu seperti ini di kotak dialog ini, yang akan melakukan apa yang saya inginkan. Tetapi dalam proyek-proyek saya hanya ada satu kolom ("Thrown").


75
2018-02-08 14:00


asal


Jawaban:


Ini adalah masalah buruk yang disebabkan oleh emulasi lapisan wow64 yang memungkinkan kode 32-bit untuk berjalan pada Windows versi 64-bit 7. Ini menelan pengecualian dalam kode yang berjalan sebagai tanggapan terhadap pemberitahuan yang dihasilkan oleh window manager 64-bit , seperti Load peristiwa. Mencegah debugger melihatnya dan melangkah masuk. Masalah ini sulit diperbaiki, grup Windows dan DevDiv di Microsoft mengarahkan jari bolak-balik. DevDiv tidak bisa berbuat apa-apa, Windows menganggap itu adalah perilaku yang benar dan terdokumentasi, misterius seperti itu terdengar.

Tentu saja didokumentasikan tetapi hampir tidak ada yang mengerti konsekuensinya atau menganggapnya sebagai perilaku yang masuk akal. Terutama tidak ketika prosedur window disembunyikan dari pandangan tentu saja, seperti itu dalam proyek apa pun yang menggunakan kelas wrapper untuk menyembunyikan jendela pipa. Seperti setiap aplikasi Winforms, WPF atau MFC. Masalah yang mendasari adalah Microsoft tidak dapat menemukan cara untuk mengalirkan pengecualian dari kode 32-bit kembali ke kode 64-bit yang memicu pemberitahuan kembali ke kode 32-bit yang mencoba menangani atau men-debug pengecualian.

Ini hanya masalah dengan debugger yang terpasang, kode Anda akan membom seperti biasa tanpa satu.

Project> Properties> Build tab> Platform target = AnyCPU dan untick Lebih Baik 32-bit. Aplikasi Anda sekarang akan berjalan sebagai proses 64-bit, menghilangkan mode kegagalan wow64. Beberapa konsekuensi, menonaktifkan Edit + Lanjutkan untuk versi VS sebelum VS2013 dan mungkin tidak selalu mungkin ketika Anda memiliki ketergantungan pada kode 32-bit.

Kemungkinan solusi lainnya:

  • Debug> Pengecualian> centang kotak Dilempar untuk pengecualian CLR untuk memaksa debugger berhenti pada baris kode yang melempar pengecualian.
  • Tulis coba / tangkap di Load pengendali event dan failfast di blok tangkap.
  • Menggunakan Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException)dalam Main() metode sehingga perangkap pengecualian di loop pesan tidak dinonaktifkan dalam mode debug. Namun ini membuat semua pengecualian yang tidak tertangani sulit untuk didebug, ThreadException acara ini sangat tidak berguna.
  • Pertimbangkan apakah kode Anda benar-benar termasuk dalam Load pengendali event. Sangat jarang membutuhkannya, namun sangat populer di VB.NET dan lagu swan karena ini adalah acara default dan klik dua kali secara sepele menambahkan pengendali event. Kamu hanya pernah sangat perlu Load saat Anda tertarik dengan ukuran jendela sebenarnya setelah preferensi pengguna dan penskalaan otomatis diterapkan. Segala sesuatu yang lain termasuk dalam konstruktor.
  • Pembaruan untuk Windows 8 atau lebih baru, mereka memiliki masalah wow64 ini dipecahkan.

117
2018-02-08 14:04



Dalam pengalaman saya, saya hanya melihat masalah ini ketika saya sedang menjalankan dengan debugger terpasang. Aplikasi berperilaku sama ketika menjalankan standalone: ​​pengecualian tidak ditelan.

Dengan diperkenalkannya KB976038, Anda dapat membuat ini bekerja seperti yang Anda harapkan lagi. Saya tidak pernah menginstal perbaikan terbaru, jadi saya berasumsi itu datang sebagai bagian dari Win7 SP1.

Ini disebutkan dalam posting ini:

Berikut beberapa kode yang akan mengaktifkan hotfix:

public static class Kernel32
{
    public const uint PROCESS_CALLBACK_FILTER_ENABLED = 0x1;

    [DllImport("Kernel32.dll")]
    public static extern bool SetProcessUserModeExceptionPolicy(UInt32 dwFlags);

    [DllImport("Kernel32.dll")]
    public static extern bool GetProcessUserModeExceptionPolicy(out UInt32 lpFlags);


    public static void DisableUMCallbackFilter() {
        uint flags;
        GetProcessUserModeExceptionPolicy(out flags);

        flags &= ~PROCESS_CALLBACK_FILTER_ENABLED;
        SetProcessUserModeExceptionPolicy(flags);
    }
}

Sebut saja di awal aplikasi Anda:

    [STAThread]
    static void Main()
    {
        Kernel32.DisableUMCallbackFilter();

        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

Saya telah mengkonfirmasi (dengan contoh sederhana yang ditunjukkan di bawah) bahwa ini berfungsi, seperti yang Anda harapkan.

protected override void OnLoad(EventArgs e) {
    throw new Exception("BOOM");   // This will now get caught.
}

Jadi, apa yang saya tidak mengerti, mengapa sebelumnya tidak mungkin bagi debugger untuk menangani crossing stack model kernel-mode, tetapi dengan perbaikan terbaru ini, mereka entah bagaimana menemukan jawabannya.


9
2017-08-17 00:07



Seperti Hans sebutkan, kompilasi aplikasi dan jalankan exe tanpa debugger terpasang.

Bagi saya masalahnya adalah mengubah nama properti Kelas bahwa kontrol BindingSource terikat. Berjalan tanpa IDE saya bisa melihat kesalahan:

Tidak dapat mengikat ke properti atau kolom SendWithoutProofReading pada   Sumber data. Nama parameter: dataMember

Memperbaiki kontrol BindingSource untuk mengikat ke nama properti yang diperbarui memecahkan masalah: enter image description here


3
2018-03-25 23:49



Saya menggunakan WPF dan mengalami masalah yang sama. Saya sudah mencoba saran-saran Hans 1-3, tetapi tidak menyukainya karena studio tidak akan berhenti di tempat kesalahan itu (jadi saya tidak bisa melihat variabel saya dan melihat apa masalahnya).

Jadi saya mencoba saran ke-4 Hans. Saya terkejut pada seberapa banyak kode saya dapat dipindahkan ke konstruktor MainWindow tanpa masalah apa pun. Tidak yakin mengapa saya memiliki kebiasaan menempatkan begitu banyak logika dalam acara Muat, tetapi ternyata banyak dari itu dapat dilakukan di ctor.

Namun, ini memiliki masalah yang sama seperti 1-3. Kesalahan yang terjadi selama ctor untuk WPF terbungkus menjadi pengecualian Xaml generik. (Pengecualian batin memiliki kesalahan nyata, tetapi sekali lagi saya ingin studio untuk hanya istirahat di tempat masalah yang sebenarnya).

Apa yang akhirnya berhasil bagi saya adalah membuat utas, tidur 50ms, mengirim kembali ke utas utama dan melakukan apa yang saya perlukan ...

    void Window_Loaded(object sender, RoutedEventArgs e)
    {
        new Thread(() =>
        {
            Thread.Sleep(50);
            CrossThread(() => { OnWindowLoaded(); });
        }).Start();
    }
    void CrossThread(Action a)
    {
        this.Dispatcher.BeginInvoke(a);
    }
    void OnWindowLoaded()
    {
        ...do my thing...

Cara ini studio akan pecah tepat di mana pengecualian yang tidak tertangkap terjadi.


1
2018-02-28 00:01



Sebuah work-around sederhana bisa jadi jika Anda dapat memindahkan kode init Anda ke acara lain seperti seperti Form_Shown yang disebut nanti Form_Load, dan gunakan bendera untuk menjalankan kode startup pada formulir pertama yang ditampilkan:

bool firstLoad = true; //flag to detect first form_shown

private void Form1_Load(object sender, EventArgs e)
{
    //firstLoad = true;
    //dowork(); //not execute initialization code here (postpone it to form_shown)
}

private void Form1_Shown(object sender, EventArgs e)
{
    if (firstLoad) //simulate Form-Load
    {
        firstLoad = false;

        dowork();
    }
}

void dowork()
{
    var f = File.OpenRead(@"D:\NoSuchFile756.123"); //this cause an exception!

}

0
2018-01-07 12:19