Windows-Fehlercodes lesen — die Dreischichtstruktur von Win32, HRESULT und NTSTATUS

· · Windows, Fehlercodes, HRESULT, NTSTATUS, Win32 API, Fehlersuche, Debugging, Windows-Entwicklung

„Auf dem App-Bildschirm erschien der Fehler 0x80004005. Was bedeutet das?“ — In Beratungen zur Störungsuntersuchung ist diese Art Frage ein Klassiker. Wer die Zahl aus einem Fehlerdialog direkt in eine Suchmaschine eingefügt hat und von einer Flut unzusammenhängender Artikel empfangen wurde — ein Windows-Update-Fehler, ein freigegebener Ordner, der nicht verbindet, ein VBA-Laufzeitfehler, ein Datenbankverbindungsfehler — und nur verwirrter geworden ist, hat viel Gesellschaft.

Das geschieht, weil 0x80004005 (E_FAIL) ein generischer Code ist, dessen einzige Bedeutung „nicht näher bezeichnetes Fehlschlagen“ ist. Derselbe Code wird in zahllosen Situationen verwendet, daher führt die Suche nur nach dem Code nicht zur Ursache. Andererseits kann ein Code wie 0x80070005, wenn Sie die Struktur kennen, in wenigen Sekunden vor der Suche zerlegt werden in „Win32-Fehlernummer 5 = Zugriff verweigert, als HRESULT verpackt“.

Windows-Fehlercodes bilden aus historischen Gründen drei Schichten — Win32-Fehlercodes, HRESULT und NTSTATUS — und sie werden schichtenübergreifend umgewandelt. Sobald Sie diese Struktur im Kopf haben, können Sie selbst beurteilen „welche Schicht, welche Partei diesen Code zurückgegeben hat“ und „was der wesentliche Code ist“, und der Eröffnungszug einer Untersuchung wird viel schneller.

Dieser Artikel richtet sich an IT-Personal in kleinen und mittleren Unternehmen und an Windows-Anwendungsentwickler und ordnet, wie man die drei Fehlercodesysteme unterscheidet und zerlegt, die Beziehung zu .NET-Ausnahmen und die praktische Suche mit err.exe und PowerShell — gestützt auf Microsoft Learn und die veröffentlichte Spezifikation [MS-ERREF] vom August 2026.

1. Zuerst die Kernaussage

  • Windows-Fehlercodes sind vor allem drei Systeme. Win32-Fehlercodes (die kleine Dezimalzahl, die GetLastError zurückgibt), HRESULT (der 32-Bit-Code seit COM, Hex beginnend mit 0x8 oder eine negative Dezimalzahl) und NTSTATUS (Codes der Kernelschicht; Fehler beginnen mit 0xC).123
  • Dezimal und Hexadezimal sind verschiedene Schreibweisen desselben Codes. „Fehler 5“, „0x5“ und „die unteren 16 Bit von 0x80070005“ bezeichnen alle ERROR_ACCESS_DENIED (Zugriff verweigert).1
  • 0x8007xxxx ist „ein verpackter Win32-Fehler“. Es ist ein Win32-Fehlercode, gespeichert in HRESULT FACILITY_WIN32 (7); wandeln Sie die unteren 16 Bit ins Dezimal um, und Sie haben den wesentlichen Code. Das ist das wichtigste Muster beim Lesen von Fehlercodes.45
  • 0x80004005 (E_FAIL) ist kein Ursachencode. Er bedeutet „Unspecified failure“ und trägt keine weitere Information. Statt in diesen Code zu graben, sollten Sie den Herkunftskontext und begleitende Protokolle suchen.6
  • Eine negative Dezimalzahl (-2147467259 und Ähnliches) ist ein HRESULT. Das höchstwertige Bit der 32 Bit (das Fehlschlagbit) ist gesetzt, daher ist eine vorzeichenbehaftete Anzeige negativ. Wandeln Sie sie ins Hexadezimal um und lesen Sie sie dann.2
  • Ein 8-stelliger Wert, der mit 0xC beginnt, ist ein NTSTATUS. 0xC0000005 (Zugriffsverletzung) und 0xC0000135 (DLL nicht gefunden) erscheinen ständig im Ereignisprotokoll und in Abbildern zur Absturzzeit. Sie haben nichts mit der Win32-Fehlernummer 5 zu tun.7
  • Derselbe Code ändert die Bedeutung mit dem Kontext. Die Ursache von Fehler 5 reicht über ACL, Erhöhung, Antivirus, eine gehaltene Datei und mehr, und die „Datei nicht gefunden“ von Fehler 2 ist oft eine abhängige DLL. Lesen Sie die Bedeutung des Codes immer zusammen damit, welche API gegen was fehlgeschlagen ist.1
  • Umwandlungs- und Nachschlagewerkzeuge sind Standard. certutil -error und net helpmsg sind in Windows eingebaut; PowerShells Win32Exception holt die Nachricht; auf einer Entwicklungsmaschine err.exe (Microsoft Error Lookup Tool); in der Abbildanalyse WinDbgs !error.8910
  • In .NET wird ein HRESULT auf einen Ausnahmetyp abgebildet. Ein bekanntes HRESULT geht zum entsprechenden Ausnahmetyp (E_ACCESSDENIED → UnauthorizedAccessException und Ähnliches); ein unbekanntes wird COMException; der ursprüngliche Wert bleibt in Exception.HResult.11

In einem Satz ist das Muster einer Windows-Fehlercode-Untersuchung „die Schreibweise auf Hex ausrichten → beurteilen, welche Schicht der Code ist → zerlegen und den wesentlichen Code herausnehmen → ihn zusammen mit dem Kontext lesen“.

2. Windows hat drei Fehlercodesysteme

Zuerst die Gesamtkarte. Windows-Fehlercodes teilen sich vor allem in die folgenden drei Systeme, nach der Schicht, die sie zurückgibt.

System Hauptpartei, die ihn zurückgibt Typisches Aussehen Repräsentatives Beispiel
Win32-Fehlercode Win32-API (GetLastError), der Exit-Code eines Befehls Eine kleine Dezimalzahl (0–15999) 5 = ERROR_ACCESS_DENIED
HRESULT Eine COM-Komponente, die Shell, ein Installer, viele Frameworks 8-stelliges Hex beginnend mit 0x8 oder eine negative Dezimalzahl 0x80004005 = E_FAIL
NTSTATUS Der Kernel, ein Treiber, eine native API (ntdll) Fehler sind 8-stelliges Hex beginnend mit 0xC 0xC0000005 = STATUS_ACCESS_VIOLATION

Historisch stapelten sie sich in dieser Reihenfolge: Win32-Fehlercodes, die MS-DOS-Fehlernummern erbten, NTSTATUS, den der NT-Kernel intern verwendet, und HRESULT, entworfen bei der Einführung von COM, um „Erfolg/Fehlschlag und den Ursprung in 32 Bit zu packen“. Auf aktuellem Windows ist ein Umwandlungsfluss Alltag: der Kernel gibt ein NTSTATUS zurück, das Win32-Subsystem wandelt es in einen Win32-Fehlercode um, und die COM-Schicht verpackt es weiter als HRESULT.124

Umwandlungsfluss über die drei SystemeDas Win32-Subsystem wandelt ein NTSTATUS, das der Kernel zurückgegeben hat, in einen Win32-Fehlercode um, und die COM-Schicht verpackt es weiter als HRESULTDas Win32-Subsystem wandelt umDie COM-Schicht verpacktKernel und TreiberNTSTATUS(Fehler sind 0xC…)Win32-Fehlercode(5 und Ähnliches)HRESULT(0x8007xxxx)

Abbildung 1: Der Umwandlungsfluss über Schichten. Ein Kernel-NTSTATUS wird ein Win32-Fehler und weiter als HRESULT verpackt.

2.1. Gewöhnen Sie sich daran, Dezimal und Hexadezimal austauschbar zu lesen

Bevor Sie die drei Systeme unterscheiden, müssen Sie Schreibweisenschwankungen aufnehmen. Derselbe Code wird je nach Situation als Dezimal oder Hex angezeigt.

  • „Fehler 5“, „Fehlercode: 0x5“ → dasselbe ERROR_ACCESS_DENIED
  • „Fehler 1223“, „0x4C1“ → dasselbe ERROR_CANCELLED
  • „0x80070005“, „-2147024891“ → dasselbe HRESULT

