Pregunta

¿Cuál es la mejor manera de detectar un fallo de una aplicación en XP (produce el mismo par de ventanas de "error" cada vez, cada una con el mismo título de ventana) y luego reiniciarla?

Me interesa especialmente conocer soluciones que utilizan recursos mínimos del sistema, ya que el sistema en cuestión es bastante antiguo.

Había pensado en usar un lenguaje de programación como AutoIt (http://www.autoitscript.com/autoit3/), y tal vez activar un script de 'detector' cada pocos minutos.

¿Sería mejor hacerlo en Python, Perl, PowerShell o algo completamente distinto?

Cualquier idea, consejo o pensamiento es muy apreciado.

EDITAR:En realidad, no falla (es decir,salir/terminar - gracias @tialaramex).Muestra un cuadro de diálogo esperando la entrada del usuario, seguido de otro cuadro de diálogo esperando más entrada del usuario y luego sale.Son estos diálogos los que me gustaría detectar y tratar.

¿Fue útil?

Solución

¿Qué tal crear una aplicación contenedora que inicie la aplicación defectuosa cuando sea niño y la espere?Si el código de salida del niño indica un error, reinícielo; de lo contrario, salga.

Otros consejos

La mejor manera es usar un nombre exclusión mutua.

  1. Inicie su solicitud.
  2. Cree un nuevo mutex con nombre y tome posesión de él.
  3. Inicie un nuevo proceso (proceso, no hilo) o una nueva aplicación, lo que prefiera.
  4. Desde ese proceso/aplicación intenta adquirir el mutex.El proceso se bloqueará
  5. Cuando la aplicación termine, suelte el mutex (señale)
  6. El proceso de "control" sólo adquirirá el mutex si la aplicación finaliza o falla.
  7. Pruebe el estado resultante después de adquirir el mutex.Si la aplicación ha fallado será WAIT_ABANDONED

Explicación: Cuando un hilo termina sin liberar el mutex, cualquier otro proceso que lo esté esperando puede adquirirlo pero obtendrá un WAIT_ABANDONED como valor de retorno, lo que significa que el mutex se abandona y por lo tanto el estado de la sección que estaba protegida puede ser inseguro.

De esta manera, su segunda aplicación no consumirá ningún ciclo de CPU, ya que seguirá esperando el mutex (y eso lo maneja completamente el sistema operativo).

Creo que el principal problema es que el Dr.Watson muestra un diálogo y mantiene su proceso vivo.

Puede escribir su propio depurador utilizando la API de Windows y ejecutar la aplicación de bloqueo desde allí.Esto evitará que otros depugadores atrapen el bloqueo de su aplicación y también podría ver el evento de excepción.

Como no he encontrado ningún código de muestra, he escrito esta muestra de Python rápido y sucio.No estoy seguro de cuán robusta es especialmente la declaración de depuración_event podría mejorarse.

from ctypes import windll, c_int, Structure
import subprocess

WaitForDebugEvent = windll.kernel32.WaitForDebugEvent    
ContinueDebugEvent = windll.kernel32.ContinueDebugEvent
DBG_CONTINUE = 0x00010002L    
DBG_EXCEPTION_NOT_HANDLED = 0x80010001L

event_names = {    
    3: 'CREATE_PROCESS_DEBUG_EVENT',
    2: 'CREATE_THREAD_DEBUG_EVENT',
    1: 'EXCEPTION_DEBUG_EVENT',
    5: 'EXIT_PROCESS_DEBUG_EVENT',
    4: 'EXIT_THREAD_DEBUG_EVENT',
    6: 'LOAD_DLL_DEBUG_EVENT',
    8: 'OUTPUT_DEBUG_STRING_EVENT', 
    9: 'RIP_EVENT',
    7: 'UNLOAD_DLL_DEBUG_EVENT',
}
class DEBUG_EVENT(Structure):
    _fields_ = [
        ('dwDebugEventCode', c_int),
        ('dwProcessId', c_int),
        ('dwThreadId', c_int),
        ('u', c_int*20)]

def run_with_debugger(args):
    proc = subprocess.Popen(args, creationflags=1)
    event = DEBUG_EVENT()

    while True:
        if WaitForDebugEvent(pointer(event), 10):
            print event_names.get(event.dwDebugEventCode, 
                    'Unknown Event %s' % event.dwDebugEventCode)
            ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE)
        retcode = proc.poll()
        if retcode is not None:
            return retcode

run_with_debugger(['python', 'crash.py'])

