Leggere i codici di errore Windows — la struttura a tre strati di Win32, HRESULT e NTSTATUS

· · 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 GetLastError restituisce), 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 -error e net helpmsg sono integrati in Windows; Win32Exception di PowerShell ottiene il messaggio; su una macchina di sviluppo err.exe (Microsoft Error Lookup Tool); nell’analisi dei dump !error di 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

Flusso di conversione tra i tre sistemiIl sottosistema Win32 converte un NTSTATUS restituito dal kernel in un codice di errore Win32, e lo strato COM lo avvolge ulteriormente come HRESULTIl sottosistema Win32 converteLo strato COM avvolgeKernel e driverNTSTATUS(errori 0xC…)Codice di errore Win32(5 e simili)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.

Tre apparenze dello stesso codiceL'errore decimale 5, l'esadecimale 0x5 e i 16 bit bassi di 0x80070005 si riferiscono tutti allo stesso ERROR_ACCESS_DENIEDNotazione decimale: errore 5ERROR_ACCESS_DENIEDNotazione esadecimale: 0x5I 16 bit bassi di 0x80070005Notazione 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

  1. 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.
  2. 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.
Leggere GetLastError subito dopo l'erroreDopo aver confermato l'errore dal valore di ritorno, recuperare il last-error code con GetLastError immediatamente, senza inserire un'altra chiamata APIWin32 APIAppWin32 APIAppInserire un'altra API in mezzo può sovrascriverloChiamata CreateFileValore di ritorno di erroreGetLastErrorCodice 5

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.

Cercare un messaggio da un codice e lasciarlo nel registroSpecificare 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 registroCodice di errore(esempio: 5)Ottenere la stringa con FormatMessageTesto del messaggioRegistrare nel logScrivere 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.

Gli errori 998 e 5 sono cose diverse998 è una violazione di accesso alla memoria, una violazione di accesso NTSTATUS convertita nello strato Win32, e differisce da 5 che rappresenta accesso negatoConvertito nello strato Win32NTSTATUS 0xC0000005Errore 998(ERROR_NOACCESS)Il significato è una violazione di accesso alla memoriaErrore 5(accesso negato)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.
La causa dell'errore 5 è decisa dal contestoAnche lo stesso accesso negato ha diversi candidati di causa come ACL insufficiente o privilegi di amministratore mancanti, e dovete identificare quale API è fallita contro cosaErrore 5(accesso negato)ACL insufficienteSenza privilegi adminBlocco da prodotto di sicurezzaPrivilegi di servizio bassiProcmon: destinazione fallita

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.

La relazione tra il bit S e una visualizzazione negativaUn 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 è negativoBit S = 1(errore)L'esadecimale inizia a 0x8 o sopraUna visualizzazione con segno è negativaQuando 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.

Scomposizione di 0x80004005 e 0x800700050x80004005 è 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 negato0x80004005Facility=0(FACILITY_NULL)Code=0x4005 → E_FAILErrore non specificato. Verso un'indagine di contesto0x80070005Facility=7(FACILITY_WIN32)Code=0x0005 → 5ERROR_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».

Come funziona HRESULT_FROM_WIN32Memorizzare il codice di errore Win32 nei 16 bit bassi, impostare Facility a 7 e il bit S a 1, e assemblare un HRESULT 0x8007xxxxCodice di errore Win32(esempio: 5)Memorizzare nei 16 bit bassiImpostare Facility a 7Impostare il bit S a 10x80070005

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

Come cercate cambia tra 0x8007 e 0x8004Un 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 restituito7, WIN324, ITFFacility è?Convertire i 16 bit bassi in decimaleIl significato differisce secondo chi lo ha restituitoLeggerlo come errore Win32Cercarlo 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

Un NTSTATUS si legge per tipo dalla cifra inizialePoiché 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 0x30xC0x80x40x0–0x3La cifra esadecimale iniziale è?ErroreAvvisoInformativoSuccessoEsempio: 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.
Distinguere un codice di eccezione da un codice STOPLeggere 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 diversoCodice di eccezioneCodice STOPDove è comparso il codice?Leggerlo come NTSTATUSCercarlo nella tabella dei bug-checkEsempio: 0xC0000005Esempio: 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.

  1. 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
  2. Conversione in un codice di errore Win32: RtlNtStatusToDosError di 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.
Due ponti da NTSTATUS agli altri stratiUn 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 RtlNtStatusToDosErrorImpostare il bit NRtlNtStatusToDosErrorNTSTATUS(0xC0000005)HRESULT(0xD0000005)Errore Win32 998(ERROR_NOACCESS)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.

IErrorInfo che integra HRESULTC'è 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 insiemeHRESULT(solo 32 bit)C'è un limite a ciò che si impacchettaIErrorInfo porta la descrizione_com_error le gestisce insiemeIl 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

Mappatura da HRESULT a un'eccezione .NETUn 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.HResultYesNoHRESULT di erroreUna mappatura nota?Convertire nel tipo di eccezione corrispondenteConvertire in COMExceptionIl valore originale resta in Exception.HResult

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

Recuperare l'ultimo errore in P/InvokeSpecificare SetLastError come true e recuperare con Marshal.GetLastWin32Error è corretto; P/Invocare GetLastError direttamente è inesatto per una sovrascrittura del runtimeChiamare un'API Win32 via P/InvokeSpecificare SetLastError=trueRecuperare con GetLastWin32ErrorUna definizione che chiama GetLastError direttamenteIl 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

Scegliere i risultati di ricerca di err.exe dal contestoerr.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 contestoImmettere err 5Percorrere molti headerDiverse definizioni colpisconoScegliere 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.

Come scegliere tra i comandi standardUn codice di errore Win32 decimale si cerca con net helpmsg; un codice che include esadecimale, compreso HRESULT, si cerca con l'opzione -error di certutilWin32 decimaleInclude esadecimaleIl codice che avete è?net helpmsgcertutil -errorTorna un messaggio italianoAccetta 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.

Flusso per confermare un codice di eccezione in WinDbgIn 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 NTSTATUSAprire il dump di crashEseguire !analyze -vIl codice di eccezione viene mostratoConfermare 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.

  1. 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.
  2. Giudicate di quale strato è il codice. Come nella tabella di giudizio sotto, le prime poche cifre lo decidono quasi.
  3. Scomponete ed estraete il codice essenziale. Un’operazione meccanica: i 16 bit bassi se 0x8007xxxx, togliere il bit N se 0xDxxxxxxx.
  4. Cercate il nome e la definizione con uno strumento. Confermate il nome del simbolo e il messaggio con err.exe, certutil o !error.
  5. 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».
Procedura per indagare un codice di erroreIl 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 contestoDecimale0x80070xC0xDNormalizzare in esadecimaleCifre iniziali?Leggere come errore Win3216 bit bassi → decimaleLeggere come NTSTATUSTogliere il bit N e leggereCercare nome/definizioneAbbinare 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

L'errore 5 e 0xC0000005 hanno direzioni di indagine diverseL'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 direzioneErrore Win32 5Indagare un problema di autorizzazioniNTSTATUS 0xC0000005Indagare un bug di programmaCodici non correlati di sistemi diversi

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.

  • 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

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.

Riferimenti

  1. 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 GetLastError restituisce 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

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

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

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

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

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

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

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

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

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

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

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

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

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

  15. 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 recenti con gli stessi tag per approfondire argomenti vicini.

Queste pagine collocano l’argomento in un contesto più ampio di servizi e decisioni.

L’articolo è direttamente collegato ai servizi seguenti.

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.

Torna al blog