In PowerShell ist die Umwandlung eine Zeile.

# Decimal → hex
'0x{0:X8}' -f 1223          # 0x000004C1
'0x{0:X8}' -f -2147024891   # 0x80070005 (negative = HRESULT to hex)

# Hex → decimal
0x4C1                        # 1223

Wenn Sie eine negative Dezimalzahl sehen, die mit „-214…“ beginnt, wandeln Sie sie reflexartig ins Hexadezimal um. Das allein schneidet viel Verlaufen am Eingang einer Untersuchung.

Drei Erscheinungen desselben CodesDezimaler Fehler 5, Hex 0x5 und die unteren 16 Bit von 0x80070005 bezeichnen alle dasselbe ERROR_ACCESS_DENIEDDezimalschreibweise: Fehler 5ERROR_ACCESS_DENIEDHex-Schreibweise: 0x5Die unteren 16 Bit von 0x80070005Andere Schreibweise, derselbe Code

Abbildung 2: Dezimal, Hex und die unteren 16 Bit eines HRESULT sind nur verschiedene Schreibweisen desselben Codes.

3. Win32-Fehlercodes — GetLastError und FORMAT_MESSAGE

3.1. Grundlegendes GetLastError-Verhalten

Viele Win32-APIs wie CreateFile und RegOpenKeyEx zeigen Fehlschlag mit dem Rückgabewert (FALSE, NULL, INVALID_HANDLE_VALUE und Ähnliches) an und speichern den detaillierten Fehlercode in einem „Last-Error-Code“, der pro Thread gehalten wird. Der Aufrufer holt ihn mit GetLastError unmittelbar nach der Bestätigung des Fehlschlags.13

Es gibt zwei praktische Vorbehalte.13

  1. Lesen Sie ihn unmittelbar nach dem Fehlschlag. Wenn Sie dazwischen einen anderen API-Aufruf einfügen (eine Protokollierungsfunktion zum Beispiel), kann dieser Aufruf den Last-Error-Code überschreiben.
  2. Verlassen Sie sich bei Erfolg nicht auf den Wert. Einige APIs setzen den Last-Error-Code bei Erfolg auf 0; einige rühren ihn nicht an. Die Regel ist, den Fehlschlag aus dem Rückgabewert zu bestätigen und dann zu lesen.
GetLastError unmittelbar nach dem Fehlschlag lesenNach Bestätigung des Fehlschlags aus dem Rückgabewert den Last-Error-Code mit GetLastError sofort holen, ohne einen anderen API-Aufruf einzufügenWin32 APIAppWin32 APIAppEinen anderen API-Aufruf dazwischen einzufügen kann überschreibenCreateFile-AufrufFehlschlag-RückgabewertGetLastErrorCode 5

Abbildung 3: Lesen Sie den Last-Error-Code unmittelbar nach dem Fehlschlag. Einen anderen API-Aufruf dazwischen einzufügen kann ihn überschreiben.

Um eine Nachrichtenzeichenfolge aus einem Code zu holen, verwenden Sie FormatMessage mit dem Flag FORMAT_MESSAGE_FROM_SYSTEM.1

#include <windows.h>
#include <stdio.h>

void PrintLastError(const wchar_t* apiName)
{
    DWORD code = GetLastError();   // Call immediately after failure (do not insert another API)
    wchar_t message[512] = L"";
    FormatMessageW(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
        nullptr, code, 0, message, 512, nullptr);
    wprintf(L"%s failed: %lu (0x%08lX) %s", apiName, code, code, message);
}

Sowohl Dezimal als auch Hex und den Nachrichtentext im Protokoll Ihrer eigenen App zu hinterlassen, wie hier, macht eine spätere Untersuchung einen Schritt schneller.

Eine Nachricht aus einem Code nachschlagen und im Protokoll hinterlassenDas Flag FORMAT_MESSAGE_FROM_SYSTEM an FormatMessage übergeben, um die Nachrichtenzeichenfolge des Fehlercodes zu holen, und Dezimal, Hex und den Nachrichtentext im Protokoll hinterlassenFehlercode(Beispiel: 5)Die Zeichenfolge mit FormatMessage holenNachrichtentextIm Protokoll aufzeichnenDezimal, Hex und Text zusammen schreiben

Abbildung 4: Wandeln Sie einen Fehlercode mit FormatMessage in eine Nachrichtenzeichenfolge um und hinterlassen Sie Dezimal, Hex und den Text zusammen im Protokoll.

3.2. Repräsentative Codes, die im Feld ständig auftauchen

Win32-Fehlercodes sind im Bereich 0–15999 definiert, und Microsoft Learn hat eine vollständige Liste.1 Unter ihnen sind die Gesichter, denen Sie in der Störungsuntersuchung immer wieder begegnen, die folgenden.

Dezimal Hex Symbol Bedeutung
2 0x2 ERROR_FILE_NOT_FOUND Die angegebene Datei wurde nicht gefunden
3 0x3 ERROR_PATH_NOT_FOUND Der angegebene Pfad wurde nicht gefunden
5 0x5 ERROR_ACCESS_DENIED Der Zugriff wurde verweigert
32 0x20 ERROR_SHARING_VIOLATION Ein anderer Prozess verwendet sie, Zugriff ist nicht möglich
87 0x57 ERROR_INVALID_PARAMETER Der Parameter ist falsch
122 0x7A ERROR_INSUFFICIENT_BUFFER Der übergebene Puffer ist zu klein
998 0x3E6 ERROR_NOACCESS Ungültiger Zugriff auf eine Speicherstelle
1223 0x4C1 ERROR_CANCELLED Der Vorgang wurde vom Benutzer abgebrochen

Davon ist 998 (ERROR_NOACCESS) nicht „Zugriff verweigert“, sondern der Win32-Ausdruck einer Speicherzugriffsverletzung, die Form des später besprochenen NTSTATUS STATUS_ACCESS_VIOLATION nach der Umwandlung in die Win32-Schicht. Achten Sie auf die Verwechslung mit Nummer 5. Auch 1223 (ERROR_CANCELLED) ist ein Code, der erscheint, wenn der Benutzer in einem UAC-Erhöhungsdialog „Nein“ wählt, zum Beispiel — eher „es wurde abgebrochen“ als ein Fehler.

Fehler 998 und 5 sind verschiedene Dinge998 ist eine Speicherzugriffsverletzung, eine NTSTATUS-Zugriffsverletzung umgewandelt in die Win32-Schicht, und unterscheidet sich von 5, das Zugriff verweigert darstelltIn die Win32-Schicht umgewandeltNTSTATUS 0xC0000005Fehler 998(ERROR_NOACCESS)Bedeutung ist eine SpeicherzugriffsverletzungFehler 5(Zugriff verweigert)Ein Berechtigungsproblem. Ein anderes Ding als 998

Abbildung 5: Fehler 998 ist eine NTSTATUS-Zugriffsverletzung, umgewandelt in die Win32-Schicht, ein anderes Ding als Zugriff-verweigert 5.

3.3. Derselbe Code ändert die Bedeutung mit dem Kontext

Wichtiger als die Tabelle der repräsentativen Codes auswendig zu lernen ist das Gefühl, dass ein Fehlercode Ihnen nur „die Art des Fehlschlags“ sagt.

  • Fehler 5 (Zugriff verweigert): Kandidaten für die Ursache reichen weit — unzureichende NTFS-ACL, Schreiben in einen geschützten Bereich ohne Administratorrechte, eine Sperre durch Antivirus oder AppLocker, unzureichende Privilegien eines Dienstkontos und so weiter.
  • Fehler 2 (Datei nicht gefunden): Es ist nicht unbedingt die Datei, die der Benutzer angegeben hat. Eine abhängige DLL, die die EXE implizit zu laden versuchte, eine Einstellungsdatei, die wegen Registrierungsumleitung (32-Bit/64-Bit) am falschen Ort gesehen wurde, ein Pfad, dessen Umgebungsvariablenerweiterung fehlgeschlagen ist — „welche Datei“ nicht gefunden wurde, ist aus dem Code nicht sichtbar.
  • Fehler 32 (Freigabeverletzung): „Welcher Prozess sie hält“ ist die eigentliche Frage, aber der Code sagt Ihnen das nicht.
