c++ - Ausnahmen, die stillschweigend von Windows abgefangen werden, wie wird manuell verfahren?




mfc exception message-pump (7)

Wir haben Probleme damit, dass Windows stillschweigend Ausnahmen ignoriert und es der Anwendung erlaubt, weiter ausgeführt zu werden, wenn die Ausnahme innerhalb der Nachrichtenübermittlung ausgelöst wird. Zum Beispiel haben wir eine Test-MFC-MDI-Anwendung erstellt und OnDraw überschrieben:

void CTestView::OnDraw(CDC* /*pDC*/)
{
    *(int*)0 = 0; // Crash

    CTestDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    // TODO: add draw code for native data here
}

Sie würden beim Ausführen der Anwendung eine unangenehme Fehlermeldung erwarten, aber Sie erhalten überhaupt nichts. Das Programm scheint einwandfrei zu laufen, aber wenn Sie das Ausgabefenster überprüfen, sehen Sie:

Erste-Chance-Ausnahme um 0x13929384 in Test.exe: 0xC0000005: Zugriffsverletzung Schreibort 0x00000000.
Erste-Chance-Ausnahme bei 0x77c6ee42 in Test.exe: 0xC0150010: Der deaktivierte Aktivierungskontext ist für den aktuellen Ausführungsthread nicht aktiv.

Ich weiß, warum ich die Anwendungskontextausnahme erhalte, aber warum wird sie stillschweigend behandelt? Es bedeutet, dass unsere Anwendungen bei der Verwendung ernsthafte Probleme haben können, aber wir werden nie davon erfahren, da unsere Benutzer niemals irgendwelche Probleme melden werden.


Answers

Nach dem Durchsuchen ähnlicher Fragen stolperte ich über diese Antwort: OpenGL unterdrückt Ausnahmen in MFC-Dialogfeld-basierte Anwendung

"Okay, ich habe mehr Informationen darüber gefunden. In meinem Fall ist es Windows 7, das KiUserCallbackExceptionHandler als Ausnahmebehandler installiert, bevor er mein WndProc aufruft und mir die Ausführungskontrolle gibt. Dies geschieht durch ntdll! KiUserCallbackDispatcher. Ich vermute, dass dies eine Sicherheit ist Maßnahme von Microsoft getroffen, um Hacking in SEH zu verhindern.

Die Lösung besteht darin, wndproc (oder hookproc) mit einem try / exception-Frame zu umbrechen. "

Ich habe einen Fehlerbericht mit Microsoft eingereicht. Sie können ihre Antwort hier sehen:
http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silently-caught-in-wndproc-messages

Von Microsoft:

Danke für den Bericht. Ich habe herausgefunden, dass dies ein Windows-Problem ist und dass ein Hotfix verfügbar ist. Eine Fehlerbehebung, die Sie installieren können, finden Sie unter http://support.microsoft.com/kb/976038 .



Ihre Ausgabe sieht so aus, als ob Sie Visual Studio verwenden ...
Wenn ich meine Antwort nicht vergesse.
Sie können festlegen, welche Ausnahmen normal ausgelöst werden. Dies bedeutet, dass Visual Studio sie abfängt und Ihr Programm an der Stelle stoppt, an der die Zugriffsverletzung aufgetreten ist. Führen Sie dies im Menü Debuggen / Ausnahmen aus. Wenn Sie nicht sicher sind, was Sie aktivieren sollen, aktivieren Sie sie alle ...


Funktionen, die von Interesse sein könnten:

SetUnhandledExceptionFilter()
_set_invalid_parameter_handler()
_RTC_SetErrorFuncW()
_CrtSetReportHookW2()

PS, beachten Sie, dass SetUnhandledExceptionFilter () von anderen DLLs überschrieben werden kann, die in Ihre .exe geladen werden. zB flash und nvidia direct3d machen das. Ich benutze api hooking, um dies zu heilen.



Sie können Windows erzwingen, die Ausnahmen mit diesem Code-Snippet nicht zu ignorieren (Ausnahmen von Microsoft , die von einer Anwendung stammen, die in einer 64-Bit-Version von Windows ausgeführt wird, werden ignoriert ), die Sie in Ihren Prozesscode eingeben:

// my SDK is v6.0A and the two APIs are not available in the .h files, so I need to get them at runtime
#define PROCESS_CALLBACK_FILTER_ENABLED     0x1
typedef BOOL (WINAPI *GETPROCESSUSERMODEEXCEPTIONPOLICY)(__out LPDWORD lpFlags);
typedef BOOL (WINAPI *SETPROCESSUSERMODEEXCEPTIONPOLICY)(__in DWORD dwFlags );
HINSTANCE h = ::LoadLibrary(L"kernel32.dll");
if ( h ) {
   GETPROCESSUSERMODEEXCEPTIONPOLICY GetProcessUserModeExceptionPolicy = reinterpret_cast< GETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "GetProcessUserModeExceptionPolicy") );
   SETPROCESSUSERMODEEXCEPTIONPOLICY SetProcessUserModeExceptionPolicy = reinterpret_cast< SETPROCESSUSERMODEEXCEPTIONPOLICY >( ::GetProcAddress(h, "SetProcessUserModeExceptionPolicy") );
   if ( GetProcessUserModeExceptionPolicy == 0 || SetProcessUserModeExceptionPolicy == 0 ) {
      return;
   }
   DWORD dwFlags;
   if (GetProcessUserModeExceptionPolicy(&dwFlags)) {
      SetProcessUserModeExceptionPolicy(dwFlags & ~PROCESS_CALLBACK_FILTER_ENABLED); 
   }
}

Es kann sein, dass Sie auch einen unbehandelten Ausnahmefilter hinzufügen müssen : Der Filter verhält sich wie ein "Top-Level-Exception-Handler", der wie ein oberster catch Block ist. Zum Extrahieren einer programmiererfreundlichen Zeichenfolge aus _EXCEPTION_POINTERS können Sie sehen: Gibt es eine Funktion zum Konvertieren von EXCEPTION_POINTERS-Struktur in eine Zeichenfolge?

LONG WINAPI my_filter(_In_  struct _EXCEPTION_POINTERS *ExceptionInfo)
{
   ::OutputDebugStringA("an exception occured!");
   return EXCEPTION_EXECUTE_HANDLER;
}

Sie fügen den Filter hinzu mit:

::SetUnhandledExceptionFilter(my_filter);

und Sie müssen es in jedem Thread Ihres Prozesses tun: Während das vorherige Snippet pro-Prozess ist, ist der Filter per-Thread.


Wie wäre es mit:

QString convertEnumToQString(ModelApple::AppleType type)
{
    const QMetaObject &mo = ModelApple::staticMetaObject;
    int index = mo.indexOfEnumerator("AppleType");
    QMetaEnum metaEnum = mo.enumerator(index);
    return metaEnum.valueToKey(type);
}

AKTUALISIERT: Für Qt 5.5, siehe diese Antwort





c++ windows mfc exception message-pump