أفضل طريقة لاكتشاف تعطل التطبيق وإعادة تشغيله؟

StackOverflow https://stackoverflow.com/questions/78048

  •  09-06-2019
  •  | 
  •  

سؤال

ما هي أفضل طريقة لاكتشاف تعطل التطبيق في نظام التشغيل XP (ينتج نفس زوج نوافذ "الخطأ" في كل مرة - كل منها يحمل نفس عنوان النافذة) ثم أعد تشغيله؟

أنا مهتم بشكل خاص بسماع الحلول التي تستخدم الحد الأدنى من موارد النظام نظرًا لأن النظام المعني قديم جدًا.

لقد فكرت في استخدام لغة البرمجة النصية مثل AutoIt (http://www.autoitscript.com/autoit3/)، وربما تشغيل برنامج نصي "كاشف" كل بضع دقائق؟

هل سيكون من الأفضل القيام بذلك في Python أو Perl أو PowerShell أو أي شيء آخر تمامًا؟

أي أفكار أو نصائح أو أفكار موضع تقدير كبير.

يحرر:لا يتعطل في الواقع (على سبيل المثال.خروج/إنهاء - شكرًا @tialaramex).يعرض مربع حوار في انتظار إدخال المستخدم، متبوعًا بمربع حوار آخر في انتظار إدخال المزيد من المستخدم، ثم يتم الخروج فعليًا.إنها مربعات الحوار هذه التي أود اكتشافها والتعامل معها.

هل كانت مفيدة؟

المحلول

ماذا عن إنشاء تطبيق مجمع يقوم بتشغيل التطبيق المعيب عندما يكون طفلاً وينتظره؟إذا كان رمز الخروج الخاص بالطفل يشير إلى خطأ، فأعد تشغيله، وإلا قم بالخروج.

نصائح أخرى

أفضل طريقة هي استخدام اسم كائن المزامنة.

  1. ابدأ تطبيقك.
  2. قم بإنشاء كائن المزامنة (mutex) مسمى جديد واحصل على ملكيته
  3. ابدأ عملية جديدة (عملية وليست خيط) أو تطبيقًا جديدًا، ما تفضله.
  4. من تلك العملية/التطبيق حاول الحصول على كائن المزامنة (mutex).سيتم حظر العملية
  5. عند انتهاء التطبيق، قم بتحرير كائن المزامنة (قم بالإشارة إليه)
  6. لن تحصل عملية "التحكم" على كائن المزامنة (mutex) إلا في حالة انتهاء التطبيق أو تعطله.
  7. اختبر الحالة الناتجة بعد الحصول على كائن المزامنة (mutex).إذا تعطل التطبيق، فسيكون WAIT_ABANDONED

توضيح: عندما ينتهي مؤشر ترابط دون تحرير كائن المزامنة، يمكن لأي عملية أخرى تنتظره الحصول عليه ولكنها ستحصل على WAIT_ABANDONED كقيمة إرجاع، مما يعني أنه تم التخلي عن كائن المزامنة وبالتالي فإن حالة القسم الذي كان محميًا يمكن أن تكون غير آمنة.

بهذه الطريقة لن يستهلك تطبيقك الثاني أي دورات لوحدة المعالجة المركزية لأنه سيستمر في انتظار كائن المزامنة (وهذا يتم التعامل معه بشكل كامل بواسطة نظام التشغيل)

أعتقد أن المشكلة الأساسية هي أن د.يعرض Watson مربع حوار ويبقي العملية على قيد الحياة.

يمكنك كتابة مصحح الأخطاء الخاص بك باستخدام Windows API وتشغيل تطبيق التحطم من هناك.سيمنع هذا من آخرين من تصحيحات التقاط طلبك ، ويمكنك أيضًا الحصول على حدث استثناء.

بما أنني لم أجد أي رمز عينة ، فقد كتبت عينة 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'])

أدرك أنك تتعامل مع نظام التشغيل Windows XP، ولكن بالنسبة للأشخاص الذين يعانون من وضع مماثل في نظام التشغيل Vista، هناك ميزات جديدة واجهة برمجة التطبيقات لاسترداد الأعطالمتاح. وهنا مقدمة جيدة إلى ما يمكنهم فعله.

هنا نسخة محسنة قليلا.

في الاختبار الذي أجريته، تم تشغيل التعليمات البرمجية السابقة في حلقة لا نهائية عندما أدى ملف exe الخاطئ إلى "انتهاك الوصول".

أنا لست راضيًا تمامًا عن الحل الذي قدمته لأنه ليس لدي معايير واضحة لمعرفة أي الاستثناءات يجب أن يستمر وأيها لا يمكن أن يكون (The ExceptionFlags لا يساعد).

لكنه يعمل على المثال الذي قمت بتشغيله.

آمل أن يساعد ذلك ، فيفيان دي سميد

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'])
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top