Die Ursache von Fehler 5 wird vom Kontext entschiedenSelbst derselbe Zugriff verweigert hat mehrere Ursachkandidaten wie unzureichende ACL oder fehlende Administratorrechte, und Sie müssen identifizieren, welche API gegen was fehlgeschlagen istFehler 5(Zugriff verweigert)Unzureichende ACLKeine AdminrechteSperre durch SicherheitsproduktDienstprivilegien niedrigProcmon: fehlgeschlagenes Ziel

Abbildung 6: Ein Code sagt Ihnen nur „die Art des Fehlschlags“. Fehler 5 hat mehrere Ursachkandidaten, und das Ziel zu identifizieren ist erforderlich.

Das Werkzeug, das misst „welche API, gegen welchen Objektnamen, welchen Ergebnis zurückgegeben hat“, ist Process Monitor. Die Verwendung ist ausführlich in „Process Monitor (ProcMon) Praxisleitfaden“ behandelt. Die Bedeutung eines Fehlercodes nachzuschlagen und das Ziel zu identifizieren, das fehlgeschlagen ist, sind zwei Räder desselben Wagens.

4. HRESULT — Die in 32 Bit gepackte Struktur lesen

4.1. Bit-Layout

HRESULT ist ein Format, das Erfolg/Fehlschlag, Ursprung und einen Detailcode in einen einzelnen 32-Bit-Wert packt. Die veröffentlichte Spezifikation [MS-ERREF] definiert es mit dem folgenden Layout.2

Bitposition Name Bedeutung
31 S Severity. 0 = Erfolg, 1 = Fehlschlag
30 R Reserviert (Teil der Severity beim Abbilden von NTSTATUS)
29 C Customer-Bit. 1 bedeutet einen Code, den jemand anderes als Microsoft definiert hat
28 N 1 bedeutet einen NTSTATUS-Wert, der in den HRESULT-Raum abgebildet wurde
27 X Reserviert (0)
26–16 Facility Ein Facility-Code, der den Ursprung anzeigt (11 Bit)
15–0 Code Ein Detailcode innerhalb der Facility (16 Bit)

Das höchstwertige S-Bit ist 1, das heißt ein HRESULT, dessen Hex-Schreibweise bei 0x8 oder darüber beginnt, ist ein Fehlschlag. Das als vorzeichenbehaftete 32-Bit-Ganzzahl anzuzeigen macht es negativ — das ist die Identität des früher erwähnten „-214…“.

Die Beziehung zwischen dem S-Bit und einer negativen AnzeigeEin Fehlschlag-HRESULT hat das höchstwertige S-Bit auf 1, daher beginnt es in Hex bei 0x8 oder darüber, und als vorzeichenbehaftete 32-Bit-Ganzzahl ist es negativS-Bit = 1(Fehlschlag)Hex beginnt bei 0x8 oder darüberEine vorzeichenbehaftete Anzeige ist negativBei einem Negativen ins Hex umwandeln und lesen

Abbildung 7: Ein Fehlschlag-HRESULT beginnt bei 0x8 oder darüber, weil das S-Bit 1 ist, und eine vorzeichenbehaftete Anzeige ist negativ.

Repräsentative Facility-Werte sind die folgenden.5

Facility Wert Hex-Erscheinung Bedeutung
FACILITY_NULL 0 0x8000xxxx Weit verbreitete gemeinsame Codes (E_FAIL, E_UNEXPECTED und Ähnliches)
FACILITY_RPC 1 0x8001xxxx RPC-Ursprung
FACILITY_ITF 4 0x8004xxxx Ein schnittstellendefinierter Fehler (Bedeutung hängt von der Schnittstelle ab)
FACILITY_WIN32 7 0x8007xxxx Ein verpackter Win32-Fehlercode
FACILITY_WINDOWS 8 0x8008xxxx Zusätzliche von Microsoft definierte Schnittstellen

4.2. 0x80004005 und 0x80070005 zerlegen

Zerlegen wir sie tatsächlich.

Für 0x80004005: S=1 (Fehlschlag), Facility=(0x80004005 » 16) & 0x7FF = 0 (FACILITY_NULL), Code=0x4005. Ein generischer FACILITY_NULL-Code, definiert als E_FAIL „Unspecified failure“.6 Mit anderen Worten trägt dieser Code nur die Bedeutung „ein Fehlschlagen, das kein Detail berichten kann“. Wenn Sie 0x80004005 sehen, hören Sie dort auf, in den Code selbst zu graben, und verschieben Sie das Gewicht der Untersuchung auf „welche Komponente ihn zurückgegeben hat“ und „gibt es Detail im Ereignisprotokoll oder im App-Protokoll zur gleichen Zeit“.

Für 0x80070005: S=1, Facility=7 (FACILITY_WIN32), Code=0x0005=5. Sie können sehen, dass es Win32-Fehlernummer 5 (ERROR_ACCESS_DENIED) als HRESULT verpackt ist. Der Alias E_ACCESSDENIED ist im Wesentlichen dieser Wert.6

Selbst für dasselbe „Zugriff verweigert“ ist 0x80070005 eine Verpackung eines konkreten Fehlschlags, der in der Win32-Schicht aufgetreten ist, und die Informationsmenge ist völlig anders als 0x80004005.

Zerlegung von 0x80004005 und 0x800700050x80004005 ist der generische FACILITY_NULL-Code E_FAIL, trägt kein Detail und sollte zu einer Kontextuntersuchung übergehen; 0x80070005 ist FACILITY_WIN32 und lässt sich als Verpackung der Win32-Fehlernummer 5, Zugriff verweigert, lesen0x80004005Facility=0(FACILITY_NULL)Code=0x4005 → E_FAILNicht näher bezeichnetes Fehlschlagen. Weiter zur Kontextuntersuchung0x80070005Facility=7(FACILITY_WIN32)Code=0x0005 → 5ERROR_ACCESS_DENIED

Abbildung 8: Selbst dasselbe „Fehlschlagen“ hat nach der Zerlegung eine andere Informationsmenge. 0x80070005 lässt sich zur Win32-Fehlernummer 5 gehen.

4.3. Das wichtigste Muster: 0x8007xxxx = HRESULT_FROM_WIN32

Um einen Fehlschlag von einer unteren Schicht, die nur einen Win32-Fehlercode zurückgeben kann, an eine obere Schicht zu übermitteln, die HRESULT zurückgibt (eine COM-Methode oder die .NET-Laufzeit), stellt winerror.h das Makro HRESULT_FROM_WIN32 bereit.4 Das Verhalten ist „den Win32-Fehlercode in den unteren 16 Bit speichern, Facility auf FACILITY_WIN32 (7) setzen und das S-Bit auf 1 setzen“.

Wie HRESULT_FROM_WIN32 funktioniertDen Win32-Fehlercode in den unteren 16 Bit speichern, Facility auf 7 und das S-Bit auf 1 setzen und ein 0x8007xxxx-HRESULT zusammenbauenWin32-Fehlercode(Beispiel: 5)In den unteren 16 Bit speichernFacility auf 7 setzenDas S-Bit auf 1 setzen0x80070005

Abbildung 9: HRESULT_FROM_WIN32 speichert den Win32-Fehler in den unteren 16 Bit und setzt Facility=7 und das S-Bit.

ERROR_ACCESS_DENIED (5)        --HRESULT_FROM_WIN32-->  0x80070005
ERROR_SHARING_VIOLATION (32)   --HRESULT_FROM_WIN32-->  0x80070020
ERROR_INVALID_PARAMETER (87)   --HRESULT_FROM_WIN32-->  0x80070057 (= E_INVALIDARG)
ERROR_OUTOFMEMORY (14)         --HRESULT_FROM_WIN32-->  0x8007000E (= E_OUTOFMEMORY)

Um in die andere Richtung zu lesen, nehmen Sie die unteren 16 Bit in PowerShell.

0x80070005 -band 0xFFFF   # 5 → ERROR_ACCESS_DENIED
0x80072EE7 -band 0xFFFF   # 12007 → ERROR_INTERNET_NAME_NOT_RESOLVED (WinINet)

