VS2010 não mostra mensagem de exceção sem tratamento em um aplicativo WinForms em uma versão de 64 bits do Windows

Quando eu crio um novo projeto, obtenho um comportamento estranho para exceções não tratadas. É assim que consigo reproduzir o problema:

1) criar um novo aplicativo Windows Forms (C #, .NET Framework 4, VS2010)

2) adicione o seguinte código ao manipulador Form1_Load :

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

Eu esperaria que o VS quebra e mostre uma mensagem de exceção não tratada na segunda linha. No entanto, o que acontece é que a terceira linha é ignorada sem nenhuma mensagem e o aplicativo continua em execução.

Eu não tenho esse problema com meus projetos C # existentes. Então, eu acho que meus novos projetos são criados com algumas configurações padrão estranhas.

Alguém tem uma idéia do que está errado com meu projeto ???

Eu tentei verificar as checkboxs em Debug-> Exceptions. Mas, em seguida, as execuções são interrompidas mesmo se eu manipular a exceção em um bloco try-catch ; que também não é o que eu quero. Se bem me lembro, havia uma coluna chamada “exceções não tratadas” ou algo assim na checkbox de diálogo, que faria exatamente o que eu queria. Mas nos meus projetos há apenas uma coluna (“Thrown”).

Esse é um problema desagradável induzido pela camada de emulação wow64 que permite que o código de 32 bits seja executado na versão de 64 bits do Windows 7. Ele engole exceções no código executado em resposta a uma notificação gerada pelo gerenciador de janelas de 64 bits , como o evento Load . Impede que o depurador o veja e entre. Esse problema é difícil de resolver, os grupos Windows e DevDiv na Microsoft estão apontando para frente e para trás. DevDiv não pode fazer nada sobre isso, o Windows acha que é o comportamento correto e documentado, por mais misterioso que pareça.

Certamente é documentado, mas quase ninguém entende as conseqüências ou acha que é um comportamento razoável. Especialmente quando o procedimento de janela está oculto da vista, como em qualquer projeto que use classs de wrapper para ocultar o encanamento da janela. Como qualquer aplicativo WinForms, WPF ou MFC. A questão subjacente é que a Microsoft não conseguiu descobrir como transmitir exceções do código de 32 bits de volta para o código de 64 bits que acionou a notificação de volta ao código de 32 bits que tenta manipular ou depurar a exceção.

É apenas um problema com um depurador conectado, seu código irá bombardear como de costume sem um.

Projeto> Propriedades> guia Construir> Plataforma alvo = AnyCPU e desmarque Preferir 32 bits. Seu aplicativo agora será executado como um processo de 64 bits, eliminando o modo de falha wow64. Algumas conseqüências, ele desabilita as versões do Edit + Continue for VS antes do VS2013 e nem sempre é possível quando você tem uma dependência no código de 32 bits.

Outras soluções possíveis:

  • Debug> Exceptions> marque a checkbox Thrown para exceções do CLR para forçar o depurador a parar na linha de código que lança a exceção.
  • Escreva try / catch no manipulador de events Load e failfast no bloco catch.
  • Use Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException) no método Main() para que a interceptação de exceção no loop de mensagens não seja desabilitada no modo de debugging. No entanto, isso faz com que todas as exceções não ThreadException sejam difíceis de depurar, o evento ThreadException é bastante inútil.
  • Considere se o seu código realmente pertence ao manipulador de events Load . É muito raro precisar dele, no entanto, é muito popular em VB.NET e em uma música cisne porque é o evento padrão e um clique duplo adiciona trivialmente o manipulador de events. Você só precisa realmente Load quando estiver interessado no tamanho real da janela depois que as preferências do usuário e o escalonamento automático forem aplicados. Tudo o resto pertence ao construtor.
  • Atualização para o Windows 8 ou posterior, eles têm esse problema wow64 resolvido.

Na minha experiência, só vejo esse problema quando estou executando um depurador conectado. O aplicativo se comporta da mesma maneira quando executado autônomo: a exceção não é engolida.

Com a introdução do KB976038 , você pode fazer isso funcionar como seria de esperar. Eu nunca instalei o hotfix, por isso estou assumindo que veio como parte do Win7 SP1.

Isso foi mencionado neste post:

  • O caso da exceção OnLoad desaparecendo – exceções de retorno de chamada do modo de usuário em x64

Aqui está um código que permitirá o 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); } } 

Ligue para o início da sua inscrição:

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

Eu confirmei (com o exemplo simples mostrado abaixo) que isso funciona, exatamente como você esperaria.

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

Então, o que eu não entendo é por que era impossível para o depurador lidar com o cruzamento de frameworks de pilha no modo kernel, mas com esse hotfix, eles de alguma forma entenderam isso.

Como Hans menciona, compile o aplicativo e execute o exe sem um depurador anexado.

Para mim, o problema estava mudando um nome de propriedade de class que um controle BindingSource estava vinculado. Executando sem o IDE, consegui ver o erro:

Não é possível ligar à propriedade ou coluna SendWithoutProofReading na DataSource. Nome do parâmetro: dataMember

Corrigindo o controle BindingSource para vincular ao nome da propriedade atualizada resolveu o problema: insira a descrição da imagem aqui

Estou usando o WPF e corri para esse mesmo problema. Eu já havia tentado as sugestões do Hans 1-3, mas não gostei delas porque o estúdio não parava onde estava o erro (então eu não conseguia ver minhas variables ​​e ver qual era o problema).

Então eu tentei a quarta sugestão de Hans. Fiquei surpreso com o quanto do meu código poderia ser movido para o construtor MainWindow sem qualquer problema. Não tenho certeza porque eu tenho o hábito de colocar muita lógica no evento Load, mas aparentemente muito disso pode ser feito no coordenador.

No entanto, isso teve o mesmo problema que 1-3. Erros que ocorrem durante o ctor para o WPF são agrupados em uma exceção Xaml genérica. (uma exceção interna tem o erro real, mas novamente eu queria que o estúdio apenas quebrasse no ponto problemático real).

O que acabou funcionando para mim foi criar um thread, dormir 50ms, despachar de volta para o thread principal e fazer o que eu preciso …

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

Desta forma, o estúdio iria quebrar exatamente onde ocorre uma exceção não capturada.

Uma Form_Shown simples poderia ser se você pudesse mover seu código de boot para outro evento como Form_Shown chamado depois de Form_Load , e usar um sinalizador para executar o código de boot no primeiro formulário mostrado:

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