代码之家  ›  专栏  ›  技术社区  ›  Umber Ferrule Gokhan Tank

检测应用程序崩溃并重新启动的最佳方法是什么?

  •  8
  • Umber Ferrule Gokhan Tank  · 技术社区  · 16 年前

    在XP中检测应用程序崩溃的最佳方法是什么(每次都会产生相同的“错误”窗口对,每个窗口的标题都相同),然后重新启动它?

    我特别感兴趣的是听到使用最少系统资源的解决方案,因为所讨论的系统相当旧。

    我曾想过使用像AutoIt这样的脚本语言( http://www.autoitscript.com/autoit3/ ),也许每隔几分钟就会触发一个“探测器”脚本?

    这在Python、Perl、PowerShell或其他完全不同的语言中做得更好吗?

    任何想法、提示或想法都非常感谢。

    编辑:它实际上并没有崩溃(即退出/终止-谢谢@tialaramex)。它显示一个等待用户输入的对话框,然后是另一个等待进一步用户输入的对话,然后它实际退出。我想检测和处理的正是这些对话。

    5 回复  |  直到 16 年前
        1
  •  12
  •   John Leidegren    13 年前

    最好的方法是使用命名 mutex .

    1. 启动您的应用程序。
    2. 创建一个新的命名互斥体并接管它的所有权
    3. 启动一个新进程(进程而不是线程)或一个新应用程序,这是你偏好的。
    4. 尝试从该进程/应用程序中获取互斥体。该过程将被阻止
    5. 当应用程序完成时释放互斥体(发出信号)
    6. 只有当应用程序完成或应用程序崩溃时,“控制”进程才会获取互斥体。
    7. 获取互斥体后测试结果状态。如果应用程序崩溃,它将是WAIT_ABANDONED

    说明: 当一个线程完成而没有释放互斥体时,任何其他等待它的进程都可以获取它,但它将获得WAIT_ABANDONED作为返回值,这意味着互斥体被放弃,因此它所保护的部分的状态可能是不安全的。

    这样,你的第二个应用程序就不会消耗任何CPU周期,因为它会一直等待互斥体(这是由操作系统内部处理的)

        2
  •  3
  •   Vinko Vrsalovic    16 年前

    创建一个包装器应用程序,将有故障的应用程序作为子应用程序启动并等待,怎么样?如果子进程的退出代码指示错误,则重新启动它,否则退出。

        3
  •  3
  •   user27030 user27030    16 年前

    我认为主要问题是沃森博士显示了一个对话框 并使你的过程保持活力。

    您可以使用Windows API编写自己的调试器 从那里运行崩溃的应用程序。 这将防止其他调试器捕获以下崩溃 您的应用程序,您还可以捕获Exception事件。

    由于我没有找到任何示例代码,我写了以下代码 Python快速而肮脏的示例。我不确定它有多坚固 特别是DEBUG_EVENT的声明可以改进。

    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'])
    
        4
  •  2
  •   Salman A    16 年前

    我意识到你正在处理的是Windows XP,但对于在Vista下处于类似情况的人来说,有新的 crash recovery API s可用。 Here's a good introduction 他们能做什么。

        5
  •  2
  •   Vivian De Smedt Vivian De Smedt    16 年前

    这是一个稍微改进的版本。

    在我的测试中,当有故障的exe生成“访问违规”时,之前的代码在无限循环中运行。

    我对我的解决方案并不完全满意,因为我没有明确的标准来知道哪些异常应该继续,哪些不能(ExceptionFlags没有帮助)。

    但它适用于我运行的示例。

    希望它能有所帮助, 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'])