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


2 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 .

Question

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.




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.




Ich habe das gleiche Problem festgestellt und festgestellt, dass es ein Ergebnis dieses Microsoft-Fehlers ist: http://connect.microsoft.com/VisualStudio/feedback/details/550944/hardware-exceptions-on-x64-machines-are-silenly-caught -in-wndproc-Nachrichten

Es gibt eine Lösung, die von Microsoft zur Verfügung gestellt wird, obwohl die Bereitstellung bei mehreren Zielplattformen eine gewisse Herausforderung darstellt:

http://support.microsoft.com/kb/976038

Hier ist ein Artikel zum Thema, der das Verhalten beschreibt:

http://blog.paulbetts.org/index.php/2010/07/20/the-case-of-the-disappearing-onload-exception-user-mode-callback-exceptions-in-x64/

Das Problem besteht im Wesentlichen darin, dass Hardwareausnahmen in 32-Bit-Programmen in der WndProc-Routine auf 64-Bit-Betriebssystemen stillschweigend abgefangen werden, es sei denn, Sie senden Befehle, die es nicht angeben. Microsoft hat einen Hotfix für das Problem, das erforderlich ist , wenn Sie Vista SP2 ausführen, aber nicht mit Windows 7 SP1 erforderlich ist (nicht sicher über Win7 ohne den SP).

Sogar MIT dem Hotfix müssen Sie das richtige Verhalten aktivieren, indem Sie einen Registrierungsschlüssel festlegen oder einige Aufrufe an den Kernel tätigen, um ihm mitzuteilen, dass Ihr Prozess erwartet, dass Hardware-Ausnahmen abstürzen, wenn er während WndProc auftritt.

Gemäß dem obigen PaulBetts-Link wurde dies aus Gründen der Abwärtskompatibilität mit Windows Server 2003 durchgeführt.

Wenn Sie ein 64-Bit-Programm programmieren, geht dieses Problem verloren.




Related