Wie im zweiten Beispiel sind WinINet- und WinHTTP-Fehler (die 12000er) ebenfalls im Win32-Fehlercode-Raum definiert1, daher lässt sich ein Netzwerk-0x8007xxxx mit demselben Verfahren zerlegen. „Wenn Sie 0x8007 sehen, wandeln Sie die unteren 4 Ziffern ins Dezimal um“ ins Muskelgedächtnis zu bringen ist die praktische Fertigkeit Nummer eins, die dieser Artikel Ihnen mitgeben möchte.

Es gibt den gegenteiligen Vorbehalt für 0x8004xxxx (FACILITY_ITF). Ein FACILITY_ITF-Code hat eine andere Partei, die die Bedeutung pro Schnittstelle definiert, daher kann derselbe 32-Bit-Wert etwas anderes bedeuten, wenn die Partei, die ihn zurückgegeben hat, anders ist.5 Für ein unvertrautes 0x8004xxxx schlagen Sie es nicht in einer generischen Suche nach, sondern in der Dokumentation der Komponente, die es zurückgegeben hat (eine Bibliothek, ein Treiber-SDK, ein Serverprodukt).

Wie Sie nachschlagen, ändert sich zwischen 0x8007 und 0x8004Ein FACILITY_WIN32-0x8007xxxx lässt sich lesen, indem man die unteren 16 Bit mechanisch zerlegt, aber ein FACILITY_ITF-0x8004xxxx hat eine andere Partei, die die Bedeutung pro Schnittstelle definiert, daher in den Unterlagen der zurückgebenden Komponente nachschlagen7, WIN324, ITFFacility ist?Die unteren 16 Bit ins Dezimal umwandelnBedeutung unterscheidet sich nach der zurückgebenden ParteiAls Win32-Fehler lesenIn den Unterlagen der zurückgebenden Partei nachschlagen

Abbildung 10: 0x8007xxxx lässt sich mechanisch zerlegen; 0x8004xxxx wird in den Unterlagen der zurückgebenden Komponente nachgeschlagen.

5. NTSTATUS — Codes der Kernelschicht und die Welt der Abstürze

5.1. Layout und Severity

NTSTATUS ist ein 32-Bit-Code, den der Kernel, Gerätetreiber und ntdll-native APIs verwenden, und sein Layout ähnelt HRESULT, ohne dasselbe zu sein.3

Bitposition Name Bedeutung
31–30 Sev Severity. 00 = Erfolg, 01 = Information, 10 = Warnung, 11 = Fehler
29 C Customer-Bit
28 N Reserviert (0, damit eine Abbildung auf HRESULT möglich ist)
27–16 Facility Facility (12 Bit)
15–0 Code Detailcode

Weil Severity 2 Bit hat, können Sie die Art aus der führenden Hex-Ziffer lesen. 0xC… ist ein Fehler (11), 0x8… eine Warnung (10), 0x4… Information (01), 0x0–0x3… Erfolg. Die Haltepunktausnahme 0x80000003 (STATUS_BREAKPOINT) ist ein repräsentatives Beispiel für „eine Warnung, kein Fehler“.37

Ein NTSTATUS lässt sich nach Art aus der führenden Ziffer lesenWeil Severity 2 Bit hat, lässt sich ein NTSTATUS als Fehler lesen, wenn die führende Hex-Ziffer 0xC ist, Warnung wenn 0x8, Information wenn 0x4 und Erfolg wenn 0x0 bis 0x30xC0x80x40x0–0x3Die führende Hex-Ziffer ist?FehlerWarnungInformationErfolgBeispiel: 0x80000003 ist eine Warnung

Abbildung 11: Ein NTSTATUS lässt sich nach Art aus der führenden Hex-Ziffer lesen. 0x80000003 ist „eine Warnung, kein Fehler“.

5.2. Wo Sie ihm begegnen — Ausnahme-Codes, STOP-Codes und das Ereignisprotokoll

Die Situationen, in denen IT-Personal und Entwickler NTSTATUS begegnen, sind vor allem absturzbezogen.

  • Ein Ausnahme-Code eines Anwendungsabsturzes: Der „Exception code: 0xc0000005“, der im Ereignisprotokoll unter „Anwendungsfehler (Ereignis-ID 1000)“ aufgezeichnet wird, ist ein NTSTATUS. Repräsentative Werte sind die folgenden.7
Wert Symbol Bedeutung
0xC0000005 STATUS_ACCESS_VIOLATION Zugriffsverletzung (ein unzulässiger Speicherzugriff)
0xC0000135 STATUS_DLL_NOT_FOUND Eine erforderliche DLL wurde nicht gefunden, Start ist nicht möglich
0xC00000FD STATUS_STACK_OVERFLOW Stapelüberlauf
0xC0000374 STATUS_HEAP_CORRUPTION Heap-Beschädigung
  • Ein Bluescreen-STOP-Code: Sie sehen auf den ersten Blick ähnlich aus, aber ein STOP-Code (Bug-Check-Code) ist ein eigenes Nummerierungssystem, getrennt von NTSTATUS, etwa 0x0000009F (DRIVER_POWER_STATE_FAILURE), und hat eine eigene Referenz.14 Nur die Unterscheidung zu behalten „0xC0000005 ist NTSTATUS; STOP 0x9F ist ein Bug-Check-Code und Sie dürfen ihn nicht in einer NTSTATUS-Tabelle nachschlagen“ reicht.
  • Die Result-Spalte von Process Monitor: NAME NOT FOUND und ACCESS DENIED in der Result-Spalte von Procmon sind Anzeigenamen des NTSTATUS, das der Kernel zurückgegeben hat (STATUS_OBJECT_NAME_NOT_FOUND, STATUS_ACCESS_DENIED). Es ist auch ein Ort, an dem Sie die Schichtentsprechung spüren können: einen Datei-E/A-Fehlschlag im NTSTATUS-Vokabular zu beobachten und dass dieser Fehlschlag in einen Win32-Fehler umgewandelt bei der App ankommt.
Einen Ausnahme-Code von einem STOP-Code unterscheidenEinen Ausnahme-Code des Ereignisprotokolls als NTSTATUS lesen; einen Bluescreen-STOP-Code in der eigenen Bug-Check-Code-Referenz nachschlagen, einem anderen SystemAusnahme-CodeSTOP-CodeWo ist der Code erschienen?Als NTSTATUS lesenIn der Bug-Check-Code-Tabelle nachschlagenBeispiel: 0xC0000005Beispiel: 0x0000009F

Abbildung 12: Ein Ausnahme-Code des Ereignisprotokolls ist ein NTSTATUS; ein Bluescreen-STOP-Code ist ein anderes System. Schlagen Sie sie nicht in der falschen Tabelle nach.

Die Untersuchung jenseits des Ausnahme-Codes, das heißt das Erfassen und Analysieren eines Absturzabbilds, ist in „Einführung in das Sammeln von Windows-Absturzabbildern“ und „Absturz-Dumps mit WinDbg + SOS lesen“ behandelt.

5.3. Die Beziehung zu HRESULT — das N-Bit und RtlNtStatusToDosError

Die Brücke zwischen NTSTATUS und den anderen zwei Schichten hat zwei Wege.

  1. Eine Abbildung in den HRESULT-Raum: Das HRESULT-N-Bit (0x10000000) zu setzen bringt einen NTSTATUS-Wert unverändert in den HRESULT-Raum (das Makro HRESULT_FROM_NT in winerror.h). 0xC0000005 abzubilden wird zum Beispiel 0xD0000005. Wenn Sie ein HRESULT sehen, das mit 0xD beginnt, ist das korrekte Verfahren, das N-Bit zu entfernen und es als NTSTATUS zu lesen.2
  2. Umwandlung in einen Win32-Fehlercode: RtlNtStatusToDosError von ntdll wandelt ein NTSTATUS in den entsprechenden Win32-Fehlercode um. Ein Wert ohne definierte Entsprechung wird ERROR_MR_MID_NOT_FOUND.12 Zum Beispiel wird STATUS_ACCESS_VIOLATION (0xC0000005) in ERROR_NOACCESS (998) umgewandelt und STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034) in ERROR_FILE_NOT_FOUND (2). Es ist auch nützlich zu behalten, dass das reiche Vokabular des Kernels in der Win32-Schicht manchmal auf eine gröbere Unterscheidung gerundet wird.
