检测应用程序崩溃并重新启动的最佳方法?
在XP中检测应用程序崩溃的最佳方法是什么(每次使用相同的窗口标题每次都生成相同的"错误"窗口对)然后重新启动它?
我特别感兴趣的是,由于所涉及的系统已经很老了,因此需要使用最少的系统资源的解决方案。
我曾想过使用像AutoIt(http://www.autoitscript.com/autoit3/)这样的脚本语言,也许每隔几分钟触发一次"检测器"脚本?
使用Python,Perl,PowerShell或者其他完全更好的方法会更好吗?
非常感谢任何想法,技巧或者想法。
编辑:它实际上并没有崩溃(即退出/终止感谢@tialaramex)。它显示一个对话框,等待用户输入,然后显示另一个对话框,等待其他用户输入,然后实际退出。我想检测并处理这些对话框。
解决方案
回答
如何创建一个包装器应用程序,将其作为子级启动有问题的应用程序并等待它?如果子代的退出代码指示错误,请重新启动它,否则退出。
回答
最好的方法是使用命名的互斥锁。
- 启动应用程序。
- 创建一个新的名为互斥体并对其进行所有权
- 根据喜好启动一个新进程(非线程进程)或者一个新应用程序。
- 从该进程/应用程序尝试获取互斥量。该过程将阻止
- 应用程序完成后,释放互斥锁(对其进行信号通知)
- 仅当应用程序完成或者应用程序崩溃时,"控制"过程才会获取互斥量。
- 获取互斥锁后测试结果状态。如果应用程序崩溃了,它将为WAIT_ABANDONED
说明:当线程完成而没有释放互斥锁时,等待它的任何其他进程可以获取它,但是它将获得WAIT_ABANDONED作为返回值,这意味着互斥锁被放弃,因此受保护的节的状态可能是不安全的。
这样,第二个应用程序将不等待任何CPU周期,因为它将继续等待互斥体(并且由操作系统认真处理)
回答
我意识到我们正在使用Windows XP,但是对于在Vista下处于类似情况的人们,有新的崩溃恢复API可用。这是他们可以做什么的很好的介绍。
回答
我认为主要的问题是Watson博士显示了一个对话框
并使过程保持活力。
我们可以使用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'])
回答
这是一个稍微改进的版本。
在我的测试中,当错误的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'])