Wie konvertiere ich einen Win32-Ausnahmecode in eine Zeichenfolge?

Lesezeit: 5 Minuten

Benutzer-Avatar
Alan Stokes

Ich muss mich widerwillig wieder mit strukturierten Win32-Ausnahmen befassen. Ich versuche, eine Zeichenfolge zu generieren, die eine Ausnahme beschreibt. Das meiste davon ist einfach, aber ich stecke bei etwas Grundlegendem fest: Wie kann ich einen Ausnahmecode (das Ergebnis von GetExceptionCode()oder der ExceptionCode Mitglied einer EXCEPTION_RECORD) in eine Zeichenfolge, die die Ausnahme beschreibt?

Ich suche etwas, das zB 0xC0000005 in “Access Violation” umwandelt. Ist es nur ein Anruf FormatMessage()?

  • Ja, FormatMessage sollte den Trick machen.

    – Avakar

    27. Oktober 2011 um 11:35 Uhr

Benutzer-Avatar
4LegsDrivenCat

Strukturierte Ausnahmecodes werden durch NTSTATUS-Nummern definiert. Obwohl jemand von MS schlägt vor verwenden FormatNachricht() Um NTSTATUS-Zahlen in Zeichenfolgen umzuwandeln, würde ich dies nicht tun. Flagge FORMAT_MESSAGE_FROM_SYSTEM wird verwendet, um das Ergebnis von umzuwandeln GetLastError() in eine Zeichenfolge, also macht es hier keinen Sinn. Flagge verwenden FORMAT_MESSAGE_FROM_HMODULE zusammen mit ntdll.dll führt bei einigen Codes zu falschen Ergebnissen. Bsp. für EXCEPTION_ACCESS_VIOLATION Sie erhalten The instruction at 0xwas nicht sehr informativ ist 🙂 .

Wenn Sie sich die Zeichenfolgen ansehen, die in gespeichert sind ntdll.dll es wird offensichtlich, dass viele von ihnen mit dem verwendet werden sollen printf() Funktion, nicht mit der FormatNachricht(). Beispielsweise die Zeichenfolge für EXCEPTION_ACCESS_VIOLATION ist:

The instruction at 0x%08lx referenced memory at 0x%08lx. The memory could not be %s.

%0 behandelt wird von FormatNachricht() als Escape-Sequenz bedeutet Nachrichtenabschlusszeichen, keine Einfügung. Einfügungen sind %1 bis %99. Deshalb Flagge FORMAT_MESSAGE_IGNORE_INSERTS macht keinen unterschied.

Vielleicht möchten Sie die Zeichenfolge von laden ntdll.dll und übergebe es an vprintf() Sie müssen die Argumente jedoch genau so vorbereiten, wie es die Zeichenfolge angibt (z. B. für EXCEPTION_ACCESS_VIOLATION es ist unsigned long, unsigned long, char*). Und dieser Ansatz hat einen großen Nachteil: Jede Änderung der Anzahl, Reihenfolge oder Größe der Argumente in ntdll.dll kann Ihren Code brechen.

Daher ist es sicherer und einfacher, die Zeichenfolgen fest in Ihren eigenen Code zu codieren. Ich finde es gefährlich, Saiten zu verwenden, die von jemand anderem ohne Absprache mit mir vorbereitet wurden 🙂 und darüber hinaus für andere Funktionen. Dies ist nur eine weitere Möglichkeit für Fehlfunktionen.

  • Danke für deine Antwort! (Obwohl die Frage jetzt ziemlich alt ist.) Wenn Sie sich meine Kommentare zu der anderen Antwort ansehen, werden Sie feststellen, dass ich die von Ihnen erwähnten Probleme entdeckt habe. Ich habe nur die lästigen Nachrichten mit einem Sonderfall versehen; Ich denke, ich ziehe das vor, alles fest zu codieren, wie Sie es vorschlagen. (Vor allem, da in Zukunft möglicherweise weitere Fehler hinzugefügt werden.)

    – Alan Stokes

    9. Oktober 2015 um 20:29 Uhr


  • Es ist natürlich Geschmackssache. Ich habe mich entschieden, die Codenummer (nützlich für mögliche neue Fehler, wie Sie bemerkt haben), ihre Zeichenfolgendarstellung (z. B. “EXCEPTION_INVALID_DISPOSITION”) und andere Werte aus der EXCEPTION_RECORD-Struktur zu drucken. Für meine Bedürfnisse reicht es. Ich glaube nicht, dass es sinnvoll ist, Endbenutzern eine ausführliche Beschreibung anzuzeigen. Die meisten werden es ohnehin kaum verstehen. Und selbst für Fortgeschrittene wird es nicht nützlich sein, sie werden Ihr Programm nicht reparieren. Der Endbenutzer sollte diese Informationen einfach an die Entwickler zur Untersuchung weitergeben. Und ich als Entwickler kann die aktuelle Beschreibung des Fehlercodes im Internet lesen.

    – 4LegsDrivenCat

    10. Oktober 2015 um 19:06 Uhr