Zwei Brücken von NTSTATUS zu den anderen SchichtenEin NTSTATUS wird auf zwei Wegen an die anderen Schichten übergeben: in den HRESULT-Raum abgebildet, indem das N-Bit gesetzt wird, und von RtlNtStatusToDosError in einen Win32-Fehlercode umgewandeltDas N-Bit setzenRtlNtStatusToDosErrorNTSTATUS(0xC0000005)HRESULT(0xD0000005)Win32-Fehler 998(ERROR_NOACCESS)ERROR_MR_MID_NOT_FOUND, wenn keine Entsprechung definiert ist

Abbildung 13: Es gibt zwei NTSTATUS-Brücken. Ein 0xD-Beginn wird nach Entfernen des N-Bits als NTSTATUS gelesen.

6. COM und .NET — Wie ein Fehlercode auf eine Ausnahme abgebildet wird

6.1. Der COM-Stil — HRESULT + IErrorInfo

Eine COM-Methode gibt grundlegend HRESULT zurück, aber es gibt eine Grenze, was in 32 Bit packt, daher kann als Ergänzung der IErrorInfo-Mechanismus eine Fehlerbeschreibungszeichenfolge und den Ursprung getrennt übermitteln. In C++ behandelt die vom Compiler unterstützte Klasse _com_error HRESULT und IErrorInfo zusammen. Eine App, deren Fehlerdialog „Code + Beschreibung“ zeigt, trägt die Beschreibung oft durch diesen Mechanismus.

IErrorInfo, das HRESULT ergänztEs gibt eine Grenze, was in ein 32-Bit-HRESULT packt, daher werden eine Fehlerbeschreibungszeichenfolge und der Ursprung getrennt mit IErrorInfo übermittelt, und in C++ behandelt die Klasse _com_error beide zusammenHRESULT(nur 32 Bit)Es gibt eine Grenze, was packtIErrorInfo trägt die Beschreibung_com_error behandelt sie zusammenDer Code + Beschreibung des Dialogs

Abbildung 14: Eine Beschreibungszeichenfolge, die nicht in ein 32-Bit-HRESULT passt, wird getrennt von IErrorInfo getragen.

6.2. Der .NET-Stil — von einem HRESULT zu einem Ausnahmetyp

Wenn die .NET-Laufzeit in COM-Interop einen HRESULT-Fehlschlag empfängt, wandelt sie ihn in eine Ausnahme um. Ein bekanntes HRESULT wird auf den entsprechenden Ausnahmetyp abgebildet; ein unbekanntes wird COMException.11

Abbildung von HRESULT auf eine .NET-AusnahmeEin Fehlschlag-HRESULT, das in COM-Interop empfangen wird, wird in den entsprechenden Ausnahmetyp umgewandelt, wenn bekannt, oder in COMException, wenn unbekannt, und in beiden Fällen bleibt der ursprüngliche Wert in Exception.HResultYesNoFehlschlag-HRESULTEine bekannte Abbildung?In den entsprechenden Ausnahmetyp umwandelnIn COMException umwandelnDer ursprüngliche Wert bleibt in Exception.HResult

Abbildung 15: .NET bildet ein HRESULT auf einen Ausnahmetyp ab, und der ursprüngliche Wert bleibt in Exception.HResult auf jeder Ausnahme.

HRESULT .NET-Ausnahmetyp
E_ACCESSDENIED (0x80070005) UnauthorizedAccessException
E_OUTOFMEMORY (0x8007000E) OutOfMemoryException
E_INVALIDARG (0x80070057) ArgumentException
E_NOTIMPL (0x80004001) NotImplementedException
Ein Wert ohne definierte Abbildung COMException (der ursprüngliche Wert in der Eigenschaft ErrorCode)

Auf jeder Ausnahme bleibt das ursprüngliche HRESULT in der Eigenschaft Exception.HResult. Eine Verzweigung in der Datei-E/A-Ausnahmebehandlung wie „nur bei einer Freigabeverletzung erneut versuchen“ lässt sich mit diesem Wert schreiben.

try
{
    using var stream = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException ex) when (ex.HResult == unchecked((int)0x80070020))
{
    // 0x80070020 = HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION)
    // Another process is holding the file — wait a little and retry, for example
}

6.3. P/Invoke und GetLastError

Wenn Sie eine Win32-API direkt über P/Invoke aufrufen, geben Sie SetLastError = true auf DllImport (oder LibraryImport) an und holen Sie dann mit Marshal.GetLastWin32Error (ab .NET 6 das Äquivalent GetLastPInvokeError). GetLastError selbst als P/Invoke zu definieren und aufzurufen ist ungenau, weil ein API-Aufruf innerhalb der Laufzeit den Wert überschreiben kann.15

Den letzten Fehler in P/Invoke holenSetLastError als true anzugeben und mit Marshal.GetLastWin32Error zu holen ist korrekt; GetLastError direkt zu P/Invoken ist ungenau wegen einer LaufzeitüberschreibungEine Win32-API über P/Invoke aufrufenSetLastError=true angebenMit GetLastWin32Error holenEine Definition, die GetLastError direkt aufruftDie Laufzeit überschreibt ihn und es ist ungenau

Abbildung 16: In P/Invoke verwenden Sie SetLastError=true und Marshal.GetLastWin32Error als Satz. GetLastError direkt aufzurufen ist ungenau.

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
static extern SafeFileHandle CreateFileW(string fileName, uint access, uint share,
    IntPtr security, uint disposition, uint flags, IntPtr template);

// Receive the return value as SafeFileHandle, not IntPtr, and close it reliably with using
// (leaving it as IntPtr leaks a kernel handle)
using var handle = CreateFileW(@"C:\ProgramData\MyApp\config.dat",
    0x80000000 /*GENERIC_READ*/, 0, IntPtr.Zero, 3 /*OPEN_EXISTING*/, 0, IntPtr.Zero);
if (handle.IsInvalid)
{
    int code = Marshal.GetLastWin32Error();              // Example: 5
    var message = new Win32Exception(code).Message;       // Example: Access is denied.
    logger.LogError("CreateFileW failed: {Code} (0x{Code:X8}) {Message}",
        code, code, message);
}

Win32Exception schlägt die OS-Nachrichtenzeichenfolge aus einem Win32-Fehlercode nach, daher können Sie sie so verwenden, um sowohl den Code als auch die Nachricht in einem Protokoll zu hinterlassen. Die Entwurfsfrage, in welcher Schicht eine Ausnahme zu fangen und wie sie in einem Protokoll zu hinterlassen ist, ist in „Wo sollten catch und Logging in der Ausnahmebehandlung stehen?“ behandelt.

7. Umwandlungs- und Untersuchungswerkzeuge in der Praxis — Eine Kopier-Einfügen-Kurzreferenz

7.1. err.exe (Microsoft Error Lookup Tool)

Ein eigenständiges Fehler-Nachschlagewerkzeug, das Microsoft verteilt. Es durchläuft eine große Zahl von Header-Dateien wie winerror.h und ntstatus.h und listet Definitionen und Nachrichten auf, die zum angegebenen Code passen.8

err 0x80070005
err 5
err 0xC0000005

Eine einzelne Zahl kann in mehreren Headern treffen (zum Beispiel trifft „5“ Definitionen an verschiedenen Stellen außer Win32 ERROR_ACCESS_DENIED), daher muss welcher der Kandidaten plausibel ist nach Kontext gewählt werden. Der Download-Dateiname ist versioniert (Err_6.4.5.exe zum Zeitpunkt des Schreibens), und beachten Sie auch, dass die Codedefinitionen auf den Headern zum Zeitpunkt des Bündelns beruhen.8

err.exe-Suchergebnisse nach Kontext wählenerr.exe durchläuft eine große Zahl von Header-Dateien und listet passende Definitionen auf, daher wenn mehrere Kandidaten für dieselbe Zahl erscheinen, nach Kontext wählen, welcher plausibel isterr 5 eingebenEine große Zahl von Headern durchlaufenMehrere Definitionen treffenEinen plausiblen Kandidaten nach Kontext wählen