Me doy cuenta de que se trata de Windows XP, pero para las personas que se encuentran en una situación similar con Vista, hay nuevas API de recuperación de fallosEstá disponible. Aquí tienes una buena introducción. a lo que pueden hacer.

Aquí hay una versión ligeramente mejorada.

En mi prueba, el código anterior se ejecutó en un bucle infinito cuando el archivo ejecutable defectuoso generó una "infracción de acceso".

No estoy totalmente satisfecho con mi solución porque no tengo un criterio claro para saber qué excepción debe continuar y cuál no (The ExceptionFlags no ayuda).

Pero funciona en el ejemplo que ejecuto.

Espero que ayude, Vivian de Smedt

from ctypes import windll, c_uint, c_void_p, Structure, Union, pointer
import subprocess

WaitForDebugEvent = windll.kernel32.WaitForDebugEvent
ContinueDebugEvent = windll.kernel32.ContinueDebugEvent
DBG_CONTINUE = 0x00010002L
DBG_EXCEPTION_NOT_HANDLED = 0x80010001L

event_names = {
    1: 'EXCEPTION_DEBUG_EVENT',
    2: 'CREATE_THREAD_DEBUG_EVENT',
    3: 'CREATE_PROCESS_DEBUG_EVENT',
    4: 'EXIT_THREAD_DEBUG_EVENT',
    5: 'EXIT_PROCESS_DEBUG_EVENT',
    6: 'LOAD_DLL_DEBUG_EVENT',
    7: 'UNLOAD_DLL_DEBUG_EVENT',
    8: 'OUTPUT_DEBUG_STRING_EVENT',
    9: 'RIP_EVENT',
}

EXCEPTION_MAXIMUM_PARAMETERS = 15

EXCEPTION_DATATYPE_MISALIGNMENT  = 0x80000002
EXCEPTION_ACCESS_VIOLATION       = 0xC0000005
EXCEPTION_ILLEGAL_INSTRUCTION    = 0xC000001D
EXCEPTION_ARRAY_BOUNDS_EXCEEDED  = 0xC000008C
EXCEPTION_INT_DIVIDE_BY_ZERO     = 0xC0000094
EXCEPTION_INT_OVERFLOW           = 0xC0000095
EXCEPTION_STACK_OVERFLOW         = 0xC00000FD


class EXCEPTION_DEBUG_INFO(Structure):
    _fields_ = [
        ("ExceptionCode", c_uint),
        ("ExceptionFlags", c_uint),
        ("ExceptionRecord", c_void_p),
        ("ExceptionAddress", c_void_p),
        ("NumberParameters", c_uint),
        ("ExceptionInformation", c_void_p * EXCEPTION_MAXIMUM_PARAMETERS),
    ]

class EXCEPTION_DEBUG_INFO(Structure):
    _fields_ = [
        ('ExceptionRecord', EXCEPTION_DEBUG_INFO),
        ('dwFirstChance', c_uint),
    ]

class DEBUG_EVENT_INFO(Union):
    _fields_ = [
        ("Exception", EXCEPTION_DEBUG_INFO),
    ]

class DEBUG_EVENT(Structure):
    _fields_ = [
        ('dwDebugEventCode', c_uint),
        ('dwProcessId', c_uint),
        ('dwThreadId', c_uint),
        ('u', DEBUG_EVENT_INFO)
    ]

def run_with_debugger(args):
    proc = subprocess.Popen(args, creationflags=1)
    event = DEBUG_EVENT()

    num_exception = 0

    while True:
        if WaitForDebugEvent(pointer(event), 10):
            print event_names.get(event.dwDebugEventCode, 'Unknown Event %s' % event.dwDebugEventCode)

            if event.dwDebugEventCode == 1:
                num_exception += 1

                exception_code = event.u.Exception.ExceptionRecord.ExceptionCode

                if exception_code == 0x80000003L:
                    print "Unknow exception:", hex(exception_code)

                else:
                    if exception_code == EXCEPTION_ACCESS_VIOLATION:
                        print "EXCEPTION_ACCESS_VIOLATION"

                    elif exception_code == EXCEPTION_INT_DIVIDE_BY_ZERO:
                        print "EXCEPTION_INT_DIVIDE_BY_ZERO"

                    elif exception_code == EXCEPTION_STACK_OVERFLOW:
                        print "EXCEPTION_STACK_OVERFLOW"

                    else:
                        print "Other exception:", hex(exception_code)

                    break

            ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE)

        retcode = proc.poll()
        if retcode is not None:
            return retcode

run_with_debugger(['crash.exe'])
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top