VS2010 non mostra un messaggio di eccezione non gestito in un’applicazione WinForms su una versione a 64 bit di Windows

Quando creo un nuovo progetto, ottengo uno strano comportamento per le eccezioni non gestite. Ecco come posso riprodurre il problema:

1) creare una nuova applicazione Windows Form (C #, .NET Framework 4, VS2010)

2) aggiungi il seguente codice al gestore Form1_Load :

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

Mi aspetto che VS si interrompa e mostri un messaggio di eccezione non gestito nella seconda riga. Tuttavia, ciò che accade è che la terza riga viene semplicemente saltata senza alcun messaggio e l’applicazione continua a funzionare.

Non ho questo problema con i miei progetti C # esistenti. Quindi immagino che i miei nuovi progetti vengano creati con alcune strane impostazioni predefinite.

Qualcuno ha un’idea di cosa c’è che non va nel mio progetto ???

Ho provato a selezionare le caselle in Debug-> Exceptions. Ma poi le esecuzioni si interrompono anche se gestisco l’eccezione in un blocco try-catch ; che non è anche quello che voglio. Se ricordo bene, c’era una colonna chiamata “eccezioni non gestite” o qualcosa di simile in questa finestra di dialogo, che farebbe esattamente quello che voglio. Ma nei miei progetti c’è solo una colonna (“Gettata”).

Questo è un brutto problema indotto dal livello di emulazione wow64 che consente di eseguire codice a 32 bit sulla versione a 64 bit di Windows 7. Ingoia le eccezioni nel codice eseguito in risposta a una notifica generata dal gestore di windows a 64 bit , come l’evento Load . Impedire al debugger di vederlo e di entrare. Questo problema è difficile da risolvere, i gruppi Windows e DevDiv in Microsoft puntano le dita avanti e indietro. DevDiv non può fare nulla al riguardo, Windows pensa che sia il comportamento corretto e documentato, misterioso come sembra.

È certamente documentato, ma quasi nessuno capisce le conseguenze o pensa che sia un comportamento ragionevole. Soprattutto non quando la procedura della finestra è nascosta alla vista, come in qualsiasi progetto che usa le classi wrapper per hide l’impianto idraulico della finestra. Come qualsiasi applicazione Winform, WPF o MFC. La questione sottostante è che Microsoft non è in grado di capire come trasferire le eccezioni dal codice a 32 bit al codice a 64 bit che ha triggersto la notifica sul codice a 32 bit che tenta di gestire o eseguire il debug dell’eccezione.

È solo un problema con un debugger collegato, il tuo codice bombarderà come al solito senza uno.

Progetto> Proprietà> scheda Crea> Target piattaforma = AnyCPU e untick Preferisci 32 bit. L’app verrà ora eseguita come processo a 64 bit, eliminando la modalità di errore di wow64. Alcune conseguenze, disabilita Modifica + Continua per le versioni VS precedenti a VS2013 e potrebbe non essere sempre ansible quando si ha una dipendenza dal codice a 32 bit.

Altri possibili soluzioni:

  • Debug> Eccezioni> selezionare la casella Gettato per le eccezioni CLR per forzare il debugger a fermarsi sulla riga di codice che genera l’eccezione.
  • Scrivi try / catch nel Load event handler e failfast nel blocco catch.
  • Utilizzare Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException) nel metodo Main() modo che il trapping delle eccezioni nel loop dei messaggi non sia disabilitato in modalità debug. Ciò tuttavia rende tutte le eccezioni non gestite difficili da eseguire il debug, l’evento ThreadException è piuttosto inutile.
  • Considera se il tuo codice appartiene veramente al gestore di eventi Load . È molto raro averne bisogno, è comunque molto popolare in VB.NET e una canzone di cigno perché è l’evento predefinito e un doppio clic aggiunge banalmente il gestore di eventi. Hai sempre davvero bisogno di Load quando sei interessato alle dimensioni effettive della finestra dopo aver applicato le preferenze dell’utente e la scalabilità automatica. Tutto il resto appartiene al costruttore.
  • Aggiornamento a Windows 8 o successivo, hanno risolto questo problema di wow64.

Nella mia esperienza, vedo solo questo problema quando sono in esecuzione con un debugger collegato. L’applicazione si comporta allo stesso modo quando viene eseguita autonomamente: l’eccezione non viene ingerita.

Con l’introduzione di KB976038 , puoi farlo funzionare come ti aspetteresti di nuovo. Non ho mai installato l’aggiornamento rapido, quindi suppongo che sia venuto come parte di Win7 SP1.

Questo è stato menzionato in questo post:

  • Il caso dell’eccezione OnLoad che scompare – eccezioni callback in modalità utente in x64

Ecco un codice che abiliterà l’aggiornamento rapido:

 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); } } 

Chiamalo all’inizio della tua richiesta:

  [STAThread] static void Main() { Kernel32.DisableUMCallbackFilter(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } 

Ho confermato (con il semplice esempio mostrato sotto) che questo funziona, proprio come ci si aspetterebbe.

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

Quindi, quello che non capisco, è il motivo per cui in precedenza era imansible per il debugger gestire i frame di stack in modalità kernel incrociati, ma con questa correzione, in qualche modo l’avevano capito.

Come menziona Hans, compilare l’applicazione ed eseguire l’exe senza un debugger allegato.

Per me il problema stava cambiando un nome di proprietà di Classe a cui era associato un controllo BindingSource. In esecuzione senza IDE sono riuscito a vedere l’errore:

Imansible eseguire il binding alla proprietà o alla colonna SendWithoutProofReading su DataSource. Nome del parametro: dataMember

La correzione del controllo BindingSource per associare il nome della proprietà aggiornata ha risolto il problema: inserisci la descrizione dell'immagine qui

Sto usando WPF e ho incontrato questo stesso problema. Avevo già provato i suggerimenti di Hans 1-3, ma non mi piacevano perché lo studio non si fermava dove si trovava l’errore (quindi non potevo vedere le mie variabili e vedere qual era il problema).

Così ho provato il 4 ° suggerimento di Hans. Sono rimasto sorpreso da quanto del mio codice potesse essere spostato al costruttore MainWindow senza alcun problema. Non sono sicuro del motivo per cui ho preso l’abitudine di mettere tanta logica nell’evento Load, ma apparentemente molto di ciò può essere fatto nel ctor.

Tuttavia, questo ha avuto lo stesso problema di 1-3. Gli errori che si verificano durante il Ctor di WPF vengono incapsulati in un’eccezione Xaml generica. (un’eccezione interna ha il vero errore, ma di nuovo volevo che lo studio si interrompesse proprio nel punto problematico).

Quello che alla fine ha funzionato per me è stato creare un thread, dormire 50ms, tornare al thread principale e fare quello che mi serve …

  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... 

In questo modo lo studio si interrompe proprio dove si verifica un’eccezione non rilevata.

Un semplice Form_Shown potrebbe essere se puoi spostare il tuo codice di inizializzazione in un altro evento come Form_Shown che ha chiamato più tardi di Form_Load e utilizzare un flag per eseguire il codice di avvio nel primo modulo mostrato:

 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! }