Abbildung 17: err.exe ist eine headerübergreifende Suche, daher können mehrere Kandidaten erscheinen, und der plausible wird nach Kontext gewählt.

7.2. In Windows eingebaute Befehle

Was Sie ohne Extra-Installation verwenden können, sind certutil und net helpmsg. Die Option -error von certutil zeigt den Nachrichtentext, der einem Fehlercode entspricht, und akzeptiert entweder ein hexadezimales HRESULT oder eine Dezimalzahl.9

certutil -error 0x80070005
certutil -error 5
net helpmsg 5

net helpmsg ist nur für einen Win32-Fehlercode in Dezimal, aber in einer deutschen Umgebung kommt die Nachricht auf Deutsch zurück, daher können Sie sie so für eine Erklärung an den Benutzer verwenden.

Wie unter den Standardbefehlen zu wählenEin dezimaler Win32-Fehlercode lässt sich mit net helpmsg nachschlagen; ein Code, der Hex enthält, einschließlich HRESULT, mit der Option -error von certutilDezimal-Win32Enthält HexDer Code, den Sie haben, ist?net helpmsgcertutil -errorEine deutsche Nachricht kommt zurückAkzeptiert Hex und Dezimal

Abbildung 18: Wie unter den Standardbefehlen zu wählen. Ein dezimaler Win32-Fehler ist net helpmsg; wenn Hex enthalten ist, certutil -error.

7.3. Eine Sammlung von PowerShell-Einzeilern

# Win32 error code → OS message string
[System.ComponentModel.Win32Exception]::new(5).Message
# → Access is denied.

# Negative decimal → hex notation (confirm the identity of an HRESULT)
'0x{0:X8}' -f -2147467259     # 0x80004005

# 0x8007xxxx → the Win32 error code in the low 16 bits
0x80070005 -band 0xFFFF        # 5

# HRESULT → confirm the exception .NET maps
[System.Runtime.InteropServices.Marshal]::GetExceptionForHR(-2147024891)
# → UnauthorizedAccessException (0x80070005)

# Win32 error code → HRESULT (reproduce the wrap)
'0x{0:X8}' -f (0x80070000 -bor 32)   # 0x80070020

7.4. WinDbgs !error

Um während der Abbildanalyse einen Code nachzuschlagen, ist die Erweiterung !error von WinDbg schnell. Standardmäßig interpretiert sie als Win32-Fehlercode; übergeben Sie 1 als zweites Argument und sie interpretiert als NTSTATUS.10

0:000> !error 5
Error code: (Win32) 0x5 (5) - Access is denied.

0:000> !error 0xc0000005 1
Error code: (NTSTATUS) 0xc0000005 - <Access violation>

In einem Absturzabbild zeigt !analyze -v automatisch den Ausnahme-Code (NTSTATUS) an, daher ist der Fluss, die Bedeutung von dort mit !error <code> 1 zu bestätigen.

Fluss, einen Ausnahme-Code in WinDbg zu bestätigenIn einem Absturzabbild zeigt der analyze-Befehl automatisch den Ausnahme-Code an; übergeben Sie diesen Code an die error-Erweiterung mit einem zweiten Argument 1 und bestätigen Sie die Bedeutung als NTSTATUSDas Absturzabbild öffnen!analyze -v ausführenDer Ausnahme-Code wird angezeigtDie Bedeutung mit !error code 1 bestätigen

Abbildung 19: In der Abbildanalyse schlagen Sie den Ausnahme-Code, den !analyze -v angezeigt hat, mit !error und Flag 1 nach.

8. Ein Untersuchungsverfahren — Vom Beurteilen der Schicht zum Abgleichen gegen den Kontext

Stellen Sie das Wissen bisher zu einem Verfahren zusammen, um einen Fehlercode tatsächlich zu untersuchen.

  1. Normalisieren Sie die Schreibweise. Wenn es eine negative Dezimalzahl ist, wandeln Sie sie in 8-stelliges Hex um. Füllen Sie Hex kürzer als 8 Stellen mit Nullen auf und lesen Sie es.
  2. Beurteilen Sie, welche Schicht der Code ist. Wie in der Beurteilungstabelle unten entscheiden die führenden wenigen Stellen es fast.
  3. Zerlegen und den wesentlichen Code herausnehmen. Eine mechanische Operation: die unteren 16 Bit wenn 0x8007xxxx, das N-Bit entfernen wenn 0xDxxxxxxx.
  4. Schlagen Sie den Namen und die Definition mit einem Werkzeug nach. Bestätigen Sie den Symbolnamen und die Nachricht mit err.exe, certutil oder !error.
  5. Gleichen Sie ihn gegen den Kontext ab. Identifizieren Sie, welche App, welcher Vorgang, welche API, gegen was fehlgeschlagen ist, aus dem App-Protokoll, dem Ereignisprotokoll und Procmon. Der Code ist „die Art des Fehlschlags“; der Kontext ist „der Ort der Ursache“.
Verfahren zur Untersuchung eines FehlercodesDas Untersuchungsmuster, die Schreibweise auf Hex auszurichten, die Schicht aus den führenden wenigen Stellen zu beurteilen, zu zerlegen und den wesentlichen Code herauszunehmen, Name und Definition mit einem Werkzeug nachzuschlagen, dann gegen den Kontext abzugleichenDezimal0x80070xC0xDAuf Hex normalisierenFührende Stellen?Als Win32-Fehler lesenUntere 16 Bit → DezimalAls NTSTATUS lesenN-Bit entfernen und lesenName/Definition nachschlagenKontext abgleichen(Procmon)

Abbildung 20: Das Untersuchungsmuster. Normalisieren Sie die Schreibweise, beurteilen Sie die Schicht und zerlegen Sie, schlagen Sie den Namen nach, dann gleichen Sie gegen den Kontext ab.

Erscheinung Erster Kandidat Wie zerlegen und umwandeln
Eine 1- bis 5-stellige Dezimalzahl (5, 1223 und Ähnliches) Win32-Fehlercode So an net helpmsg oder err.exe
Eine negative Dezimalzahl (-2147024891 und Ähnliches) HRESULT In 8-stelliges Hex umwandeln, dann die Beurteilung der Zeilen darunter
0x8007xxxx HRESULT (FACILITY_WIN32) Die unteren 16 Bit ins Dezimal umwandeln und als Win32 lesen
0x8004xxxx HRESULT (FACILITY_ITF) In der Dokumentation der zurückgebenden Komponente nachschlagen
0x8000xxxx HRESULT (FACILITY_NULL) Ein generischer Code wie E_FAIL. Das Gewicht auf eine Kontextuntersuchung verschieben
0xCxxxxxxx NTSTATUS (Fehler) !error <code> 1; bei Bedarf in Win32 umwandeln und lesen
0xDxxxxxxx Eine NTSTATUS-HRESULT-Abbildung Das N-Bit (0x10000000) entfernen und als NTSTATUS lesen
Eine eigene Facility wie 0x8024xxxx Ein HRESULT, das einem Funktionsbereich eigen ist Den Bereich aus dem Facility-Wert identifizieren und zu eigenen Unterlagen gehen (0x8024… ist Windows Update)2

Was in Schritt 5 „gegen den Kontext abgleichen“ besonders wirksam ist, ist die Result-Spalte von Process Monitor. Selbst wenn die App nur „0x80070002“ zeigt, sagt Procmon Ihnen in einer Zeile „welcher Prozess, gegen welchen Pfad, NAME NOT FOUND zurückerhalten hat“. Für das Nachschlagen auf der Ereignisprotokollseite siehe auch „Einführung in Windows-Ereignisprotokoll und ETW“.

9. Häufige Fehllektüren — Muster, die eine Untersuchung den langen Weg schicken

Schließlich Fehllektürmuster, die in tatsächlichen Beratungen auftauchen.

Fehllektüre 1: Denken, 0x80004005 sei „ein Code, der eine bestimmte Ursache anzeigt“

