2008-09-16 32 views
9

在XP中檢測應用程序崩潰的最佳方式是什麼(每次產生同一對「錯誤」窗口 - 每個都有相同的窗口標題),然後重新啓動它?檢測應用程序崩潰並重新啓動它的最佳方法?

我特別感興趣的是使用最少系統資源的解決方案,因爲所討論的系統相當陳舊。

我曾想過使用像AutoIt這樣的腳本語言(http://www.autoitscript.com/autoit3/),並且可能每隔幾分鐘觸發一次「檢測器」腳本?

這會更好地在Python,Perl,PowerShell或其他東西完成嗎?

任何想法,提示或想法非常讚賞。

編輯:它實際上並沒有崩潰(即退出/終止 - 謝謝@tialaramex)。它顯示一個等待用戶輸入的對話框,然後是另一個對話框,等待進一步的用戶輸入,然後實際退出。這是我想要檢測和處理的這些對話框。

+0

應用程序是否真正崩潰(退出,終止,停止運行)或它顯示一個錯誤對話框,等你做什麼? – tialaramex 2008-09-16 23:28:55

回答

3

如何創建一個包裝應用程序作爲一個孩子啓動故障的應用程序,並等待它呢?如果孩子的退出代碼表明有錯誤,則重新啓動它,否則退出。

12

最好的方法是使用一個名爲mutex

  1. 啓動您的應用程序。
  2. 創建一個新的命名互斥體並對其擁有所有權
  3. 開始一個新的進程(進程不是線程)或新的應用程序,你所說的。
  4. 從該進程/應用程序嘗試獲得互斥量。這個過程將阻止
  5. 當應用程序完成釋放互斥鎖(信號)
  6. 如果應用程序完成或應用程序崩潰,「控制」進程將只會獲得互斥鎖。
  7. 測試獲得互斥鎖後的結果狀態。如果應用程序已經墜毀將WAIT_ABANDONED

說明:當一個線程完成不釋放互斥任何其他進程等待它可以AQUIRE它,但它會獲得WAIT_ABANDONED的返回值,這意味着互斥因此被保護的部分的狀態可能是不安全的。

這樣你的第二個應用程序不會消耗任何CPU週期,因爲它會繼續等待互斥體(而這enterely由操作系統處理)

3

我認爲主要問題是Dr. 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']) 
2

這是一個稍微改進的版本。

在我的測試中,當錯誤的exe生成「訪問衝突」時,以前的代碼在無限循環中運行。

我對我的解決方案並不完全滿意,因爲我沒有明確的標準知道應該繼續哪個異常,哪個不能(ExceptionFlags沒有幫助)。

但它適用於我運行的示例。

希望它能幫助, 維維安德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']) 
相關問題