关于Windows XP:检测应用程序崩溃并重新启动的最佳方法?

关于Windows XP:检测应用程序崩溃并重新启动的最佳方法?

Best way to detect an application crash and restart it?

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

我特别感兴趣的是,由于所涉及的系统很旧,使用最少系统资源的解决方案。

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

使用Python,Perl,PowerShell或其他完全更好的方法会更好吗?

任何想法,技巧或想法都值得赞赏。

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


最好的方法是使用命名的互斥锁。

  • 启动您的应用程序。
  • 创建一个新的名为互斥体并对其进行所有权
  • 根据您的喜好启动一个新进程(非线程进程)或一个新应用程序。
  • 从该进程/应用程序尝试获取互斥量。该过程将阻止
  • 应用程序完成后,释放互斥锁(对其进行信号通知)
  • 仅当应用程序完成或应用程序崩溃时,"控制"过程才会获取互斥量。
  • 获取互斥锁后测试结果状态。如果应用程序崩溃了,它将为WAIT_ABANDONED
  • 说明:当线程完成而没有释放互斥锁时,等待它的任何其他进程可以获取它,但是它将获得WAIT_ABANDONED作为返回值,这意味着互斥锁被放弃,因此受保护的节的状态可能是不安全的。

    这样,您的第二个应用程序将不等待任何CPU周期,因为它将继续等待互斥体(并且由操作系统很好地处理)


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

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

    由于我没有找到任何示例代码,因此我编写了此代码
    Python快速入门示例。我不确定它是否坚固
    特别是DEBUG_EVENT的声明可以改进。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    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'])

    如何创建一个包装器应用程序,将其作为子级启动有问题的应用程序并等待它?如果子代的退出代码指示错误,请重新启动它,否则退出。


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

    在我的测试中,当错误的exe产生"访问冲突"时,先前的代码将无限循环运行。

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

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

    希望能帮助到你,
    薇薇安·德·史密特(Vivian De Smedt)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    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'])


    我意识到您正在使用Windows XP,但对于在Vista下处于类似情况的人们,有新的崩溃恢复API可用。这是他们可以做什么的很好的介绍。


    推荐阅读