Leggere i codici di errore Windows — la struttura a tre strati di Win32, HRESULT e NTSTATUS
· Go Komura · Windows, Codici di errore, HRESULT, NTSTATUS, Win32 API, Risoluzione dei problemi, Debug, Sviluppo Windows
«Lo schermo dell’app ha mostrato l’errore 0x80004005. Cosa significa?» — Nelle consulenze di indagine sugli incidenti, questo tipo di domanda è un classico. Chiunque abbia incollato il numero da una finestra di errore in un motore di ricerca e sia stato accolto da un diluvio di articoli non correlati — un errore di Windows Update, una cartella condivisa che non si connette, un errore di runtime VBA, un errore di connessione al database — e sia diventato più confuso ha molta compagnia.
Succede perché 0x80004005 (E_FAIL) è un codice generico il cui unico significato è «errore non specificato». Lo stesso codice è usato in innumerevoli situazioni, quindi cercare solo il codice non raggiunge la causa. D’altra parte, un codice come 0x80070005 può, se conoscete la struttura, essere scomposto in pochi secondi prima di cercare in «numero di errore Win32 5 = accesso negato, avvolto come HRESULT».
I codici di errore Windows, per ragioni storiche, formano tre strati — codici di errore Win32, HRESULT e NTSTATUS — e vengono convertiti tra gli strati. Una volta che avete quella struttura in testa, potete giudicare da soli «quale strato, quale parte ha restituito questo codice» e «qual è il codice essenziale», e la mossa di apertura di un’indagine diventa molto più veloce.
Destinato al personale IT delle piccole e medie imprese e agli sviluppatori di app Windows, questo articolo organizza come distinguere e scomporre i tre sistemi di codici di errore, la relazione con le eccezioni .NET e la ricerca pratica con err.exe e PowerShell — basato su Microsoft Learn e sulla specifica pubblicata [MS-ERREF] di agosto 2026.
1. Prima la conclusione
- I codici di errore Windows sono soprattutto tre sistemi. Codici di errore Win32 (il piccolo decimale che
GetLastErrorrestituisce), HRESULT (il codice a 32 bit da COM in poi, esadecimale che inizia con 0x8 o un decimale negativo) e NTSTATUS (codici dello strato kernel; gli errori iniziano con 0xC).123 - Decimale ed esadecimale sono notazioni diverse dello stesso codice. «Errore 5», «0x5» e «i 16 bit bassi di 0x80070005» si riferiscono tutti a ERROR_ACCESS_DENIED (accesso negato).1
- 0x8007xxxx è «un errore Win32 avvolto». È un codice di errore Win32 memorizzato in HRESULT FACILITY_WIN32 (7); convertite i 16 bit bassi in decimale e avete il codice essenziale. Questo è il motivo più importante nella lettura dei codici di errore.45
- 0x80004005 (E_FAIL) non è un codice di causa. Significa «Unspecified failure» e non contiene più informazioni. Invece di scavare in questo codice, dovreste cercare il contesto di origine e i registri che lo accompagnano.6
- Un decimale negativo (-2147467259 e simili) è un HRESULT. Il bit più significativo dei 32 bit (il bit di errore) è impostato, quindi una visualizzazione con segno è negativa. Convertitelo in esadecimale e poi leggetelo.2
- Un valore a 8 cifre che inizia con 0xC è un NTSTATUS. 0xC0000005 (violazione di accesso) e 0xC0000135 (DLL non trovata) compaiono di continuo nel registro eventi e nei dump al momento del crash. Non sono correlati al numero di errore Win32 5.7
- Lo stesso codice cambia significato con il contesto. La causa dell’errore 5 va da ACL, elevazione, antivirus, un file tenuto e altro, e il «file non trovato» dell’errore 2 è spesso una DLL dipendente. Leggete sempre il significato del codice insieme a quale API è fallita contro cosa.1
- Gli strumenti di conversione e ricerca sono standard.
certutil -errorenet helpmsgsono integrati in Windows;Win32Exceptiondi PowerShell ottiene il messaggio; su una macchina di sviluppo err.exe (Microsoft Error Lookup Tool); nell’analisi dei dump!errordi WinDbg.8910 - In .NET, un HRESULT è mappato a un tipo di eccezione. Un HRESULT noto va al tipo di eccezione corrispondente (E_ACCESSDENIED → UnauthorizedAccessException e simili); uno sconosciuto diventa COMException; il valore originale resta in
Exception.HResult.11
In una frase, il motivo di un’indagine su un codice di errore Windows è «allineare la notazione all’esadecimale → giudicare di quale strato è il codice → scomporre ed estrarre il codice essenziale → leggerlo insieme al contesto».
2. Windows ha tre sistemi di codici di errore
Prima, la mappa d’insieme. I codici di errore Windows si dividono soprattutto nei tre sistemi seguenti, secondo lo strato che li restituisce.
| Sistema | Parte principale che lo restituisce | Aspetto tipico | Esempio rappresentativo |
|---|---|---|---|
| Codice di errore Win32 | API Win32 (GetLastError), codice di uscita di un comando |
Un piccolo decimale (0–15999) | 5 = ERROR_ACCESS_DENIED |
| HRESULT | Un componente COM, la shell, un installer, molti framework | Esadecimale a 8 cifre che inizia con 0x8, o un decimale negativo | 0x80004005 = E_FAIL |
| NTSTATUS | Il kernel, un driver, un’API nativa (ntdll) | Gli errori sono esadecimali a 8 cifre che iniziano con 0xC | 0xC0000005 = STATUS_ACCESS_VIOLATION |
Storicamente si sono impilati in quest’ordine: codici di errore Win32 che hanno ereditato i numeri di errore MS-DOS, NTSTATUS che il kernel NT usa internamente, e HRESULT progettato all’introduzione di COM per «impacchettare successo/errore e l’origine in 32 bit». Su Windows attuale, un flusso di conversione è quotidiano: il kernel restituisce un NTSTATUS, il sottosistema Win32 lo converte in un codice di errore Win32 e lo strato COM lo avvolge ulteriormente come HRESULT.124
flowchart TB
accTitle: Flusso di conversione tra i tre sistemi
accDescr: Il sottosistema Win32 converte un NTSTATUS restituito dal kernel in un codice di errore Win32, e lo strato COM lo avvolge ulteriormente come HRESULT
kernel["Kernel e driver"] --> nt["NTSTATUS(errori 0xC…)"]
nt -->|Il sottosistema Win32 converte| win["Codice di errore Win32(5 e simili)"]
win -->|Lo strato COM avvolge| hr["HRESULT(0x8007xxxx)"]
Figura 1: Il flusso di conversione tra gli strati. Un NTSTATUS del kernel diventa un errore Win32 e viene ulteriormente avvolto come HRESULT.
2.1. Abituatevi a leggere decimale ed esadecimale in modo intercambiabile
Prima di distinguere i tre sistemi, dovete assorbire l’oscillazione di notazione. Lo stesso codice viene visualizzato come decimale o esadecimale a seconda della situazione.
- «Errore 5», «codice di errore: 0x5» → lo stesso ERROR_ACCESS_DENIED
- «Errore 1223», «0x4C1» → lo stesso ERROR_CANCELLED
- «0x80070005», «-2147024891» → lo stesso HRESULT
In PowerShell la conversione è una riga.
# Decimal → hex
'0x{0:X8}' -f 1223 # 0x000004C1
'0x{0:X8}' -f -2147024891 # 0x80070005 (negative = HRESULT to hex)
# Hex → decimal
0x4C1 # 1223
Quando vedete un decimale negativo che inizia con «-214…», convertitelo per riflesso in esadecimale. Questo da solo taglia molto smarrimento all’ingresso di un’indagine.
flowchart TB
accTitle: Tre apparenze dello stesso codice
accDescr: L'errore decimale 5, l'esadecimale 0x5 e i 16 bit bassi di 0x80070005 si riferiscono tutti allo stesso ERROR_ACCESS_DENIED
d["Notazione decimale: errore 5"] --> same["ERROR_ACCESS_DENIED"]
h["Notazione esadecimale: 0x5"] --> same
l["I 16 bit bassi di 0x80070005"] --> same
same -.-> memo["Notazione diversa, stesso codice"]
Figura 2: Decimale, esadecimale e i 16 bit bassi di un HRESULT sono solo notazioni diverse dello stesso codice.
3. Codici di errore Win32 — GetLastError e FORMAT_MESSAGE
3.1. Comportamento di base di GetLastError
Molte API Win32 come CreateFile e RegOpenKeyEx indicano l’errore con il valore di ritorno (FALSE, NULL, INVALID_HANDLE_VALUE e simili) e memorizzano il codice di errore dettagliato in un «last-error code» tenuto per thread. Il chiamante lo recupera con GetLastError immediatamente dopo aver confermato l’errore.13
Ci sono due avvertenze pratiche.13
- Leggetelo immediatamente dopo l’errore. Se inserite un’altra chiamata API (una funzione di registrazione, per esempio) in mezzo, quella chiamata può sovrascrivere il last-error code.
- Non fate affidamento sul valore in caso di successo. Alcune API azzerano il last-error code a 0 in caso di successo; alcune non lo toccano. La regola è confermare l’errore dal valore di ritorno e poi leggere.
sequenceDiagram
accTitle: Leggere GetLastError subito dopo l'errore
accDescr: Dopo aver confermato l'errore dal valore di ritorno, recuperare il last-error code con GetLastError immediatamente, senza inserire un'altra chiamata API
participant app as App
participant api as Win32 API
app->>api: Chiamata CreateFile
api-->>app: Valore di ritorno di errore
app->>api: GetLastError
api-->>app: Codice 5
Note over app: Inserire un'altra API in mezzo può sovrascriverlo
Figura 3: Leggete il last-error code immediatamente dopo l’errore. Inserire un’altra chiamata API in mezzo può sovrascriverlo.
Per ottenere una stringa di messaggio da un codice, usate FormatMessage con il 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);
}
Lasciare sia il decimale sia l’esadecimale e il testo del messaggio nel registro della vostra app, come qui, rende un’indagine successiva un passo più veloce.
flowchart TB
accTitle: Cercare un messaggio da un codice e lasciarlo nel registro
accDescr: Specificare il flag FORMAT_MESSAGE_FROM_SYSTEM a FormatMessage per ottenere la stringa di messaggio del codice di errore, e lasciare decimale, esadecimale e il testo del messaggio nel registro
code["Codice di errore(esempio: 5)"] --> fm["Ottenere la stringa con FormatMessage"]
fm --> msg["Testo del messaggio"]
msg --> log["Registrare nel log"]
log -.-> both["Scrivere decimale, esadecimale e testo insieme"]
Figura 4: Convertite un codice di errore in una stringa di messaggio con FormatMessage e lasciate decimale, esadecimale e il testo insieme nel registro.
3.2. Codici rappresentativi che compaiono di continuo sul campo
I codici di errore Win32 sono definiti nell’intervallo 0–15999 e Microsoft Learn ha un elenco completo.1 Tra di essi, i volti che incontrate di continuo nell’indagine sugli incidenti sono i seguenti.
| Decimale | Hex | Simbolo | Significato |
|---|---|---|---|
| 2 | 0x2 | ERROR_FILE_NOT_FOUND | Il file specificato non è stato trovato |
| 3 | 0x3 | ERROR_PATH_NOT_FOUND | Il percorso specificato non è stato trovato |
| 5 | 0x5 | ERROR_ACCESS_DENIED | L’accesso è stato negato |
| 32 | 0x20 | ERROR_SHARING_VIOLATION | Un altro processo lo sta usando e l’accesso non è possibile |
| 87 | 0x57 | ERROR_INVALID_PARAMETER | Il parametro non è corretto |
| 122 | 0x7A | ERROR_INSUFFICIENT_BUFFER | Il buffer passato è troppo piccolo |
| 998 | 0x3E6 | ERROR_NOACCESS | Accesso non valido a una posizione di memoria |
| 1223 | 0x4C1 | ERROR_CANCELLED | L’operazione è stata annullata dall’utente |
Di questi, 998 (ERROR_NOACCESS) non è «accesso negato» ma l’espressione Win32 di una violazione di accesso alla memoria, la forma dell’NTSTATUS STATUS_ACCESS_VIOLATION discusso più avanti dopo la conversione allo strato Win32. Attenzione alla confusione con il numero 5. Anche 1223 (ERROR_CANCELLED) è un codice che compare quando l’utente sceglie «No» in una finestra di elevazione UAC, per esempio — più «è stato annullato» che un errore.
flowchart TB
accTitle: Gli errori 998 e 5 sono cose diverse
accDescr: 998 è una violazione di accesso alla memoria, una violazione di accesso NTSTATUS convertita nello strato Win32, e differisce da 5 che rappresenta accesso negato
nt["NTSTATUS 0xC0000005"] -->|Convertito nello strato Win32| e998["Errore 998(ERROR_NOACCESS)"]
e998 -.-> m1["Il significato è una violazione di accesso alla memoria"]
e5["Errore 5(accesso negato)"] -.-> m2["Un problema di autorizzazioni. Una cosa diversa da 998"]
Figura 5: L’errore 998 è una violazione di accesso NTSTATUS convertita nello strato Win32, una cosa diversa dall’accesso negato 5.
3.3. Lo stesso codice cambia significato con il contesto
Più importante che memorizzare la tabella dei codici rappresentativi è il senso che un codice di errore vi dice solo «il tipo di errore».
- Errore 5 (accesso negato): i candidati alla causa vanno ampiamente — ACL NTFS insufficiente, scrivere un’area protetta senza privilegi di amministratore, un blocco da antivirus o AppLocker, privilegi insufficienti di un account di servizio e così via.
- Errore 2 (file non trovato): non è necessariamente il file che l’utente ha specificato. Una DLL dipendente che l’EXE ha tentato di caricare implicitamente, un file di impostazioni visto nel posto sbagliato per la redirezione del registro (32 bit/64 bit), un percorso la cui espansione di variabile d’ambiente è fallita — «quale file» non è stato trovato non è visibile dal codice.
- Errore 32 (violazione di condivisione): «quale processo lo tiene» è la vera domanda, ma il codice non ve lo dice.
flowchart TB
accTitle: La causa dell'errore 5 è decisa dal contesto
accDescr: Anche lo stesso accesso negato ha diversi candidati di causa come ACL insufficiente o privilegi di amministratore mancanti, e dovete identificare quale API è fallita contro cosa
e5["Errore 5(accesso negato)"] --> c1["ACL insufficiente"]
e5 --> c2["Senza privilegi admin"]
e5 --> c3["Blocco da prodotto di sicurezza"]
e5 --> c4["Privilegi di servizio bassi"]
c1 --> next["Procmon: destinazione fallita"]
c2 --> next
c3 --> next
c4 --> next
Figura 6: Un codice vi dice solo «il tipo di errore». L’errore 5 ha diversi candidati di causa e identificare la destinazione è richiesto.
Lo strumento che misura «quale API, contro quale nome di oggetto, ha restituito quale risultato» è Process Monitor. Come usarlo è trattato in dettaglio in «Guida pratica a Process Monitor (ProcMon)». Cercare il significato di un codice di errore e identificare la destinazione che è fallita sono due ruote dello stesso carro.
4. HRESULT — Leggere la struttura impacchettata in 32 bit
4.1. Layout dei bit
HRESULT è un formato che impacchetta successo/errore, origine e un codice di dettaglio in un singolo valore a 32 bit. La specifica pubblicata [MS-ERREF] lo definisce con il layout seguente.2
| Posizione del bit | Nome | Significato |
|---|---|---|
| 31 | S | Severity. 0 = successo, 1 = errore |
| 30 | R | Riservato (parte della severity quando si mappa NTSTATUS) |
| 29 | C | Bit Customer. 1 significa un codice definito da qualcuno diverso da Microsoft |
| 28 | N | 1 significa un valore NTSTATUS mappato nello spazio HRESULT |
| 27 | X | Riservato (0) |
| 26–16 | Facility | Un codice di facility che indica l’origine (11 bit) |
| 15–0 | Code | Un codice di dettaglio all’interno della facility (16 bit) |
Il bit S più significativo è 1, cioè un HRESULT la cui notazione esadecimale inizia a 0x8 o sopra è un errore. Visualizzarlo come intero a 32 bit con segno lo rende negativo — questa è l’identità del «-214…» menzionato prima.
flowchart TB
accTitle: La relazione tra il bit S e una visualizzazione negativa
accDescr: Un HRESULT di errore ha il bit S più significativo impostato a 1, quindi in esadecimale inizia a 0x8 o sopra, e come intero a 32 bit con segno è negativo
s["Bit S = 1(errore)"] --> hex["L'esadecimale inizia a 0x8 o sopra"]
hex --> neg["Una visualizzazione con segno è negativa"]
neg --> back["Quando vedete un negativo, convertite in esadecimale e leggete"]
Figura 7: Un HRESULT di errore inizia a 0x8 o sopra perché il bit S è 1, e una visualizzazione con segno è negativa.
I valori Facility rappresentativi sono i seguenti.5
| Facility | Valore | Aspetto esadecimale | Significato |
|---|---|---|---|
| FACILITY_NULL | 0 | 0x8000xxxx | Codici ampiamente comuni (E_FAIL, E_UNEXPECTED e simili) |
| FACILITY_RPC | 1 | 0x8001xxxx | Origine RPC |
| FACILITY_ITF | 4 | 0x8004xxxx | Un errore definito dall’interfaccia (il significato dipende dall’interfaccia) |
| FACILITY_WIN32 | 7 | 0x8007xxxx | Un codice di errore Win32 avvolto |
| FACILITY_WINDOWS | 8 | 0x8008xxxx | Interfacce Microsoft aggiuntive |
4.2. Scomporre 0x80004005 e 0x80070005
Scomponiamoli davvero.
Per 0x80004005: S=1 (errore), Facility=(0x80004005 » 16) & 0x7FF = 0 (FACILITY_NULL), Code=0x4005. Un codice FACILITY_NULL generico, definito come E_FAIL «Unspecified failure».6 In altre parole questo codice contiene solo il significato «un errore che non può riportare il dettaglio». Quando vedete 0x80004005, smettete di scavare nel codice stesso lì, e spostate il peso dell’indagine su «quale componente lo ha restituito» e «c’è dettaglio nel registro eventi o nel registro dell’app nello stesso momento».
Per 0x80070005: S=1, Facility=7 (FACILITY_WIN32), Code=0x0005=5. Potete vedere che è il numero di errore Win32 5 (ERROR_ACCESS_DENIED) avvolto come HRESULT. L’alias E_ACCESSDENIED è, in sostanza, questo valore.6
Anche per lo stesso «accesso negato», 0x80070005 è un avvolgimento di un errore concreto avvenuto allo strato Win32, e la quantità di informazione è del tutto diversa da 0x80004005.
flowchart TB
accTitle: Scomposizione di 0x80004005 e 0x80070005
accDescr: 0x80004005 è il codice FACILITY_NULL generico E_FAIL, non contiene dettaglio e deve passare a un'indagine di contesto; 0x80070005 è FACILITY_WIN32 e si vede come avvolgimento del numero di errore Win32 5, accesso negato
a["0x80004005"] --> af["Facility=0(FACILITY_NULL)"]
af --> ac["Code=0x4005 → E_FAIL"]
ac --> ax["Errore non specificato. Verso un'indagine di contesto"]
b["0x80070005"] --> bf["Facility=7(FACILITY_WIN32)"]
bf --> bc["Code=0x0005 → 5"]
bc --> bx["ERROR_ACCESS_DENIED"]
Figura 8: Anche lo stesso «errore» ha una quantità di informazione diversa una volta scomposto. 0x80070005 si può percorrere fino al numero di errore Win32 5.
4.3. Il motivo più importante: 0x8007xxxx = HRESULT_FROM_WIN32
Per trasmettere un errore da uno strato inferiore che può restituire solo un codice di errore Win32 a uno strato superiore che restituisce HRESULT (un metodo COM o il runtime .NET), winerror.h fornisce la macro HRESULT_FROM_WIN32.4 Il comportamento è «memorizzare il codice di errore Win32 nei 16 bit bassi, impostare Facility a FACILITY_WIN32 (7) e impostare il bit S a 1».
flowchart TB
accTitle: Come funziona HRESULT_FROM_WIN32
accDescr: Memorizzare il codice di errore Win32 nei 16 bit bassi, impostare Facility a 7 e il bit S a 1, e assemblare un HRESULT 0x8007xxxx
win["Codice di errore Win32(esempio: 5)"] --> low["Memorizzare nei 16 bit bassi"]
low --> fac["Impostare Facility a 7"]
fac --> sbit["Impostare il bit S a 1"]
sbit --> hr["0x80070005"]
Figura 9: HRESULT_FROM_WIN32 memorizza l’errore Win32 nei 16 bit bassi e imposta Facility=7 e il bit S.
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)
Per leggere nell’altro senso, prendete i 16 bit bassi in PowerShell.
0x80070005 -band 0xFFFF # 5 → ERROR_ACCESS_DENIED
0x80072EE7 -band 0xFFFF # 12007 → ERROR_INTERNET_NAME_NOT_RESOLVED (WinINet)
Come nel secondo esempio, gli errori WinINet e WinHTTP (i 12000) sono anche definiti nello spazio dei codici di errore Win321, quindi un 0x8007xxxx di rete si può scomporre con la stessa procedura. Mettere nella memoria muscolare «quando vedete 0x8007, convertite le 4 cifre basse in decimale» è la competenza pratica numero uno che questo articolo vorrebbe che portaste a casa.
C’è l’avvertenza opposta per 0x8004xxxx (FACILITY_ITF). Un codice FACILITY_ITF ha una parte diversa che definisce il significato per interfaccia, quindi lo stesso valore a 32 bit può significare qualcosa di diverso se la parte che lo ha restituito è diversa.5 Per un 0x8004xxxx non familiare, cercatelo non in una ricerca generica ma nella documentazione del componente che lo ha restituito (una libreria, un SDK di driver, un prodotto server).
flowchart TB
accTitle: Come cercate cambia tra 0x8007 e 0x8004
accDescr: Un 0x8007xxxx FACILITY_WIN32 si legge scomponendo meccanicamente i 16 bit bassi, ma un 0x8004xxxx FACILITY_ITF ha una parte diversa che definisce il significato per interfaccia, quindi cercatelo nei materiali del componente che lo ha restituito
hr{"Facility è?"} -->|7, WIN32| w["Convertire i 16 bit bassi in decimale"]
hr -->|4, ITF| i["Il significato differisce secondo chi lo ha restituito"]
w --> ww["Leggerlo come errore Win32"]
i --> ii["Cercarlo nei materiali di chi lo ha restituito"]
Figura 10: 0x8007xxxx si scompone meccanicamente; 0x8004xxxx si cerca nei materiali del componente che lo ha restituito.
5. NTSTATUS — Codici dello strato kernel e il mondo dei crash
5.1. Layout e Severity
NTSTATUS è un codice a 32 bit usato dal kernel, dai driver di dispositivo e dalle API native ntdll, e il suo layout è simile a HRESULT senza essere lo stesso.3
| Posizione del bit | Nome | Significato |
|---|---|---|
| 31–30 | Sev | Severity. 00 = successo, 01 = informativo, 10 = avviso, 11 = errore |
| 29 | C | Bit Customer |
| 28 | N | Riservato (0, così è possibile una mappa verso HRESULT) |
| 27–16 | Facility | Facility (12 bit) |
| 15–0 | Code | Codice di dettaglio |
Poiché la severity è a 2 bit, potete leggere il tipo dalla cifra esadecimale iniziale. 0xC… è un errore (11), 0x8… un avviso (10), 0x4… informativo (01), 0x0–0x3… successo. L’eccezione di breakpoint 0x80000003 (STATUS_BREAKPOINT) è un esempio rappresentativo di «un avviso, non un errore».37
flowchart TB
accTitle: Un NTSTATUS si legge per tipo dalla cifra iniziale
accDescr: Poiché la severity è a 2 bit, un NTSTATUS si legge come errore se la cifra esadecimale iniziale è 0xC, avviso se 0x8, informativo se 0x4 e successo se da 0x0 a 0x3
head{"La cifra esadecimale iniziale è?"} -->|0xC| e["Errore"]
head -->|0x8| w["Avviso"]
head -->|0x4| i["Informativo"]
head -->|0x0–0x3| s["Successo"]
w -.-> ex["Esempio: 0x80000003 è un avviso"]
Figura 11: Un NTSTATUS si legge per tipo dalla cifra esadecimale iniziale. 0x80000003 è «un avviso, non un errore».
5.2. Dove lo incontrate — codici di eccezione, codici STOP e il registro eventi
Le situazioni in cui il personale IT e gli sviluppatori incontrano NTSTATUS sono soprattutto legate ai crash.
- Un codice di eccezione di crash dell’applicazione: l’«Exception code: 0xc0000005» registrato nel registro eventi «Errore applicazione (ID evento 1000)» è un NTSTATUS. I valori rappresentativi sono i seguenti.7
| Valore | Simbolo | Significato |
|---|---|---|
| 0xC0000005 | STATUS_ACCESS_VIOLATION | Violazione di accesso (un accesso alla memoria illegale) |
| 0xC0000135 | STATUS_DLL_NOT_FOUND | Una DLL richiesta non è stata trovata e non può avviarsi |
| 0xC00000FD | STATUS_STACK_OVERFLOW | Overflow dello stack |
| 0xC0000374 | STATUS_HEAP_CORRUPTION | Corruzione dell’heap |
- Un codice STOP della schermata blu: sembrano simili a prima vista, ma un codice STOP (bug check code) è un sistema di numerazione proprio, distinto da NTSTATUS, come 0x0000009F (DRIVER_POWER_STATE_FAILURE), e ha un riferimento dedicato.14 Ricordare solo la distinzione «0xC0000005 è NTSTATUS; STOP 0x9F è un bug check code e non dovete cercarlo in una tabella NTSTATUS» basta.
- La colonna Result di Process Monitor: NAME NOT FOUND e ACCESS DENIED nella colonna Result di Procmon sono nomi di visualizzazione dell’NTSTATUS che il kernel ha restituito (STATUS_OBJECT_NAME_NOT_FOUND, STATUS_ACCESS_DENIED). È anche un posto in cui potete sentire la corrispondenza degli strati: osservare un errore di I/O file nel vocabolario NTSTATUS e che quell’errore viene convertito in un errore Win32 e arriva all’app.
flowchart TB
accTitle: Distinguere un codice di eccezione da un codice STOP
accDescr: Leggere un codice di eccezione del registro eventi come NTSTATUS; cercare un codice STOP della schermata blu nel riferimento dedicato dei bug-check code, un sistema diverso
q{"Dove è comparso il codice?"} -->|Codice di eccezione| nt["Leggerlo come NTSTATUS"]
q -->|Codice STOP| bc["Cercarlo nella tabella dei bug-check"]
nt -.-> n1["Esempio: 0xC0000005"]
bc -.-> b1["Esempio: 0x0000009F"]
Figura 12: Un codice di eccezione del registro eventi è un NTSTATUS; un codice STOP della schermata blu è un sistema diverso. Non cercateli nella tabella sbagliata.
L’indagine oltre il codice di eccezione, cioè catturare e analizzare un dump di crash, è trattata in «Introduzione alla raccolta di crash dump Windows» e «Leggere un crash dump con WinDbg + SOS».
5.3. La relazione con HRESULT — il bit N e RtlNtStatusToDosError
Il ponte tra NTSTATUS e gli altri due strati ha due percorsi.
- Una mappa nello spazio HRESULT: impostare il bit N HRESULT (0x10000000) porta un valore NTSTATUS così com’è nello spazio HRESULT (la macro HRESULT_FROM_NT in winerror.h). Mappare 0xC0000005 diventa 0xD0000005, per esempio. Quando vedete un HRESULT che inizia con 0xD, la procedura corretta è togliere il bit N e leggerlo come NTSTATUS.2
- Conversione in un codice di errore Win32:
RtlNtStatusToDosErrordi ntdll converte un NTSTATUS nel codice di errore Win32 corrispondente. Un valore senza corrispondenza definita diventa ERROR_MR_MID_NOT_FOUND.12 Per esempio STATUS_ACCESS_VIOLATION (0xC0000005) viene convertito in ERROR_NOACCESS (998) e STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034) in ERROR_FILE_NOT_FOUND (2). È anche utile ricordare che il vocabolario ricco del kernel a volte viene arrotondato a una distinzione più grossolana allo strato Win32.
flowchart TB
accTitle: Due ponti da NTSTATUS agli altri strati
accDescr: Un NTSTATUS viene passato agli altri strati in due modi: mappato nello spazio HRESULT impostando il bit N, e convertito in un codice di errore Win32 da RtlNtStatusToDosError
nt["NTSTATUS(0xC0000005)"] -->|Impostare il bit N| hr["HRESULT(0xD0000005)"]
nt -->|RtlNtStatusToDosError| win["Errore Win32 998(ERROR_NOACCESS)"]
win -.-> memo["ERROR_MR_MID_NOT_FOUND se non c'è corrispondenza"]
Figura 13: Ci sono due ponti NTSTATUS. Un inizio 0xD si legge come NTSTATUS dopo aver tolto il bit N.
6. COM e .NET — Come un codice di errore viene mappato a un’eccezione
6.1. Lo stile COM — HRESULT + IErrorInfo
Un metodo COM restituisce fondamentalmente HRESULT, ma c’è un limite a ciò che si può impacchettare in 32 bit, quindi come complemento il meccanismo IErrorInfo può trasmettere una stringa di descrizione dell’errore e l’origine separatamente. In C++, la classe _com_error supportata dal compilatore gestisce HRESULT e IErrorInfo insieme. Un’app la cui finestra di errore mostra «codice + descrizione» spesso porta la descrizione attraverso questo meccanismo.
flowchart TB
accTitle: IErrorInfo che integra HRESULT
accDescr: C'è un limite a ciò che si può impacchettare in un HRESULT a 32 bit, quindi una stringa di descrizione dell'errore e l'origine vengono trasmesse separatamente con IErrorInfo, e in C++ la classe _com_error le gestisce insieme
hr["HRESULT(solo 32 bit)"] --> lim["C'è un limite a ciò che si impacchetta"]
lim --> ei["IErrorInfo porta la descrizione"]
ei --> ce["_com_error le gestisce insieme"]
ce -.-> dlg["Il codice + descrizione della finestra"]
Figura 14: Una stringa di descrizione che non sta in un HRESULT a 32 bit è portata separatamente da IErrorInfo.
6.2. Lo stile .NET — da un HRESULT a un tipo di eccezione
Quando il runtime .NET riceve un errore HRESULT in interop COM, lo converte in un’eccezione. Un HRESULT noto è mappato al tipo di eccezione corrispondente; uno sconosciuto diventa COMException.11
flowchart TB
accTitle: Mappatura da HRESULT a un'eccezione .NET
accDescr: Un HRESULT di errore ricevuto in interop COM viene convertito nel tipo di eccezione corrispondente se noto, o in COMException se sconosciuto, e in entrambi i casi il valore originale è tenuto in Exception.HResult
hr["HRESULT di errore"] --> known{"Una mappatura nota?"}
known -->|Yes| typed["Convertire nel tipo di eccezione corrispondente"]
known -->|No| comex["Convertire in COMException"]
typed --> keep["Il valore originale resta in Exception.HResult"]
comex --> keep
Figura 15: .NET mappa un HRESULT a un tipo di eccezione e il valore originale resta in Exception.HResult su ogni eccezione.
| HRESULT | Tipo di eccezione .NET |
|---|---|
| E_ACCESSDENIED (0x80070005) | UnauthorizedAccessException |
| E_OUTOFMEMORY (0x8007000E) | OutOfMemoryException |
| E_INVALIDARG (0x80070057) | ArgumentException |
| E_NOTIMPL (0x80004001) | NotImplementedException |
| Un valore senza mappatura definita | COMException (il valore originale nella proprietà ErrorCode) |
Su ogni eccezione, l’HRESULT originale è tenuto nella proprietà Exception.HResult. Un ramo nella gestione delle eccezioni di I/O file come «riprovare solo su una violazione di condivisione» si può scrivere con questo valore.
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 e GetLastError
Quando chiamate un’API Win32 direttamente tramite P/Invoke, specificate SetLastError = true su DllImport (o LibraryImport), poi recuperate con Marshal.GetLastWin32Error (da .NET 6, l’equivalente GetLastPInvokeError). Definire GetLastError stesso come P/Invoke e chiamarlo è inesatto, perché una chiamata API all’interno del runtime può sovrascrivere il valore.15
flowchart TB
accTitle: Recuperare l'ultimo errore in P/Invoke
accDescr: Specificare SetLastError come true e recuperare con Marshal.GetLastWin32Error è corretto; P/Invocare GetLastError direttamente è inesatto per una sovrascrittura del runtime
pi["Chiamare un'API Win32 via P/Invoke"] --> ok["Specificare SetLastError=true"]
ok --> get["Recuperare con GetLastWin32Error"]
pi --> ng["Una definizione che chiama GetLastError direttamente"]
ng --> bad["Il runtime lo sovrascrive ed è inesatto"]
Figura 16: In P/Invoke usate SetLastError=true e Marshal.GetLastWin32Error come coppia. Chiamare GetLastError direttamente è inesatto.
[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 cerca la stringa di messaggio del sistema operativo da un codice di errore Win32, quindi potete usarla così com’è per lasciare sia il codice sia il messaggio in un registro. La domanda di progettazione di a quale strato catturare un’eccezione e come lasciarla in un registro è trattata in «Dove devono stare catch e il logging nella gestione delle eccezioni?».
7. Strumenti di conversione e indagine in pratica — Una guida rapida da copiare
7.1. err.exe (Microsoft Error Lookup Tool)
Uno strumento autonomo di ricerca errori distribuito da Microsoft. Percorre un gran numero di file header come winerror.h e ntstatus.h ed elenca definizioni e messaggi che corrispondono al codice specificato.8
err 0x80070005
err 5
err 0xC0000005
Un singolo numero può colpire in diversi header (per esempio «5» corrisponde a definizioni in vari posti oltre a Win32 ERROR_ACCESS_DENIED), quindi quale dei candidati è plausibile deve essere scelto dal contesto. Il nome del file di download è versionato (Err_6.4.5.exe al momento della stesura) e notate anche che le definizioni dei codici si basano sugli header al momento in cui sono stati impacchettati.8
flowchart TB
accTitle: Scegliere i risultati di ricerca di err.exe dal contesto
accDescr: err.exe percorre un gran numero di file header ed elenca le definizioni corrispondenti, quindi quando compaiono diversi candidati per lo stesso numero, scegliete quale è plausibile dal contesto
in["Immettere err 5"] --> scan["Percorrere molti header"]
scan --> hits["Diverse definizioni colpiscono"]
hits --> pick["Scegliere un candidato plausibile dal contesto"]
Figura 17: err.exe è una ricerca trasversale agli header, quindi possono comparire diversi candidati e quello plausibile si sceglie dal contesto.
7.2. Comandi integrati in Windows
Quello che potete usare senza installazioni extra sono certutil e net helpmsg. L’opzione -error di certutil mostra il testo del messaggio che corrisponde a un codice di errore e accetta sia un HRESULT esadecimale sia un decimale.9
certutil -error 0x80070005
certutil -error 5
net helpmsg 5
net helpmsg è solo per un codice di errore Win32 in decimale, ma in un ambiente italiano il messaggio torna in italiano, quindi potete usarlo così per una spiegazione all’utente.
flowchart TB
accTitle: Come scegliere tra i comandi standard
accDescr: Un codice di errore Win32 decimale si cerca con net helpmsg; un codice che include esadecimale, compreso HRESULT, si cerca con l'opzione -error di certutil
q{"Il codice che avete è?"} -->|Win32 decimale| net["net helpmsg"]
q -->|Include esadecimale| cert["certutil -error"]
net -.-> jp["Torna un messaggio italiano"]
cert -.-> any["Accetta esadecimale e decimale"]
Figura 18: Come scegliere tra i comandi standard. Un errore Win32 decimale è net helpmsg; se include esadecimale, certutil -error.
7.3. Una raccolta di one-liner PowerShell
# 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. !error di WinDbg
Per cercare un codice durante l’analisi di un dump, l’estensione !error di WinDbg è rapida. Per impostazione predefinita interpreta come codice di errore Win32; passate 1 come secondo argomento e interpreta come 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 un dump di crash, !analyze -v mostra automaticamente il codice di eccezione (NTSTATUS), quindi il flusso è confermare il significato da lì con !error <code> 1.
flowchart TB
accTitle: Flusso per confermare un codice di eccezione in WinDbg
accDescr: In un dump di crash il comando analyze mostra automaticamente il codice di eccezione; passate quel codice all'estensione error con un secondo argomento 1 e confermate il significato come NTSTATUS
dump["Aprire il dump di crash"] --> an["Eseguire !analyze -v"]
an --> exc["Il codice di eccezione viene mostrato"]
exc --> chk["Confermare il significato con !error code 1"]
Figura 19: Nell’analisi dei dump, cercate il codice di eccezione che !analyze -v ha mostrato con !error e il flag 1.
8. Una procedura di indagine — Dal giudicare lo strato all’abbinare al contesto
Riunite le conoscenze fin qui in una procedura per indagare davvero un codice di errore.
- Normalizzate la notazione. Se è un decimale negativo, convertitelo in esadecimale a 8 cifre. Completate con zeri un esadecimale più corto di 8 cifre e leggetelo.
- Giudicate di quale strato è il codice. Come nella tabella di giudizio sotto, le prime poche cifre lo decidono quasi.
- Scomponete ed estraete il codice essenziale. Un’operazione meccanica: i 16 bit bassi se 0x8007xxxx, togliere il bit N se 0xDxxxxxxx.
- Cercate il nome e la definizione con uno strumento. Confermate il nome del simbolo e il messaggio con err.exe, certutil o
!error. - Abbinatelo al contesto. Identificate quale app, quale operazione, quale API, è fallita contro cosa, dal registro dell’app, dal registro eventi e da Procmon. Il codice è «il tipo di errore»; il contesto è «il luogo della causa».
flowchart TB
accTitle: Procedura per indagare un codice di errore
accDescr: Il motivo di indagine di allineare la notazione all'esadecimale, giudicare lo strato dalle prime poche cifre, scomporre ed estrarre il codice essenziale, cercare nome e definizione con uno strumento, poi abbinare al contesto
fix["Normalizzare in esadecimale"] --> judge{"Cifre iniziali?"}
judge -->|Decimale| d1["Leggere come errore Win32"]
judge -->|0x8007| d2["16 bit bassi → decimale"]
judge -->|0xC| d3["Leggere come NTSTATUS"]
judge -->|0xD| d4["Togliere il bit N e leggere"]
d1 --> tool["Cercare nome/definizione"]
d2 --> tool
d3 --> tool
d4 --> tool
tool --> ctx["Abbinare il contesto(Procmon)"]
Figura 20: Il motivo di indagine. Normalizzate la notazione, giudicate lo strato e scomponete, cercate il nome, poi abbinate al contesto.
| Aspetto | Primo candidato | Come scomporre e convertire |
|---|---|---|
| Un decimale da 1 a 5 cifre (5, 1223 e simili) | Codice di errore Win32 | Così com’è a net helpmsg o err.exe |
| Un decimale negativo (-2147024891 e simili) | HRESULT | Convertire in esadecimale a 8 cifre, poi il giudizio delle righe sotto |
| 0x8007xxxx | HRESULT (FACILITY_WIN32) | Convertire i 16 bit bassi in decimale e leggere come Win32 |
| 0x8004xxxx | HRESULT (FACILITY_ITF) | Cercarlo nella documentazione del componente che lo ha restituito |
| 0x8000xxxx | HRESULT (FACILITY_NULL) | Un codice generico come E_FAIL. Spostare il peso a un’indagine di contesto |
| 0xCxxxxxxx | NTSTATUS (errore) | !error <code> 1; convertire in Win32 e leggere se serve |
| 0xDxxxxxxx | Una mappa HRESULT di un NTSTATUS | Togliere il bit N (0x10000000) e leggere come NTSTATUS |
| Una facility propria come 0x8024xxxx | Un HRESULT specifico di un’area di funzionalità | Identificare l’area dal valore Facility e andare ai materiali dedicati (0x8024… è Windows Update)2 |
Ciò che è particolarmente efficace nel passo 5 «abbinare al contesto» è la colonna Result di Process Monitor. Anche se l’app mostra solo «0x80070002», Procmon vi dice in una riga «quale processo, contro quale percorso, ha ricevuto NAME NOT FOUND». Per cercare dal lato del registro eventi, vedete anche «Introduzione al registro eventi di Windows e a ETW».
9. Letture errate comuni — Motivi che mandano un’indagine per la strada lunga
Infine, motivi di lettura errata che compaiono nelle consulenze reali.
Lettura errata 1: Pensare che 0x80004005 sia «un codice che indica una causa specifica»
E_FAIL è «Unspecified failure» e lo stesso valore compare in Windows Update, rete e database. Provare ogni rimedio che compare quando cercate su questo codice è quasi certamente la strada lunga. Restringete non dal codice ma da «quale app, quale operazione, altri registri nello stesso momento».6
Lettura errata 2: Non notare che un decimale negativo è un HRESULT
Un caso di cercare così com’è un registro che dice «Error -2147467259 occurred», o di essere confusi da «un errore meno?». Quando vedete un negativo, convertitelo in esadecimale. Questo da solo vi dice che è 0x80004005 (E_FAIL) e si collega alla conoscenza della lettura errata 1.
Lettura errata 3: Cercare tutte le 8 cifre di 0x8007xxxx e non guardare l’errore Win32 sottostante
L’essenza di 0x80070005 è «5 = accesso negato». Pensare a «cosa significa l’errore Win32 5 nel contesto di questa operazione» dopo aver estratto i 16 bit bassi raggiunge il nucleo più in fretta che cercare tutte le 8 cifre.
Lettura errata 4: Assumere «lo stesso codice = la stessa causa»
Se una volta avete avuto «l’errore 5 era causato dall’antivirus», tendete a saltare allo stesso rimedio al prossimo errore 5. Anche con lo stesso codice, se l’API che è fallita e la risorsa di destinazione differiscono, la causa è un’altra cosa. Confermare il significato del codice e identificare la destinazione con Procmon o simile sono un insieme, ogni volta.
Lettura errata 5: Confondere l’errore Win32 5 con 0xC0000005 e un codice STOP con NTSTATUS
Trattare ERROR_ACCESS_DENIED e STATUS_ACCESS_VIOLATION come gli stessi per il collegamento «5» manda l’indagine in direzioni del tutto diverse — un problema di autorizzazioni contro un bug di programma. Inoltre, un codice STOP della schermata blu è un sistema diverso da NTSTATUS, quindi cercare 0x9F in una tabella NTSTATUS non produce una risposta significativa.14
flowchart TB
accTitle: L'errore 5 e 0xC0000005 hanno direzioni di indagine diverse
accDescr: L'errore Win32 5 va indagato come problema di autorizzazioni e NTSTATUS 0xC0000005 come bug di programma; trattarli come gli stessi manda l'indagine in un'altra direzione
a["Errore Win32 5"] --> ad["Indagare un problema di autorizzazioni"]
b["NTSTATUS 0xC0000005"] --> bd["Indagare un bug di programma"]
a -.-> memo["Codici non correlati di sistemi diversi"]
b -.-> memo
Figura 21: Non trattateli come gli stessi per il collegamento «5». L’errore 5 va verso un problema di autorizzazioni; 0xC0000005 verso un bug di programma.
10. Riepilogo
- I codici di errore Windows sono una struttura a tre strati di codici di errore Win32, HRESULT e NTSTATUS. Giudicate prima quale strato, quale parte ha restituito il codice.
- L’oscillazione di notazione (decimale / esadecimale / negativo) si può allineare meccanicamente. Convertite un negativo in esadecimale a 8 cifre e poi leggetelo.
- HRESULT è una struttura di bit S/R/C/N/X + Facility (11 bit) + Code (16 bit), e 0x8007xxxx è il motivo più importante, un errore Win32 avvolto. Convertite i 16 bit bassi in decimale ed estraete il codice essenziale.
- Un codice generico come 0x80004005 (E_FAIL) non indica una causa. Il giudizio di smettere di scavare nel codice e passare a un’indagine di contesto è possibile proprio perché conoscete la struttura.
- Incontrate NTSTATUS come codice di eccezione di crash o nella colonna Result di Procmon. 0xC0000005 è una violazione di accesso, non correlata all’errore Win32 5. Un codice STOP è ancora un altro sistema.
- In .NET, un HRESULT è mappato a un tipo di eccezione e il valore originale resta in Exception.HResult. In P/Invoke usate SetLastError=true e Marshal.GetLastWin32Error come coppia.
- Gli strumenti di ricerca sono certutil -error e net helpmsg (standard), err.exe (una macchina di sviluppo), one-liner PowerShell e !error di WinDbg.
- La procedura è «normalizzare la notazione → giudicare lo strato → scomporre → cercare il nome → abbinare al contesto». Ciò che un codice vi dice è il tipo di errore; il luogo della causa è ciò che il contesto vi dice.
La prossima volta che incontrate un codice di errore non familiare, guardate le prime poche cifre prima di incollarlo nella casella di ricerca. Le 4 cifre basse se 0x8007, NTSTATUS se 0xC, convertire in esadecimale se negativo — questa scomposizione di 10 secondi decide in gran parte il tempo di indagine che segue.
Articoli correlati
- Leggere un crash dump con WinDbg + SOS — guida pratica all’analisi dopo la raccolta
- Introduzione alla raccolta di crash dump Windows - WER/ProcDump/WinDbg
- Dove devono stare catch e il logging nella gestione delle eccezioni?
- Guida pratica a Process Monitor (ProcMon) — Individuare in 10 minuti “la configurazione non viene letta” e “ACCESS DENIED”
- Introduzione al registro eventi di Windows e a ETW — usare per le app aziendali i meccanismi standard del sistema operativo
Aree di consulenza correlate
KomuraSoft LLC gestisce indagini su incidenti che partono da un codice di errore — «non so cosa significa questo codice di errore», «0x80070005 compare solo in un ambiente specifico» —, la progettazione della gestione degli errori per app che mescolano Win32 API, COM e .NET, e l’identificazione delle cause con dump di crash e Process Monitor. Una consulenza da un singolo screenshot di una finestra di errore va bene.
- Sviluppo di app Windows
- Indagine sui difetti e analisi delle cause
- Consulenza tecnica e revisione della progettazione
- Contattaci
Riferimenti
-
Microsoft Learn, Debug system error codes. Un indice all’elenco dei codici di errore di sistema Win32 (0–15999); l’ottenimento del messaggio per un codice che
GetLastErrorrestituisce con FormatMessage e il flag FORMAT_MESSAGE_FROM_SYSTEM; che gli errori WinINet/WinHTTP (i 12000) sono definiti in questo spazio; e i metodi di indagine con Microsoft Error Lookup Tool e il comando !err. ↩ ↩2 ↩3 ↩4 ↩5 ↩6 -
Microsoft Open Specifications, [MS-ERREF]: HRESULT. Il layout dei bit HRESULT (bit S, R, C, N e X, Facility a 11 bit, Code a 16 bit); che il bit N indica un valore NTSTATUS mappato nello spazio HRESULT; e l’elenco dei codici di facility compreso FACILITY_WINDOWS_UPDATE (36). ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. Il layout dei bit NTSTATUS (Sev a 2 bit, bit C, bit N, Facility a 12 bit, Code a 16 bit); e che la severity si divide in quattro tipi: successo (00), informativo (01), avviso (10) ed errore (11). ↩ ↩2 ↩3
-
Microsoft Learn, HRESULT_FROM_WIN32 macro. La definizione della macro winerror.h che mappa un codice di errore di sistema Win32 a un valore HRESULT. ↩ ↩2 ↩3
-
Microsoft Learn, Structure of COM Error Codes. Il ruolo del bit di severity HRESULT e del campo facility; i valori di FACILITY_NULL, FACILITY_RPC, FACILITY_ITF, FACILITY_WIN32 e FACILITY_WINDOWS; e che un codice FACILITY_ITF ha il significato definito per interfaccia e lo stesso valore può significare qualcosa di diverso. ↩ ↩2 ↩3
-
Microsoft Learn, Common HRESULT values. Che E_FAIL (0x80004005) è «Unspecified failure»; e le definizioni di valori HRESULT frequenti come E_ACCESSDENIED (0x80070005), E_INVALIDARG (0x80070057) e E_OUTOFMEMORY (0x8007000E). ↩ ↩2 ↩3 ↩4
-
Microsoft Open Specifications, [MS-ERREF]: NTSTATUS values. L’elenco dei valori NTSTATUS compreso STATUS_ACCESS_VIOLATION (0xC0000005), STATUS_DLL_NOT_FOUND (0xC0000135), STATUS_STACK_OVERFLOW (0xC00000FD), STATUS_HEAP_CORRUPTION (0xC0000374) e STATUS_BREAKPOINT (0x80000003). ↩ ↩2 ↩3
-
Microsoft Learn, The Microsoft Error Lookup Tool. Che è uno strumento autonomo che mostra il testo del messaggio associato a un codice di stato esadecimale attraverso vari file header come Winerror.h; che il nome del file di download è Err_6.4.5.exe; e che dovete notare che le definizioni impacchettate sono al momento della compilazione. ↩ ↩2 ↩3
-
Microsoft Learn, certutil. Che l’opzione -error di certutil mostra il testo del messaggio associato a un codice di errore e che si usa una notazione di errore che include un nome di simbolo in una forma come 0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND). ↩ ↩2
-
Microsoft Learn, !error. Che l’estensione !error di WinDbg decodifica e mostra valori di errore Win32, Winsock, NTSTATUS e NetAPI; e che specificare 1 come flag interpreta come NTSTATUS. ↩ ↩2
-
Microsoft Learn, How to: Map HRESULTs and exceptions. Il meccanismo di mappatura reciproca tra HRESULT COM ed eccezioni .NET; la tabella di corrispondenza come E_NOTIMPL → NotImplementedException; che un HRESULT senza mappatura esplicita viene convertito in COMException; e che Message, Source e simili dell’eccezione vengono inizializzati dalle informazioni IErrorInfo. ↩ ↩2
-
Microsoft Learn, RtlNtStatusToDosError function (winternl.h). Che è una funzione che converte un codice NTSTATUS nel codice di errore di sistema Win32 corrispondente; che ERROR_MR_MID_NOT_FOUND viene restituito quando non è definita una corrispondenza; e che una funzione che esegue la conversione inversa non esiste. ↩ ↩2
-
Microsoft Learn, Last-Error Code. Che il last-error code è tenuto per thread; che va recuperato con GetLastError immediatamente dopo l’errore; che API che sovrascrivono il codice a 0 in caso di successo e API che non lo toccano sono miste; e che il bit 29 è riservato ai codici definiti dall’applicazione. ↩ ↩2
-
Microsoft Learn, Bug check code reference. L’elenco dei bug check code (codici STOP) visualizzati su una schermata blu e come visualizzare informazioni su un codice con l’estensione !analyze di WinDbg. Che è un sistema di numerazione proprio, distinto da NTSTATUS, si conferma dall’elenco. ↩ ↩2
-
Microsoft Learn, Marshal.GetLastWin32Error Method. Che è un modo per recuperare il last-error code di una chiamata P/Invoke che ha impostato il flag SetLastError; che P/Invocare GetLastError direttamente non è affidabile per la sovrascrittura da una chiamata API all’interno del runtime; e che da .NET 6 è consigliato GetLastPInvokeError. ↩
Articoli correlati
Articoli recenti con gli stessi tag per approfondire argomenti vicini.
App che si rompono alla ripresa dalla sospensione — Come funzionano gli eventi di alimentazione di Windows e come costruire app aziendali che li sopravvivono
Aprite il portatile e le connessioni dell'app aziendale sono morte — la causa è un progetto che non ha mai tenuto conto della sospensione...
DllMain e il loader lock — Il vero motivo per cui vi dicono di «non fare niente nell'inizializzazione della DLL»
Perché non dovete chiamare LoadLibrary o sincronizzarvi con altri thread da DllMain. A partire dalle fonti primarie, l'articolo spiega co...
Che cos'è davvero «Non risponde» — Come Windows decide che un'app è bloccata, e come progettare app che non lo sono
Il «Non risponde» di Windows è un meccanismo in cui il sistema operativo giudica che una finestra non ha prelevato un messaggio per 5 sec...
L'API thread pool Win32 — Concorrenza senza creare thread, tramite CreateThreadpoolWork
State spargendo chiamate CreateThread per tutto il codice nativo? Questo articolo spiega l'API thread pool Win32 ridisegnata in Vista — i...
Named pipe in pratica — L'IPC standard di Windows, dalla progettazione alla sicurezza
Guida pratica alle named pipe, il meccanismo standard di comunicazione tra processi su Windows. L'articolo organizza, a partire dalle fon...
Argomenti correlati
Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.
Argomenti tecnici Windows
Portale su sviluppo Windows, analisi dei problemi e valorizzazione delle risorse esistenti.
Servizi collegati all’argomento
L’articolo è direttamente collegato ai servizi seguenti.
Sviluppo di applicazioni Windows
Applicazioni aziendali, integrazione di dispositivi e strumenti di comunicazione, dai requisiti allo sviluppo.
Domande frequenti
Domande che ricorrono nelle consulenze sull’argomento dell’articolo.
- Cosa significa l'errore 0x80004005?
- 0x80004005 è l'HRESULT E_FAIL e significa "Unspecified failure" (errore non specificato). Indica solo che "si è verificato un errore che non può riportare un motivo dettagliato"; non è un codice che rappresenta la causa stessa. Lo stesso 0x80004005 compare in posti non correlati — rete, Windows Update, VBA, un driver di database — per questo motivo. Quando vedete questo codice, non scavate nel significato del codice; restringete la causa dal contesto di quale app e quale operazione lo ha prodotto, e da altre informazioni di errore lasciate nel registro eventi o in un registro dettagliato.
- Che cos'è un codice di errore negativo come -2147467259?
- È un HRESULT a 32 bit visualizzato come decimale con segno. Un HRESULT imposta il bit più significativo in caso di errore, quindi come intero con segno è sempre negativo. In PowerShell, '0x{0:X8}' -f -2147467259 lo riconverte in esadecimale (in questo esempio 0x80004005 = E_FAIL). Quando vedete un numero negativo che inizia con -214… in un registro o in un messaggio di errore di script, il primo passo standard è convertirlo in esadecimale e poi cercarlo.
- Qual è il modo più semplice per cercare il significato di un codice di errore?
- Senza installazioni extra potete usare net helpmsg 5 al prompt dei comandi (per un errore Win32 in decimale) e certutil -error 0x80070005. certutil accetta anche un HRESULT esadecimale e mostra il nome del simbolo e il testo del messaggio. In PowerShell, [System.ComponentModel.Win32Exception]::new(5).Message ottiene il messaggio localizzato. Su una macchina di sviluppo, tenete lo strumento ufficiale Microsoft err.exe (Microsoft Error Lookup Tool); può cercare in Win32, HRESULT e NTSTATUS ed elencare le definizioni corrispondenti in un colpo solo.
- Che tipo di errore è 0xC0000005?
- È l'NTSTATUS STATUS_ACCESS_VIOLATION, cioè una violazione di accesso (un accesso alla memoria illegale). È il codice che vedete più spesso come "Exception code" nel registro eventi o in un dump di crash quando un'applicazione si blocca, e indica un bug di programma come il dereferenziamento di un puntatore non valido o l'accesso a memoria già liberata. Sembra simile nel nome all'errore Win32 5 (ERROR_ACCESS_DENIED = accesso negato), ma è un codice non correlato di un sistema diverso; non confondeteli. Il modo affidabile per identificare la causa è catturare un dump di crash e analizzarlo in WinDbg.
- Perché la causa è diversa ogni volta, anche con lo stesso codice di errore?
- Perché un codice di errore rappresenta solo "che tipo di errore", e "cosa è fallito e perché" è deciso dal contesto di chiamata. L'errore 5 (accesso negato), per esempio, è lo stesso codice per cause del tutto diverse — autorizzazioni NTFS insufficienti, privilegi di amministratore mancanti, un blocco antivirus e così via. In una situazione simile, se un altro processo ha ancora il file aperto ottenete un codice diverso (errore 32 = violazione di condivisione), e leggere il codice correttamente cambia dove cercate. L'errore 2 (file non trovato) spesso non è il file principale ma una DLL dipendente o un file di impostazioni. Una volta cercato il significato del codice, confermare quale API è fallita contro quale risorsa con Process Monitor o simile è la via breve verso la causa.
Profilo dell’autore
Pagina di presentazione dell’autore dell’articolo.
Go Komura
Rappresentante di KomuraSoft LLC
Specializzato nello sviluppo di software Windows, nella consulenza tecnica e nell’analisi dei malfunzionamenti, soprattutto nei progetti con sistemi esistenti e guasti difficili da riprodurre.