Manipulador de exceções não tratadas no .NET 1.1
-
08-06-2019 - |
Pergunta
Estou mantendo um aplicativo .NET 1.1 e uma das tarefas que recebi é garantir que o usuário não veja nenhuma notificação de erro hostil.
Eu adicionei manipuladores a Application.ThreadException
e AppDomain.CurrentDomain.UnhandledException
, que são chamados.Meu problema é que a caixa de diálogo de erro CLR padrão ainda é exibida (antes que o manipulador de exceções seja chamado).
Jeff fala sobre esse problema em seu blog aqui e aqui.Mas não há solução.Então, qual é a maneira padrão no .NET 1.1 de lidar com exceções não detectadas e exibir uma caixa de diálogo amigável?
A resposta de Jeff foi marcada como correta porque o link que ele forneceu contém as informações mais completas sobre como fazer o que é necessário.
Solução
Ah, no Windows Forms você definitivamente deve conseguir fazê-lo funcionar.A única coisa que você deve observar são as coisas que acontecem em tópicos diferentes.
Eu tenho um artigo antigo do Code Project aqui que deve ajudar:
Outras dicas
AppDomain.UnhandledException é um evento, não um manipulador de exceção global.Isso significa que, no momento em que ele é gerado, seu aplicativo já está indo pelo ralo e não há nada que você possa fazer a respeito, exceto limpar e registrar erros.
O que aconteceu nos bastidores foi o seguinte:A estrutura detectou a exceção, subiu a pilha de chamadas até o topo, não encontrou nenhum manipulador que pudesse se recuperar do erro e, portanto, não foi capaz de determinar se era seguro continuar a execução.Então, ele iniciou a sequência de desligamento e iniciou este evento como uma cortesia para você, para que você possa prestar sua homenagem ao seu processo já condenado.Isso acontece quando uma exceção não é tratada no thread principal.
Não existe uma solução única para esse tipo de erro.Você precisa colocar um manipulador de exceção real (um bloco catch) a montante de todos os locais onde esse erro ocorre e encaminhá-lo para (por exemplo) um método/classe de manipulador global que determinará se é seguro simplesmente relatar e continuar, com base em tipo e/ou conteúdo da exceção.
Editar:É possível desabilitar (= hackear) o mecanismo de relatório de erros integrado ao Windows para que a caixa de diálogo obrigatória "travar e gravar" não seja exibida quando o aplicativo for desativado.No entanto, isso se torna eficaz para todos os aplicativos do sistema, não apenas os seus.
O comportamento de exceção não tratada em um aplicativo .NET 1.x Windows Forms depende de:
- O tipo de thread que lançou a exceção
- Se ocorreu durante o processamento da mensagem da janela
- Se um depurador foi anexado ao processo
- A configuração do registro DbgJitDebugLaunchSetting
- O sinalizador jitDebugging em App.Config
- Se você substituiu o manipulador de exceções do Windows Forms
- Se você lidou com o evento de exceção do CLR
- A fase da lua
O comportamento padrão de exceções não tratadas é:
- Se a exceção ocorrer no thread principal ao bombear mensagens de janela, ela será interceptada pelo manipulador de exceções do Windows Forms.
- Se a exceção ocorrer no thread principal ao bombear mensagens de janela, o processo do aplicativo será encerrado, a menos que seja interceptado pelo manipulador de exceções do Windows Forms.
- Se a exceção ocorrer em um thread manual, threadpool ou finalizador, ela será engolida pelo CLR.
Os pontos de contato para uma exceção não tratada são:
- Manipulador de exceções do Windows Forms.
- A opção de registro de depuração JIT DbgJitDebugLaunchSetting.
- O evento de exceção não tratada do CLR.
O tratamento de exceções interno do Windows Form faz o seguinte por padrão:
- Captura uma exceção não tratada quando:
- a exceção está no thread principal e nenhum depurador anexado.
- exceção ocorre durante o processamento de mensagens da janela.
- jitDebugging = falso em App.Config.
- Mostra a caixa de diálogo ao usuário e evita o encerramento do aplicativo.
Você pode desabilitar o último comportamento definindo jitDebugging = true em App.Config.Mas lembre-se de que esta pode ser sua última chance de impedir o encerramento de aplicativos.Portanto, a próxima etapa para capturar uma exceção não tratada é registrar-se no evento Application.ThreadException, por exemplo:
Application.ThreadException += new
Threading.ThreadExceptionHandler(CatchFormsExceptions);
Observe a configuração do registro DbgJitDebugLaunchSetting em HKEY_LOCAL_MACHINE\Software.NetFramework.Isso tem um dos três valores dos quais estou ciente:
- 0:mostra a caixa de diálogo do usuário perguntando "depurar ou encerrar".
- 1:permite a exceção para o CLR lidar.
- 2:inicia o depurador especificado na chave de registro DbgManagedDebugger.
No Visual Studio, vá para o menu Ferramentas → Opções → Depuração → JIT para definir esta chave como 0 ou 2.Mas o valor 1 geralmente é melhor na máquina do usuário final.Observe que essa chave de registro é acionada antes do evento de exceção não tratada do CLR.
Este último evento é sua última chance de registrar uma exceção não tratada.É acionado antes que seus blocos Finalmente sejam executados.Você pode interceptar este evento da seguinte maneira:
AppDomain.CurrentDomain.UnhandledException += new
System.UnhandledExceptionEventHandler(CatchClrExceptions);
Este é um aplicativo de console ou um aplicativo Windows Forms?Se for um aplicativo de console .NET 1.1, isso é, infelizmente, intencional - foi confirmado por um desenvolvedor da MSFT no segunda postagem do blog que você mencionou:
Aliás, na minha máquina 1.1, o exemplo do MSDN tem a saída esperada;só que a segunda linha só aparece depois de você anexar um depurador (ou não).Na v2, invertemos as coisas para que o evento UnhandledException seja acionado antes que o depurador seja anexado, o que parece ser o que a maioria das pessoas espera.
Parece que o .NET 2.0 faz isso melhor (graças a Deus), mas, honestamente, nunca tive tempo de voltar e verificar.
É um aplicativo Windows Forms.As exceções capturadas por Application.ThreadException funcionam bem e não recebo a caixa de exceção feia do .NET (OK terminar, Cancelar depurar?quem inventou isso??).
Eu estava recebendo algumas exceções que não estavam sendo detectadas por isso e acabei indo para o evento AppDomain.UnhandledException que estava causando problemas.Acho que detectei a maioria dessas exceções e estou exibindo-as em nossa bela caixa de erro agora.
Portanto, só espero que não haja outras circunstâncias que possam fazer com que as exceções não sejam capturadas pelo manipulador Application.ThreadException.