E_FAIL ist „Unspecified failure“, und derselbe Wert erscheint in Windows Update, Netzwerk und Datenbanken. Jede Abhilfe zu versuchen, die erscheint, wenn Sie nach diesem Code suchen, ist fast sicher der lange Weg. Engen Sie nicht vom Code ein, sondern von „welche App, welcher Vorgang, andere Protokolle zur gleichen Zeit“.6

Fehllektüre 2: Nicht bemerken, dass eine negative Dezimalzahl ein HRESULT ist

Ein Fall, ein Protokoll, das „Error -2147467259 occurred“ sagt, so zu suchen, oder von „ein Minus-Fehler?“ verwirrt zu sein. Wenn Sie ein Negatives sehen, wandeln Sie es ins Hexadezimal um. Das allein sagt Ihnen, dass es 0x80004005 (E_FAIL) ist, und verbindet sich mit dem Wissen von Fehllektüre 1.

Fehllektüre 3: Die ganzen 8 Stellen von 0x8007xxxx nachzuschlagen und den darunterliegenden Win32-Fehler nicht anzusehen

Das Wesen von 0x80070005 ist „5 = Zugriff verweigert“. Nach dem Herausnehmen der unteren 16 Bit über „was Win32-Fehler 5 im Kontext dieses Vorgangs bedeutet“ nachzudenken erreicht den Kern schneller als die ganzen 8 Stellen zu suchen.

Fehllektüre 4: Anzunehmen „derselbe Code = dieselbe Ursache“

Wenn Sie einmal „Fehler 5 wurde durch Antivirus verursacht“ hatten, neigen Sie dazu, beim nächsten Fehler 5 zur selben Abhilfe zu springen. Selbst mit demselben Code, wenn die API, die fehlgeschlagen ist, und die Zielressource sich unterscheiden, ist die Ursache ein anderes Ding. Die Bedeutung des Codes zu bestätigen und das Ziel mit Procmon oder ähnlichem zu identifizieren sind ein Satz, jedes Mal.

Fehllektüre 5: Win32-Fehler 5 mit 0xC0000005 und einen STOP-Code mit NTSTATUS zu verwechseln

ERROR_ACCESS_DENIED und STATUS_ACCESS_VIOLATION wegen der „5“-Verbindung als dieselben zu behandeln schickt die Untersuchung in völlig verschiedene Richtungen — ein Berechtigungsproblem gegen einen Programmfehler. Auch ist ein Bluescreen-STOP-Code ein anderes System als NTSTATUS, daher erzeugt 0x9F in einer NTSTATUS-Tabelle nachzuschlagen keine sinnvolle Antwort.14

Fehler 5 und 0xC0000005 haben verschiedene UntersuchungsrichtungenWin32-Fehler 5 sollte als Berechtigungsproblem untersucht werden und NTSTATUS 0xC0000005 als Programmfehler; sie als dieselben zu behandeln schickt die Untersuchung in eine andere RichtungWin32-Fehler 5Ein Berechtigungsproblem untersuchenNTSTATUS 0xC0000005Einen Programmfehler untersuchenUnzusammenhängende Codes verschiedener Systeme

Abbildung 21: Behandeln Sie sie nicht als dieselben wegen der „5“-Verbindung. Fehler 5 geht zu einem Berechtigungsproblem; 0xC0000005 zu einem Programmfehler.

10. Zusammenfassung

  • Windows-Fehlercodes sind eine Dreischichtstruktur aus Win32-Fehlercodes, HRESULT und NTSTATUS. Beurteilen Sie zuerst, welche Schicht, welche Partei den Code zurückgegeben hat.
  • Schreibweisenschwankungen (Dezimal / Hex / negativ) lassen sich mechanisch ausrichten. Wandeln Sie ein Negatives in 8-stelliges Hex um und lesen Sie es dann.
  • HRESULT ist eine Struktur aus S/R/C/N/X-Bits + Facility (11 Bit) + Code (16 Bit), und 0x8007xxxx ist das wichtigste Muster, ein verpackter Win32-Fehler. Wandeln Sie die unteren 16 Bit ins Dezimal um und nehmen Sie den wesentlichen Code heraus.
  • Ein generischer Code wie 0x80004005 (E_FAIL) zeigt keine Ursache an. Die Beurteilung, aufzuhören, in den Code zu graben, und zu einer Kontextuntersuchung zu wechseln, ist gerade deshalb möglich, weil Sie die Struktur kennen.
  • Sie begegnen NTSTATUS als Absturz-Ausnahme-Code oder in der Result-Spalte von Procmon. 0xC0000005 ist eine Zugriffsverletzung, unzusammenhängend mit Win32-Fehler 5. Ein STOP-Code ist noch ein anderes System.
  • In .NET wird ein HRESULT auf einen Ausnahmetyp abgebildet, und der ursprüngliche Wert bleibt in Exception.HResult. In P/Invoke verwenden Sie SetLastError=true und Marshal.GetLastWin32Error als Satz.
  • Die Nachschlagewerkzeuge sind certutil -error und net helpmsg (Standard), err.exe (eine Entwicklungsmaschine), PowerShell-Einzeiler und WinDbgs !error.
  • Das Verfahren ist „die Schreibweise normalisieren → die Schicht beurteilen → zerlegen → den Namen nachschlagen → gegen den Kontext abgleichen“. Was ein Code Ihnen sagt, ist die Art des Fehlschlags; der Ort der Ursache ist, was der Kontext Ihnen sagt.

Das nächste Mal, wenn Sie einem unvertrauten Fehlercode begegnen, schauen Sie auf die führenden wenigen Stellen, bevor Sie ihn in das Suchfeld einfügen. Die unteren 4 Stellen wenn 0x8007, NTSTATUS wenn 0xC, ins Hex umwandeln wenn negativ — diese 10-Sekunden-Zerlegung entscheidet weitgehend die Untersuchungszeit, die folgt.

Weiterführende Artikel

Zugehörige Beratungsfelder

KomuraSoft LLC übernimmt Störungsuntersuchungen, die von einem Fehlercode ausgehen — „ich weiß nicht, was dieser Fehlercode bedeutet“, „0x80070005 erscheint nur in einer bestimmten Umgebung“ —, den Entwurf der Fehlerbehandlung für Apps, die Win32 API, COM und .NET mischen, und das Identifizieren von Ursachen mit Absturzabbildern und Process Monitor. Eine Beratung von einem einzelnen Screenshot eines Fehlerdialogs ist in Ordnung.