Benutzer-Avatar
MSalter

Ja. Es ist ein NTSTATUSalso verwenden FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_FROM_HMODULEund passieren Sie die HMODULE aus LoadLibrary("NTDLL.DLL")

Quelle: KB259693 (archiviert)

  • Danke, das funktioniert fast. Leider scheinen die Zeichenfolgen in NTDLL.DLL nicht die richtigen Formatcodes für FormatMessage zu verwenden. Die Zeichenfolge für 0xc0000005 lautet “Die Anweisung bei %p verweist auf den Speicher bei %p.”, denke ich, die FormatMessage konvertiert in “Die Anweisung bei “0x” (sic). Siehe auch diese verwandte Frage.

    – Alan Stokes

    27. Oktober 2011 um 13:39 Uhr


  • Bitte lesen Sie meine Antwort, in der ich erklärt habe, warum FormatMessage für diesen Zweck nicht verwendet werden kann.

    – 4LegsDrivenCat

    9. Oktober 2015 um 19:08 Uhr

  • @4Legs “kann nicht” ist zu stark. Ich habe es getan und es hat gut funktioniert, nachdem ich mich speziell um die schwierigen Fälle gekümmert habe.

    – Alan Stokes

    9. Oktober 2015 um 20:33 Uhr

  • Zustimmung, umformuliert. Und fügte sogar eine Referenz hinzu, die Ihre Wahl unterstützt, obwohl ich immer noch glaube, dass es keine gute Idee ist 🙂

    – 4LegsDrivenCat

    10. Oktober 2015 um 18:55 Uhr

  • Das Quelle existiert nicht.

    – Armali

    11. Januar 2018 um 10:28 Uhr

Benutzer-Avatar
LaaLaa

Es ist kompliziert, das Stream-Format einiger NTSTATUS-Strings korrekt zu verwalten. Sie sollten erwägen, es in eine Win32-Nachricht mit zu konvertieren RtlNtStatusToDosError(), das im Header Winternl.h kommt. Sie müssen ntdll.lib in Ihrer Linker-Eingabe haben.

Beispielimplementierung:

// Returns length of resulting string, excluding null-terminator.
// Use LocalFree() to free the buffer when it is no longer needed.
// Returns 0 upon failure, use GetLastError() to get error details.
DWORD FormatNtStatus(NTSTATUS nsCode, TCHAR **ppszMessage) {

    // Get handle to ntdll.dll.
    HMODULE hNtDll = LoadLibrary(_T("NTDLL.DLL"));

    // Check for fail, user may use GetLastError() for details.
    if (hNtDll == NULL) return 0;

    // Call FormatMessage(), note use of RtlNtStatusToDosError().
    DWORD dwRes = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
        hNtDll, RtlNtStatusToDosError(nsCode), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)ppszMessage, 0, NULL);

    // Free loaded dll module and decrease its reference count.
    FreeLibrary(hNtDll);

    return dwRes;
}

  • Was macht das, wenn 0xC0000005 gegeben wird?

    – Alan Stokes

    15. Mai 2017 um 8:50 Uhr

  • @AlanStokes Es wird in ERROR_NOACCESS umgewandelt (in englischer Lokalisierung: „Ungültiger Zugriff auf Speicherort.“).

    – Laa Laa

    15. Mai 2017 um 15:20 Uhr

Ich schlage vor, dass Sie Bugslayer verwenden. Ruf einfach an GetFaultReason mit dem EXCEPTION_POINTERS.

Zusätzlich können Sie den Stapel mit gehen GetFirstStackTraceString und GetNextStackTraceString.

1063450cookie-checkWie konvertiere ich einen Win32-Ausnahmecode in eine Zeichenfolge?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy