2010-08-05 10 views
6

Tenemos una aplicación C++ no administrada que utiliza API de terceros para leer archivos CAD. En ciertos archivos CAD corruptos, la biblioteca de terceros se bloquea y trae nuestro EXE hacia abajo con ella. Debido a esto, nuestra aplicación principal es un EXE separado y de esta manera no se ve afectado por el bloqueo. Sin embargo, terminamos con molestos diálogos de informes de errores de Microsoft.¿Se puede evitar el informe de errores de Microsoft para una sola aplicación?

No quiero deshabilitar el sistema de informe de errores de Microsoft. ¿Hay alguna forma de desactivar el informe de errores para una sola aplicación, de modo que si se bloquea, se cuelga silenciosamente sin diálogos emergentes de error?

Respuesta

0

No estoy del todo seguro, pero quizás SetErrorMode o SetThreadErrorMode funcionarán para usted?

+0

nota adicional, si este accidente está siendo causado por una excepción no controlada estructurada (violación de acceso, desbordamiento de pila, etc.) , es posible que desee examinar el uso de manejadores de excepciones estructurados. Puede usarlos para registrar información y silenciarlos silenciosamente o cualquier otra cosa que quiera hacer. –

5

En Vista y más arriba, la función API WerAddExcludedApplication se puede utilizar para excluir un ejecutable de aplicación especificado del informe de errores. Por lo que sé, no hay una opción similar en XP y otras versiones heredadas del sistema operativo.

Sin embargo, dado que WER solo activará las excepciones de aplicación no controlada, debería poder suprimirla agregando un controlador de excepción "catch-all" a su EXE. Ver vectored exception handling para algunas ideas sobre cómo lograr eso.

Tenga en cuenta que la supresión de todas las excepciones no controladas es generalmente una mala idea (y, por ejemplo, hacer que su aplicación falle la certificación del logotipo de Windows), por lo que no debe utilizar esta técnica de manera indiscriminada ...

+0

+1 por mencionar la API de WER. – bk1e

5

Sí, hay algo que puedes hacer Llame a SetUnhandledExceptionFilter() en su método main() para registrar una devolución de llamada. Se llamará cuando nadie se ofrezca como voluntario para manejar la excepción, justo antes de que aparezca el cuadro de diálogo de Microsoft WER.

En realidad, hacer algo en esa devolución de llamada está plagado de problemas. El programa ha muerto con, invariablemente, algo desagradable como una excepción AccessViolation. Que a menudo es disparado por la corrupción del montón. Intentar hacer algo como mostrar un cuadro de mensaje para que el usuario lo sepa es problemático cuando el montón es pan comido. Deadlock siempre acecha a la vuelta de la esquina, listo para simplemente bloquear el programa sin ningún diagnóstico.

Lo único seguro es tener un proceso de ayuda que proteja su proceso principal. Actívelo señalando un evento nombrado en su devolución de llamada. Bríndele la información de excepción que necesita con un archivo mapeado en memoria. El ayudante puede hacer casi todo lo que quiera cuando vea el evento señalado. Incluyendo mostrar un mensaje, tomar un minivolcado. Y terminando el proceso principal.

Así es exactamente como funciona el asistente de Microsoft WerFault.

+0

UEFs son problemáticos y poco confiables en general. Hay algunas circunstancias excepcionales en que el sistema no las devuelve, incluso cuando deberían serlo. Además, son globales y pueden ser reemplazados por extensiones de shell descaradas, bibliotecas de terceros, etc. Llamando 'WerAddExcludedApplication' (propuesta por el usuario" mdb ") o llamando a' SetErrorMode' con 'SEM_NOGPFAULTERRORBOX' (propuesto por el usuario" Jan Goyvaerts ") son ambos más robustos. – Donpedro

5

La respuesta de Hans Passant sobre SetUnhandledExceptionFilter está en el camino correcto. También señala algunos puntos buenos acerca de no poder hacer demasiado en la devolución de llamada porque varias partes del proceso podrían estar en un estado inestable.

Sin embargo, por la forma en que se describe el problema, no parece que quiera hacer otra cosa que decirle al sistema que no ejecute el diálogo de bloqueo normal. En ese caso, es fácil y debe estar seguro, independientemente de las partes del proceso que hayan afectado al choque.

hacer una función algo como esto:

LONG WINAPI UnhandledExceptionCallback(PEXCEPTION_POINTERS pExceptPtrs) 
{ 
    if (IsDebuggerPresent()) 
     // Allow normal crash handling, which means the debugger will take over. 
     return EXCEPTION_CONTINUE_SEARCH; 
    else 
     // Say we've handled it, so that the standard crash dialog is inhibited. 
     return EXCEPTION_EXECUTE_HANDLER; 
} 

Y en algún lugar de su programa (probablemente tan pronto como sea posible) establece la devolución de llamada:

SetUnhandledExceptionFilter(UnhandledExceptionCallback); 

Eso debería hacer lo que quiera - permitir que cualquier bloqueos de ese programa en particular para morir en silencio.

Sin embargo, hay algo más a tener en cuenta sobre esto: siempre que traiga componentes de terceros (DLL, OCX, etc.) existe el riesgo de que uno de ellos también llame a SetUnhandledExceptionFilter y reemplace su devolución de llamada por la suya . Una vez encontré un control ActiveX que establecería su propia devolución de llamada cuando se crea una instancia. Y lo que es peor, no pudo restaurar la devolución de llamada original cuando se destruyó. Eso parecía ser un error en su código, pero independientemente de que tuviera que tomar medidas adicionales para garantizar que mi devolución de llamada deseada al menos se restableció cuando se suponía que era después de que se cerró su control. Entonces, si encuentra que esto no parece funcionar para usted a veces, incluso cuando sabe que ha establecido la devolución de llamada correctamente, entonces puede encontrar algo similar.

+0

Esto no funciona, no se manejó nada. Simplemente reiniciará la instrucción de fallas de nuevo, colisionando de la misma manera. Ciclo infinito. –

+0

Es cierto que escribí esto sobre la base de una combinación de memoria y un fragmento de un código antiguo que ya no estaba en condiciones de probar esto. Pero lo puse en un programa de prueba rápido que hice fallar al intentar usar un puntero NULL y parece funcionar como estaba previsto. Lo veo terminar en silencio, no en bucle. ¿No sería EXCEPTION_CONTINUE_EXECUTION que hace que se reanude en la instrucción de fallas? – TheUndeadFish

+1

Si no me equivoco, no tiene sentido buscar un depurador en su devolución de llamada UEF ('IsDebuggerPresent'), ya que no se devuelven cuando hay un depurador presente. – Donpedro

2

Me encontré en exactamente esta situación mientras desarrollaba una aplicación Delphi. Descubrí que necesitaba dos cosas para suprimir de manera confiable el cuadro de diálogo "la aplicación ha dejado de funcionar".

Llamar a SetErrorMode(SEM_NOGPFAULTERRORBOX); suprime el cuadro de diálogo "la aplicación ha dejado de funcionar". Pero el controlador de excepción de Delphi muestra un cuadro de mensaje con un mensaje de error de tiempo de ejecución en su lugar.

Para suprimir el controlador de excepciones de Delphi llamo a SetUnhandledExceptionFilter con un controlador personalizado que finaliza el proceso llamando al Halt.

Así el esqueleto de una aplicación cliente de Delphi que ejecuta código propenso a los accidentes se convierte en:

function HaltOnException(const ExceptionInfo: TExceptionPointers): Longint; stdcall; 
begin 
    Halt; 
    Result := 1; // Suppress compiler warning 
end; 

begin 
    SetErrorMode(SEM_NOGPFAULTERRORBOX); 
    SetUnhandledExceptionFilter(@HaltOnException); 
    try 
    DoSomethingThatMightCrash; 
    except 
    on E: Exception do 
     TellServerWeFailed(E.Message); 
    end; 
end. 
+0

Para Visual C++, en muchos casos solo usa SetErrorMode (SEM_NOGPFAULTERRORBOX); basta. –

Cuestiones relacionadas