Quellen

  1. Microsoft Learn, Debug system error codes. Ein Index zur Liste der Win32-Systemfehlercodes (0–15999); das Holen der Nachricht für einen Code, den GetLastError zurückgibt, mit FormatMessage und dem Flag FORMAT_MESSAGE_FROM_SYSTEM; dass WinINet/WinHTTP-Fehler (die 12000er) in diesem Raum definiert sind; und Untersuchungsmethoden mit Microsoft Error Lookup Tool und dem Befehl !err.  2 3 4 5 6

  2. Microsoft Open Specifications, [MS-ERREF]: HRESULT. Das HRESULT-Bit-Layout (S-, R-, C-, N- und X-Bits, 11-Bit-Facility, 16-Bit-Code); dass das N-Bit einen in den HRESULT-Raum abgebildeten NTSTATUS-Wert anzeigt; und die Liste der Facility-Codes einschließlich FACILITY_WINDOWS_UPDATE (36).  2 3 4 5

  3. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. Das NTSTATUS-Bit-Layout (2-Bit-Sev, C-Bit, N-Bit, 12-Bit-Facility, 16-Bit-Code); und dass Severity sich in vier Arten teilt: Erfolg (00), Information (01), Warnung (10) und Fehler (11).  2 3

  4. Microsoft Learn, HRESULT_FROM_WIN32 macro. Die Definition des winerror.h-Makros, das einen Win32-Systemfehlercode auf einen HRESULT-Wert abbildet.  2 3

  5. Microsoft Learn, Structure of COM Error Codes. Die Rolle des HRESULT-Severity-Bits und des Facility-Felds; die Werte von FACILITY_NULL, FACILITY_RPC, FACILITY_ITF, FACILITY_WIN32 und FACILITY_WINDOWS; und dass ein FACILITY_ITF-Code seine Bedeutung pro Schnittstelle definiert hat und derselbe Wert etwas anderes bedeuten kann.  2 3

  6. Microsoft Learn, Common HRESULT values. Dass E_FAIL (0x80004005) „Unspecified failure“ ist; und Definitionen häufig gesehener HRESULT-Werte wie E_ACCESSDENIED (0x80070005), E_INVALIDARG (0x80070057) und E_OUTOFMEMORY (0x8007000E).  2 3 4

  7. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS values. Die Liste der NTSTATUS-Werte einschließlich STATUS_ACCESS_VIOLATION (0xC0000005), STATUS_DLL_NOT_FOUND (0xC0000135), STATUS_STACK_OVERFLOW (0xC00000FD), STATUS_HEAP_CORRUPTION (0xC0000374) und STATUS_BREAKPOINT (0x80000003).  2 3

  8. Microsoft Learn, The Microsoft Error Lookup Tool. Dass es ein eigenständiges Werkzeug ist, das den Nachrichtentext anzeigt, der einem hexadezimalen Statuscode zugeordnet ist, über verschiedene Header-Dateien wie Winerror.h; dass der Download-Dateiname Err_6.4.5.exe ist; und dass Sie beachten müssen, dass die gebündelten Definitionen zum Kompilierzeitpunkt gelten.  2 3

  9. Microsoft Learn, certutil. Dass die Option -error von certutil den Nachrichtentext anzeigt, der einem Fehlercode zugeordnet ist, und dass eine Fehlerschreibweise, die einen Symbolnamen enthält, in einer Form wie 0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND) verwendet wird.  2

  10. Microsoft Learn, !error. Dass die !error-Erweiterung von WinDbg Win32-, Winsock-, NTSTATUS- und NetAPI-Fehlerwerte dekodiert und anzeigt; und dass das Angeben von 1 als Flag als NTSTATUS interpretiert.  2

  11. Microsoft Learn, How to: Map HRESULTs and exceptions. Der gegenseitige Abbildungsmechanismus zwischen COM-HRESULT und .NET-Ausnahmen; die Entsprechungstabelle wie E_NOTIMPL → NotImplementedException; dass ein HRESULT ohne explizite Abbildung in COMException umgewandelt wird; und dass Ausnahme-Message, Source und Ähnliches aus IErrorInfo-Informationen initialisiert werden.  2

  12. Microsoft Learn, RtlNtStatusToDosError function (winternl.h). Dass es eine Funktion ist, die einen NTSTATUS-Code in den entsprechenden Win32-Systemfehlercode umwandelt; dass ERROR_MR_MID_NOT_FOUND zurückgegeben wird, wenn keine Entsprechung definiert ist; und dass eine Funktion, die die Umkehrung durchführt, nicht existiert.  2

  13. Microsoft Learn, Last-Error Code. Dass der Last-Error-Code pro Thread gehalten wird; dass er mit GetLastError unmittelbar nach dem Fehlschlag geholt werden sollte; dass APIs, die den Code bei Erfolg mit 0 überschreiben, und APIs, die ihn nicht anrühren, gemischt sind; und dass Bit 29 für anwendungsdefinierte Codes reserviert ist.  2

  14. Microsoft Learn, Bug check code reference. Die Liste der Bug-Check-Codes (STOP-Codes), die auf einem Bluescreen angezeigt werden, und wie Informationen über einen Code mit der !analyze-Erweiterung von WinDbg anzuzeigen sind. Dass es ein eigenes Nummerierungssystem ist, getrennt von NTSTATUS, lässt sich aus der Liste bestätigen.  2

  15. Microsoft Learn, Marshal.GetLastWin32Error Method. Dass es ein Weg ist, den Last-Error-Code eines P/Invoke-Aufrufs zu holen, der das Flag SetLastError gesetzt hat; dass GetLastError direkt zu P/Invoken nicht vertrauenswürdig ist wegen Überschreibung durch einen API-Aufruf innerhalb der Laufzeit; und dass ab .NET 6 GetLastPInvokeError empfohlen wird. 

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Was bedeutet der Fehler 0x80004005?
0x80004005 ist der HRESULT E_FAIL und bedeutet "Unspecified failure" (nicht näher bezeichnetes Fehlschlagen). Er zeigt nur an, dass "ein Fehlschlagen aufgetreten ist, das keinen detaillierten Grund berichten kann"; er ist kein Code, der die Ursache selbst darstellt. Derselbe 0x80004005 erscheint deshalb an unzusammenhängenden Stellen — Netzwerk, Windows Update, VBA, ein Datenbanktreiber. Wenn Sie diesen Code sehen, graben Sie nicht in der Bedeutung des Codes; engen Sie die Ursache anhand des Kontexts ein, welche App und welcher Vorgang ihn erzeugt hat, und anhand anderer Fehlerinformationen im Ereignisprotokoll oder in einem detaillierten Protokoll.
Was ist ein negativer Fehlercode wie -2147467259?
Es ist ein 32-Bit-HRESULT, angezeigt als vorzeichenbehaftete Dezimalzahl. Ein HRESULT setzt bei Fehlschlag das höchstwertige Bit, daher ist er als vorzeichenbehaftete Ganzzahl immer negativ. In PowerShell wandelt '0x{0:X8}' -f -2147467259 ihn zurück ins Hexadezimal (in diesem Beispiel 0x80004005 = E_FAIL). Wenn Sie in einem Protokoll oder einer Skriptfehlermeldung eine negative Zahl sehen, die mit -214… beginnt, ist der Standarderstschritt, sie ins Hexadezimal umzuwandeln und dann nachzuschlagen.
Was ist der einfachste Weg, die Bedeutung eines Fehlercodes nachzuschlagen?
Ohne Extra-Installation können Sie an der Eingabeaufforderung net helpmsg 5 (für einen Win32-Fehler in Dezimal) und certutil -error 0x80070005 verwenden. certutil akzeptiert auch ein hexadezimales HRESULT und zeigt den Symbolnamen und den Nachrichtentext. In PowerShell holt [System.ComponentModel.Win32Exception]::new(5).Message die lokalisierte Nachricht. Auf einer Entwicklungsmaschine behalten Sie Microsofts offizielles Nachschlagewerkzeug err.exe (Microsoft Error Lookup Tool); es kann über Win32, HRESULT und NTSTATUS suchen und passende Definitionen auf einmal auflisten.
Was für ein Fehler ist 0xC0000005?
Es ist der NTSTATUS STATUS_ACCESS_VIOLATION, also eine Zugriffsverletzung (ein unzulässiger Speicherzugriff). Es ist der Code, den Sie beim Absturz einer Anwendung am häufigsten als "Exception code" im Ereignisprotokoll oder in einem Absturzabbild sehen, und er zeigt einen Programmfehler an, etwa die Dereferenzierung eines ungültigen Zeigers oder den Zugriff auf bereits freigegebenen Speicher. Er ähnelt namentlich dem Win32-Fehler 5 (ERROR_ACCESS_DENIED = Zugriff verweigert), ist aber ein unzusammenhängender Code eines anderen Systems; verwechseln Sie sie nicht. Der zuverlässige Weg, die Ursache zu identifizieren, ist, ein Absturzabbild zu erfassen und es in WinDbg zu analysieren.
Warum ist die Ursache jedes Mal anders, selbst beim gleichen Fehlercode?
Weil ein Fehlercode nur "welche Art von Fehlschlag" darstellt, und "was fehlgeschlagen ist und warum" vom Aufrufkontext entschieden wird. Fehler 5 (Zugriff verweigert) ist zum Beispiel derselbe Code für völlig verschiedene Ursachen — unzureichende NTFS-Berechtigungen, fehlende Administratorrechte, eine Antivirus-Sperre und so weiter. In einer ähnlichen Lage, wenn ein anderer Prozess die Datei noch offen hat, erhalten Sie einen anderen Code (Fehler 32 = Freigabeverletzung), und den Code richtig zu lesen ändert, wo Sie suchen. Fehler 2 (Datei nicht gefunden) ist oft auch nicht die Hauptdatei, sondern eine abhängige DLL oder eine Einstellungsdatei. Sobald Sie die Bedeutung des Codes nachgeschlagen haben, mit Process Monitor oder ähnlichem zu bestätigen, welche API gegen welche Ressource fehlgeschlagen ist, ist der kurze Weg zur Ursache.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog