Как читать коды ошибок Windows — Win32, HRESULT и NTSTATUS

· Обновлено: · · Windows, Коды ошибок, HRESULT, NTSTATUS, Win32 API, Диагностика, Отладка, Разработка Windows

История изменений (1 обновлений, последнее 31 Aug 2026)

Журнал изменений этой статьи. Там, где версия до правки была заархивирована, она остаётся доступной для чтения по постоянной ссылке с DOI.

Русский текст переписан по текущему навыку технического перевода как полный перевод японского оригинала.
Первая публикация
Цитирование статьи(DOI (зарегистрированный архив): 10.5281/zenodo.22176051)

Приведённые ниже DOI относятся к ранее зарегистрированным архивным версиям, которые могут отличаться от текущего текста. Для ссылки на текущий текст используйте URL этой страницы.

Go Komura (2026). Как читать коды ошибок Windows — Win32, HRESULT и NTSTATUS. KomuraSoft LLC. https://comcomponent.com/ru/blog/windows-error-codes-win32-hresult-ntstatus/

DOI (зарегистрированный архив)
10.5281/zenodo.22176051
DOI (последняя зарегистрированная версия)
10.5281/zenodo.22176052

«На экране приложения появилась ошибка 0x80004005. Что это значит?» — в разборе сбоев такой вопрос встречается постоянно. Если вбить в поиск число из диалога как есть, вываливается куча несвязанных статей — сбой Windows Update, общая папка не открывается, ошибка выполнения VBA, сбой подключения к базе — и путаница только растёт. С этим сталкивались многие.

Так выходит потому, что 0x80004005 (E_FAIL) — универсальный код, у которого нет другого смысла, кроме «сбой без подробностей». Раз один и тот же код используют в бесчисленных ситуациях, поиск только по коду к причине не приводит. Зато код вроде 0x80070005 при знании структуры за несколько секунд, ещё до поиска, разбирается так: «ошибка Win32 номер 5 = отказ в доступе, упакованная в HRESULT».

Коды ошибок Windows исторически сложились в три системы — коды ошибок Win32, HRESULT и NTSTATUS, — и между этими слоями они ещё и преобразуются друг в друга. Если держать эту структуру в голове, вы сами определите, какой слой и кто вернул код и какой код стоит за записью, — и первый шаг расследования заметно ускоряется.

Статья рассчитана на системных администраторов малого и среднего бизнеса и разработчиков Windows-приложений. По Microsoft Learn и открытой спецификации [MS-ERREF] по состоянию на август 2026 года здесь собрано, как различать и разбирать три системы кодов ошибок, как они связаны с исключениями .NET и как искать значения на практике через err.exe и PowerShell.

1. Сначала выводы

  • Коды ошибок Windows — это в основном три системы. Коды ошибок Win32 (небольшое десятичное число, которое возвращает GetLastError), HRESULT (32-битный код со времён COM: hex, который начинается с 0x8, либо отрицательное десятичное) и NTSTATUS (коды слоя ядра; ошибки начинаются с 0xC).123
  • Десятичная и шестнадцатеричная запись — разные обозначения одного кода. «Ошибка 5», «0x5» и «младшие 16 бит 0x80070005» все обозначают ERROR_ACCESS_DENIED (отказано в доступе).1
  • 0x8007xxxx — это упакованная ошибка Win32. Код ошибки Win32 лежит в HRESULT FACILITY_WIN32 (7); переведите младшие 16 бит в десятичное — и получите исходный код. Это главный шаблон чтения кодов ошибок.45
  • 0x80004005 (E_FAIL) — не код причины. Он означает «Unspecified failure» и больше ничего не несёт. Вместо того чтобы разбирать сам код, ищите исходный контекст и сопутствующие журналы.6
  • Отрицательное десятичное (-2147467259 и подобные) — это HRESULT. Старший бит 32-битного значения (бит сбоя) установлен, поэтому знаковое представление отрицательное. Переведите в hex и читайте уже его.2
  • Восьмизначное значение, которое начинается с 0xC, — это NTSTATUS. 0xC0000005 (нарушение доступа) и 0xC0000135 (DLL не найдена) постоянно появляются в журнале событий и дампах в момент сбоя. К ошибке Win32 номер 5 они отношения не имеют.7
  • Один и тот же код меняет смысл вместе с контекстом. Причина ошибки 5 бывает разной: ACL, повышение прав, антивирус, занятый файл и другое, а «файл не найден» у ошибки 2 нередко оказывается зависимой DLL. Смысл кода всегда читайте вместе с тем, какой API не сработал и против чего.1
  • Инструменты преобразования и поиска уже есть в стандартной поставке. certutil -error и net helpmsg встроены в Windows; Win32Exception в PowerShell даёт сообщение; на машине разработки — err.exe (Microsoft Error Lookup Tool); при разборе дампа — !error в WinDbg.8910
  • В .NET HRESULT преобразуется в тип исключения. Известный HRESULT идёт в соответствующий тип (E_ACCESSDENIED → UnauthorizedAccessException и т. п.); неизвестный становится COMException; исходное значение остаётся в Exception.HResult.11

Если свести к одной фразе, порядок разбора кода ошибки Windows такой: «привести запись к hex → определить слой → разобрать и извлечь исходный код → прочитать его вместе с контекстом».

На схеме сплошная линия обозначает отношение, которое выполняется всегда, а пунктирная — условное отношение (условия указаны в пояснении к каждому отношению на странице сведений). Полный список отношений (всего 18, с доказательствами и степенью уверенности) и определения основных понятий собраны на странице сведений карты знаний (на японском). Данные: JSON-LD / Turtle

2. В Windows три системы кодов ошибок

Сначала общая карта. Коды ошибок Windows делятся в основном на три системы — по слою, который их возвращает.

Система Кто обычно возвращает Типичный вид Типичный пример
Код ошибки Win32 Win32 API (GetLastError), код выхода команды Небольшое десятичное (0–15999) 5 = ERROR_ACCESS_DENIED
HRESULT Компонент COM, оболочка, установщик, многие фреймворки 8 hex-цифр, начинающихся с 0x8, либо отрицательное десятичное 0x80004005 = E_FAIL
NTSTATUS Ядро, драйвер, нативный API (ntdll) Ошибки — 8 hex-цифр, начинающихся с 0xC 0xC0000005 = STATUS_ACCESS_VIOLATION

Исторически они наложились в таком порядке: коды ошибок Win32, унаследовавшие номера MS-DOS; NTSTATUS, которым ядро NT пользуется внутри; и HRESULT, спроектированный при появлении COM, чтобы упаковать успех или сбой и источник в 32 бита. В нынешнем Windows поток преобразования повседневный: ядро возвращает NTSTATUS, подсистема Win32 преобразует его в код ошибки Win32, а слой COM упаковывает дальше в HRESULT.124

Поток преобразования между тремя системамиПодсистема Win32 преобразует NTSTATUS, который вернуло ядро, в код ошибки Win32, а слой COM упаковывает его дальше в HRESULTПодсистема Win32 преобразуетСлой COM упаковываетЯдро и драйверыNTSTATUS (ошибки 0xC…)Код ошибки Win32 (5 и подобные)HRESULT (0x8007xxxx)

Рис. 1: Поток преобразования между слоями. NTSTATUS ядра становится ошибкой Win32 и дальше упаковывается в HRESULT.

2.1. Привыкайте читать десятичное и шестнадцатеричное как одно и то же

Прежде чем различать три системы, нужно научиться не спотыкаться о разные формы записи. Один и тот же код в зависимости от места показывают десятичным или hex.

  • «Ошибка 5», «код ошибки: 0x5» → тот же ERROR_ACCESS_DENIED
  • «Ошибка 1223», «0x4C1» → тот же ERROR_CANCELLED
  • «0x80070005», «-2147024891» → тот же HRESULT

В PowerShell перевод — одна строка.

# десятичное → hex
'0x{0:X8}' -f 1223          # 0x000004C1
'0x{0:X8}' -f -2147024891   # 0x80070005 (отрицательное = HRESULT в hex)

# hex → десятичное
0x4C1                        # 1223

Увидев отрицательное десятичное, которое начинается с «-214…», сразу переводите его в hex. Одно это уже отсекает много блужданий на входе в расследование.

Три облика одного кодаДесятичная ошибка 5, hex 0x5 и младшие 16 бит 0x80070005 все обозначают один ERROR_ACCESS_DENIEDДесятичная запись: ошибка 5ERROR_ACCESS_DENIEDШестнадцатеричная запись: 0x5Младшие 16 бит 0x80070005Разная запись, тот же код

Рис. 2: Десятичное, hex и младшие 16 бит HRESULT — лишь разные записи одного кода.

3. Коды ошибок Win32 — GetLastError и FORMAT_MESSAGE

3.1. Как работает GetLastError

Многие Win32 API вроде CreateFile и RegOpenKeyEx показывают сбой возвращаемым значением (FALSE, NULL, INVALID_HANDLE_VALUE и т. п.) и кладут подробный код ошибки в код последней ошибки, который хранится отдельно для каждого потока. Вызывающий забирает его через GetLastError сразу после того, как убедился в сбое.13

Два практических предостережения.13

  1. Читайте сразу после сбоя. Если вставить другой вызов API (например, функцию журналирования), этот вызов может перезаписать код последней ошибки.
  2. Не полагайтесь на значение при успехе. Одни API обнуляют код последней ошибки при успехе, другие его не трогают. Правило — сначала подтвердить сбой по возвращаемому значению и только потом читать.
Читать GetLastError сразу после сбояПосле подтверждения сбоя по возвращаемому значению сразу получить код последней ошибки через GetLastError, не вставляя другой вызов APIWin32 APIПриложениеWin32 APIПриложениеДругой API между ними может перезаписать значениеВызов CreateFileВозвращаемое значение сбояGetLastErrorКод 5

Рис. 3: Код последней ошибки читайте сразу после сбоя. Другой вызов API между ними может его перезаписать.

Чтобы получить строку сообщения из кода, используйте FormatMessage с флагом FORMAT_MESSAGE_FROM_SYSTEM.1

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

void PrintLastError(const wchar_t* apiName)
{
    DWORD code = GetLastError();   // сразу после сбоя (другой 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);
}

Если в журнале своего приложения оставлять и десятичное, и hex, и текст сообщения, как здесь, последующее расследование идёт быстрее.

Получить сообщение по коду и записать в журналПередать флаг FORMAT_MESSAGE_FROM_SYSTEM в FormatMessage, чтобы получить строку сообщения кода ошибки, и оставить в журнале десятичное, hex и текстКод ошибки (пример: 5)Получить строку через FormatMessageТекст сообщенияЗаписать в журналПисать десятичное, hex и текст вместе

Рис. 4: Преобразуйте код ошибки в строку сообщения через FormatMessage и оставляйте в журнале десятичное, hex и текст вместе.

3.2. Коды, которые на практике встречаются постоянно

Коды ошибок Win32 определены в диапазоне 0–15999, и в Microsoft Learn есть полный список.1 Среди них при разборе сбоев снова и снова встречаются следующие.

Десятичное Hex Символ Смысл
2 0x2 ERROR_FILE_NOT_FOUND Указанный файл не найден
3 0x3 ERROR_PATH_NOT_FOUND Указанный путь не найден
5 0x5 ERROR_ACCESS_DENIED Отказано в доступе
32 0x20 ERROR_SHARING_VIOLATION Другой процесс использует объект, доступ невозможен
87 0x57 ERROR_INVALID_PARAMETER Параметр неверен
122 0x7A ERROR_INSUFFICIENT_BUFFER Переданный буфер слишком мал
998 0x3E6 ERROR_NOACCESS Недопустимый доступ к участку памяти
1223 0x4C1 ERROR_CANCELLED Операцию отменил пользователь

Из них 998 (ERROR_NOACCESS) — не «отказано в доступе», а выражение Win32 для нарушения доступа к памяти: вид NTSTATUS STATUS_ACCESS_VIOLATION, о котором ниже, после преобразования в слой Win32. Не путайте с номером 5. Ещё 1223 (ERROR_CANCELLED) появляется, когда пользователь выбирает «Нет» в диалоге повышения UAC, например, — это скорее «операцию отменили», чем ошибка.

Ошибки 998 и 5 — разные вещи998 — нарушение доступа к памяти, NTSTATUS-нарушение доступа, преобразованное в слой Win32, и отличается по смыслу от 5, которое означает отказ в доступеПреобразовано в слой Win32NTSTATUS 0xC0000005Ошибка 998 (ERROR_NOACCESS)Смысл — нарушение доступа к памятиОшибка 5 (отказано в доступе)Проблема прав. Другое, чем 998

Рис. 5: Ошибка 998 — это NTSTATUS-нарушение доступа, преобразованное в слой Win32, иное, чем «отказано в доступе» у 5.

3.3. Один и тот же код меняет смысл вместе с контекстом

Важнее запоминания таблицы частых кодов — понимание, что код ошибки говорит только тип сбоя.

  • Ошибка 5 (отказано в доступе): кандидаты причины широки — не хватает ACL NTFS, запись в защищённую область без прав администратора, блокировка антивирусом или AppLocker, недостаточно прав у учётной записи службы и так далее.
  • Ошибка 2 (файл не найден): это не обязательно файл, который указал пользователь. Зависимая DLL, которую EXE пытался загрузить неявно; файл настроек, который из-за перенаправления реестра (32-бит/64-бит) искали не там; путь, у которого не раскрылась переменная окружения, — какой именно файл не найден, из кода не видно.
  • Ошибка 32 (нарушение совместного доступа): настоящий вопрос — «какой процесс держит объект», но код этого не говорит.
Причину ошибки 5 решает контекстДаже один и тот же отказ в доступе имеет несколько кандидатов причины, например недостаточный ACL или отсутствие прав администратора, и нужно определить, какой API не сработал против чегоОшибка 5 (отказано в доступе)Не хватает ACLНет прав администратораБлокировка средством защитыМало прав у службыProcmon: цель сбоя

Рис. 6: Код говорит только тип сбоя. У ошибки 5 несколько кандидатов причины, и нужно определить цель.

Инструмент, который показывает на деле, какой API, против какого имени объекта, вернул какой результат, — Process Monitor. Как им пользоваться, подробно в «Практическое руководство по Process Monitor (ProcMon)». Поиск смысла кода ошибки и определение цели, которая не сработала, нужно делать вместе: одно без другого не закрывает расследование.

4. HRESULT — как читать структуру, упакованную в 32 бита

4.1. Размещение битов

HRESULT — формат, который упаковывает успех или сбой, источник и подробный код в одно 32-битное значение. Открытая спецификация [MS-ERREF] задаёт его такой раскладкой.2

Позиция бита Имя Смысл
31 S Серьёзность. 0 = успех, 1 = сбой
30 R Зарезервировано (часть серьёзности при отображении NTSTATUS)
29 C Бит Customer. 1 означает код, определённый не Microsoft
28 N 1 означает значение NTSTATUS, отображённое в пространство HRESULT
27 X Зарезервировано (0)
26–16 Facility Код facility, указывающий источник (11 бит)
15–0 Code Подробный код внутри facility (16 бит)

Старший бит S равен 1, то есть HRESULT, чья hex-запись начинается с 0x8 или выше, — сбой. Показ как знакового 32-битного целого делает его отрицательным — вот что стоит за уже упомянутым «-214…».

Связь бита S и отрицательного отображенияHRESULT сбоя имеет старший бит S равным 1, поэтому в hex начинается с 0x8 или выше, а как знаковое 32-битное целое отрицателенБит S = 1 (сбой)Hex начинается с 0x8 или вышеЗнаковое представление отрицательноеУвидев отрицательное, перевести в hex и читать

Рис. 7: HRESULT сбоя начинается с 0x8 или выше, потому что бит S равен 1, а знаковое представление отрицательное.

Основные значения Facility следующие.5

Facility Значение Вид hex Смысл
FACILITY_NULL 0 0x8000xxxx Широко общие коды (E_FAIL, E_UNEXPECTED и т. п.)
FACILITY_RPC 1 0x8001xxxx Источник — RPC
FACILITY_ITF 4 0x8004xxxx Ошибка, заданная интерфейсом (смысл зависит от интерфейса)
FACILITY_WIN32 7 0x8007xxxx Упакованный код ошибки Win32
FACILITY_WINDOWS 8 0x8008xxxx Дополнительные интерфейсы, определённые Microsoft

4.2. Разбор 0x80004005 и 0x80070005

Разберём их на деле.

Для 0x80004005: S=1 (сбой), Facility=(0x80004005 » 16) & 0x7FF = 0 (FACILITY_NULL), Code=0x4005. Общий код FACILITY_NULL, определённый как E_FAIL «Unspecified failure».6 Иначе говоря, этот код несёт только смысл «сбой, для которого нет подробностей». Увидев 0x80004005, остановите разбор самого кода и перенесите расследование на «какой компонент его вернул» и «есть ли подробности в журнале событий или журнале приложения в то же время».

Для 0x80070005: S=1, Facility=7 (FACILITY_WIN32), Code=0x0005=5. Видно, что это ошибка Win32 номер 5 (ERROR_ACCESS_DENIED), упакованная в HRESULT. Псевдоним E_ACCESSDENIED по сути это же значение.6

Даже для одного и того же «отказано в доступе» 0x80070005 — упаковка конкретного сбоя на слое Win32, и информативность совершенно иная, чем у 0x80004005.

Разбор 0x80004005 и 0x800700050x80004005 — общий код FACILITY_NULL E_FAIL, без подробностей, и должен перейти к расследованию контекста; 0x80070005 — FACILITY_WIN32 и читается как упаковка ошибки Win32 номер 5, отказ в доступе0x80004005Facility=0 (FACILITY_NULL)Code=0x4005 → E_FAILНеопределённый сбой. Дальше к расследованию контекста0x80070005Facility=7 (FACILITY_WIN32)Code=0x0005 → 5ERROR_ACCESS_DENIED

Рис. 8: Даже один и тот же «сбой» после разбора несёт разный объём информации. 0x80070005 можно провести к ошибке Win32 номер 5.

4.3. Главный шаблон: 0x8007xxxx = HRESULT_FROM_WIN32

Чтобы передать сбой от нижнего слоя, который может вернуть только код ошибки Win32, верхнему слою, который возвращает HRESULT (метод COM или среда .NET), в winerror.h есть макрос HRESULT_FROM_WIN32.4 Поведение такое: положить код ошибки Win32 в младшие 16 бит, выставить Facility в FACILITY_WIN32 (7) и выставить бит S в 1.

Как работает HRESULT_FROM_WIN32Положить код ошибки Win32 в младшие 16 бит, выставить Facility в 7 и бит S в 1 и собрать HRESULT 0x8007xxxxКод ошибки Win32 (пример: 5)Положить в младшие 16 битВыставить Facility в 7Выставить бит S в 10x80070005

Рис. 9: HRESULT_FROM_WIN32 кладёт ошибку Win32 в младшие 16 бит и выставляет Facility=7 и бит 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)

Чтобы читать в другую сторону, возьмите младшие 16 бит в PowerShell.

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

Как во втором примере, ошибки WinINet и WinHTTP (12000-е) тоже определены в пространстве кодов ошибок Win321, поэтому сетевой 0x8007xxxx разбирается той же процедурой. Довести до автоматизма правило «увидев 0x8007, переведите младшие 4 цифры в десятичное» — главный практический навык, который стоит унести из этой статьи.

Есть обратное предостережение для 0x8004xxxx (FACILITY_ITF). У кода FACILITY_ITF смысл задаёт каждый интерфейс сам, поэтому одно и то же 32-битное значение может значить другое, если его вернул другой компонент.5 Незнакомый 0x8004xxxx ищите не общим поиском, а в документации компонента, который его вернул (библиотека, SDK драйвера, серверный продукт).

Как искать, меняется между 0x8007 и 0x8004FACILITY_WIN32 0x8007xxxx читается формальным разбором младших 16 бит, а FACILITY_ITF 0x8004xxxx имеет разный смысл на интерфейс, поэтому ищите в материалах вернувшего компонента7, WIN324, ITFКакой Facility?Перевести младшие 16 бит в десятичноеСмысл зависит от того, кто вернулЧитать как ошибку Win32Искать в материалах вернувшего компонента

Рис. 10: 0x8007xxxx можно разобрать формально; 0x8004xxxx ищут в материалах компонента, который его вернул.

5. NTSTATUS — коды слоя ядра и мир сбоев

5.1. Размещение битов и Severity

NTSTATUS — 32-битный код, которым пользуются ядро, драйверы устройств и нативные API ntdll; раскладка похожа на HRESULT, но это не то же самое.3

Позиция бита Имя Смысл
31–30 Sev Серьёзность. 00 = успех, 01 = сведения, 10 = предупреждение, 11 = ошибка
29 C Бит Customer
28 N Зарезервировано (0, чтобы отображение в HRESULT было возможно)
27–16 Facility Facility (12 бит)
15–0 Code Подробный код

Поскольку серьёзность занимает 2 бита, тип читается по старшей hex-цифре. 0xC… — ошибка (11), 0x8… — предупреждение (10), 0x4… — сведения (01), 0x0–0x3… — успех. Исключение точки останова 0x80000003 (STATUS_BREAKPOINT) — характерный пример «предупреждение, не ошибка».37

NTSTATUS читается по типу из старшей цифрыПоскольку серьёзность — 2 бита, NTSTATUS читается как ошибка, если старшая hex-цифра 0xC, предупреждение если 0x8, сведения если 0x4 и успех если 0x0–0x30xC0x80x40x0–0x3Старшая hex-цифра?ОшибкаПредупреждениеСведенияУспехПример: 0x80000003 — предупреждение

Рис. 11: NTSTATUS читается по типу из старшей hex-цифры. 0x80000003 — «предупреждение, не ошибка».

5.2. Где вы его встречаете — коды исключений, коды STOP и журнал событий

Ситуации, в которых системные администраторы и разработчики встречают NTSTATUS, в основном связаны со сбоями.

  • Код исключения при падении приложения: «Код исключения: 0xc0000005», записанный в журнале событий в «Ошибка приложения (код события 1000)», — это NTSTATUS. Характерные значения следующие.7
Значение Символ Смысл
0xC0000005 STATUS_ACCESS_VIOLATION Нарушение доступа (некорректное обращение к памяти)
0xC0000135 STATUS_DLL_NOT_FOUND Нужная DLL не найдена, запуск невозможен
0xC00000FD STATUS_STACK_OVERFLOW Переполнение стека
0xC0000374 STATUS_HEAP_CORRUPTION Повреждение кучи
  • Код STOP синего экрана: на первый взгляд похожи, но код STOP (bug check code) — своя система нумерации, отдельная от NTSTATUS, например 0x0000009F (DRIVER_POWER_STATE_FAILURE), и имеет отдельный справочник.14 Достаточно помнить различие: «0xC0000005 — NTSTATUS; STOP 0x9F — код bug check, его нельзя искать в таблице NTSTATUS».
  • Столбец Result в Process Monitor: NAME NOT FOUND и ACCESS DENIED в столбце Result Procmon — отображаемые имена NTSTATUS, который вернуло ядро (STATUS_OBJECT_NAME_NOT_FOUND, STATUS_ACCESS_DENIED). Это также место, где видно соответствие слоёв: наблюдать сбой файлового ввода-вывода в словаре NTSTATUS и видеть, как этот сбой преобразуется в ошибку Win32 и приходит в приложение.
Отличить код исключения от кода STOPКод исключения журнала событий читать как NTSTATUS; код STOP синего экрана искать в отдельном справочнике bug-check, другой системеКод исключенияКод STOPГде появился код?Читать как NTSTATUSИскать в таблице bug-checkПример: 0xC0000005Пример: 0x0000009F

Рис. 12: Код исключения журнала событий — NTSTATUS; код STOP синего экрана — другая система. Не ищите их в неверной таблице.

Расследование за пределами кода исключения, то есть съём и анализ дампа сбоя, разобрано в «Введение в сбор дампов сбоев Windows» и «Чтение крэш-дампов с WinDbg + SOS».

5.3. Связь с HRESULT — бит N и RtlNtStatusToDosError

Мост между NTSTATUS и двумя другими слоями имеет два пути.

  1. Отображение в пространство HRESULT: установка бита N HRESULT (0x10000000) переносит значение NTSTATUS в пространство HRESULT как есть (макрос HRESULT_FROM_NT в winerror.h). Отображение 0xC0000005 становится, например, 0xD0000005. Увидев HRESULT, который начинается с 0xD, правильная процедура — снять бит N и читать как NTSTATUS.2
  2. Преобразование в код ошибки Win32: RtlNtStatusToDosError из ntdll преобразует NTSTATUS в соответствующий код ошибки Win32. Значение без определённого соответствия становится ERROR_MR_MID_NOT_FOUND.12 Например, STATUS_ACCESS_VIOLATION (0xC0000005) преобразуется в ERROR_NOACCESS (998), а STATUS_OBJECT_NAME_NOT_FOUND (0xC0000034) — в ERROR_FILE_NOT_FOUND (2). Полезно помнить и то, что богатый набор кодов ядра на слое Win32 иногда сводится к более грубой классификации.
Два моста от NTSTATUS к другим слоямNTSTATUS передаётся другим слоям двумя путями: отображается в пространство HRESULT установкой бита N и преобразуется в код ошибки Win32 через RtlNtStatusToDosErrorВыставить бит NRtlNtStatusToDosErrorNTSTATUS (0xC0000005)HRESULT (0xD0000005)Ошибка Win32 998 (ERROR_NOACCESS)ERROR_MR_MID_NOT_FOUND, если соответствие не определено

Рис. 13: Мостов у NTSTATUS два. Начало 0xD читают как NTSTATUS после снятия бита N.

6. COM и .NET — как код ошибки превращается в исключение

6.1. Как устроен COM — HRESULT + IErrorInfo

Метод COM принципиально возвращает HRESULT, но в 32 бита умещается не всё, поэтому дополнительно механизм IErrorInfo может отдельно передать строку описания ошибки и источник. В C++ поддерживаемый компилятором класс _com_error обрабатывает HRESULT и IErrorInfo вместе. Приложение, чей диалог ошибки показывает «код + описание», часто несёт описание через этот механизм.

IErrorInfo, дополняющий HRESULTВ 32-битный HRESULT умещается не всё, поэтому строка описания ошибки и источник передаются отдельно через IErrorInfo, а в C++ класс _com_error обрабатывает оба вместеHRESULT (только 32 бита)В 32 бита умещается не всёIErrorInfo несёт описание_com_error обрабатывает их вместеКод + описание диалога

Рис. 14: Строку описания, которая не умещается в 32-битный HRESULT, отдельно несёт IErrorInfo.

6.2. Как устроен .NET — от HRESULT к типу исключения

Когда среда .NET в COM interop получает сбой HRESULT, она преобразует его в исключение. Известный HRESULT сопоставляется с соответствующим типом исключения; неизвестный становится COMException.11

Сопоставление HRESULT с исключением .NETHRESULT сбоя, полученный в COM interop, преобразуется в соответствующий тип исключения, если известен, или в COMException, если неизвестен, и в любом случае исходное значение остаётся в Exception.HResultДаНетHRESULT сбояЕсть известное соответствие?Преобразовать в соответствующий тип исключенияПреобразовать в COMExceptionИсходное значение остаётся в Exception.HResult

Рис. 15: .NET сопоставляет HRESULT с типом исключения, и исходное значение остаётся в Exception.HResult у каждого исключения.

HRESULT Тип исключения .NET
E_ACCESSDENIED (0x80070005) UnauthorizedAccessException
E_OUTOFMEMORY (0x8007000E) OutOfMemoryException
E_INVALIDARG (0x80070057) ArgumentException
E_NOTIMPL (0x80004001) NotImplementedException
Значение без определённого соответствия COMException (исходное значение в свойстве ErrorCode)

У каждого исключения исходный HRESULT остаётся в свойстве Exception.HResult. Ветвление в обработке исключений файлового ввода-вывода вроде «повторять только при нарушении совместного доступа» можно написать этим значением.

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)
    // Файл держит другой процесс — подождать и повторить попытку и т. п.
}

6.3. P/Invoke и GetLastError

Когда вы вызываете Win32 API напрямую через P/Invoke, укажите SetLastError = true на DllImport (или LibraryImport), затем заберите код через Marshal.GetLastWin32Error (с .NET 6 эквивалент GetLastPInvokeError). Определять сам GetLastError как P/Invoke и вызывать его ненадёжно: вызов API внутри среды может перезаписать значение.15

Получение последней ошибки в P/InvokeУказать SetLastError как true и забрать через Marshal.GetLastWin32Error правильно; вызывать GetLastError напрямую через P/Invoke неточно из-за перезаписи средойВызвать Win32 API через P/InvokeУказать SetLastError=trueЗабрать через GetLastWin32ErrorОпределение, которое вызывает GetLastError напрямуюСреда перезаписывает, значение неточно

Рис. 16: В P/Invoke используйте SetLastError=true и Marshal.GetLastWin32Error как пару. Прямой вызов GetLastError ненадёжен.

[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);

// Возвращаемое значение принимать как SafeFileHandle, не IntPtr, и закрывать через using
// (если оставить IntPtr, утечёт дескриптор ядра)
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();              // например: 5
    var message = new Win32Exception(code).Message;       // например: Отказано в доступе.
    logger.LogError("CreateFileW failed: {Code} (0x{Code:X8}) {Message}",
        code, code, message);
}

Win32Exception ищет строку сообщения ОС по коду ошибки Win32, поэтому её можно использовать как есть, чтобы оставить в журнале и код, и сообщение. Вопрос проектирования — на каком слое ловить исключение и как оставлять его в журнале — разобран в «Где размещать catch и логирование при обработке исключений».

7. Инструменты преобразования и расследования на практике — шпаргалка, которую можно копировать

7.1. err.exe (Microsoft Error Lookup Tool)

Автономный инструмент поиска ошибок, который распространяет Microsoft. Он обходит большое число заголовочных файлов вроде winerror.h и ntstatus.h и перечисляет определения и сообщения, совпадающие с указанным кодом.8

err 0x80070005
err 5
err 0xC0000005

Одно число может попасть в нескольких заголовках (например, «5» совпадает с определениями в разных местах помимо Win32 ERROR_ACCESS_DENIED), поэтому какой из кандидатов уместен, нужно выбрать по контексту. Имя файла загрузки версионировано (Err_6.4.5.exe на момент написания), и учтите также, что определения кодов основаны на заголовках на момент комплектации.8

Выбирать результаты поиска err.exe по контекстуerr.exe обходит большое число заголовочных файлов и перечисляет совпадающие определения, поэтому когда на одно число приходится несколько кандидатов, выбирайте уместного по контекстуВвести err 5Обойти большое число заголовковНесколько определений совпалиВыбрать уместного кандидата по контексту

Рис. 17: err.exe ищет по заголовкам, поэтому может выйти несколько кандидатов, и уместного выбирают по контексту.

7.2. Команды, встроенные в Windows

То, чем можно пользоваться без дополнительной установки, — certutil и net helpmsg. Параметр -error у certutil показывает текст сообщения, соответствующий коду ошибки, и принимает либо шестнадцатеричный HRESULT, либо десятичное.9

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

net helpmsg — только для кода ошибки Win32 в десятичном виде, но в русской среде сообщение возвращается по-русски, поэтому его можно использовать как есть для объяснения пользователю.

Как выбирать среди стандартных командДесятичный код ошибки Win32 ищут через net helpmsg; код, включающий hex, в том числе HRESULT, — через параметр -error у certutilДесятичный Win32Включает hexКакой код у вас?net helpmsgcertutil -errorВозвращается русское сообщениеПринимает и hex, и десятичное

Рис. 18: Как выбирать среди стандартных команд. Десятичная ошибка Win32 — net helpmsg; если есть hex — certutil -error.

7.3. Набор однострочников PowerShell

# код ошибки Win32 → строка сообщения ОС
[System.ComponentModel.Win32Exception]::new(5).Message
# → Отказано в доступе.

# отрицательное десятичное → hex (подтвердить, что это HRESULT)
'0x{0:X8}' -f -2147467259     # 0x80004005

# 0x8007xxxx → код ошибки Win32 в младших 16 битах
0x80070005 -band 0xFFFF        # 5

# HRESULT → какое исключение сопоставляет .NET
[System.Runtime.InteropServices.Marshal]::GetExceptionForHR(-2147024891)
# → UnauthorizedAccessException (0x80070005)

# код ошибки Win32 → HRESULT (воспроизвести упаковку)
'0x{0:X8}' -f (0x80070000 -bor 32)   # 0x80070020

7.4. !error в WinDbg

Чтобы искать код при разборе дампа, расширение !error в WinDbg быстрое. По умолчанию оно толкует значение как код ошибки Win32; передайте 1 вторым аргументом — и оно толкует как NTSTATUS.10

0:000> !error 5
Error code: (Win32) 0x5 (5) - Отказано в доступе.

0:000> !error 0xc0000005 1
Error code: (NTSTATUS) 0xc0000005 - <нарушение доступа>

В дампе сбоя !analyze -v автоматически показывает код исключения (NTSTATUS), поэтому поток такой: оттуда подтвердить смысл через !error <code> 1.

Поток подтверждения кода исключения в WinDbgВ дампе сбоя команда analyze автоматически показывает код исключения; передайте этот код расширению error со вторым аргументом 1 и подтвердите смысл как NTSTATUSОткрыть дамп сбояВыполнить !analyze -vПоказан код исключенияПодтвердить смысл через !error код 1

Рис. 19: При разборе дампа ищите код исключения, который показал !analyze -v, через !error с флагом 1.

8. Порядок расследования — от определения слоя к сопоставлению с контекстом

Сведите сказанное выше в порядок фактического разбора кода ошибки.

  1. Нормализуйте запись. Если это отрицательное десятичное, переведите в 8-значный hex. Hex короче 8 цифр дополните нулями слева и читайте.
  2. Определите, какому слою принадлежит код. Как в таблице ниже, старшие несколько цифр почти всегда решают.
  3. Разберите и извлеките исходный код. Формальная операция: младшие 16 бит, если 0x8007xxxx; снять бит N, если 0xDxxxxxxx.
  4. Найдите имя и определение инструментом. Подтвердите имя символа и сообщение через err.exe, certutil или !error.
  5. Сопоставьте с контекстом. Определите, какое приложение, какая операция, какой API не сработал против чего, из журнала приложения, журнала событий и Procmon. Код — «тип сбоя»; контекст — «где искать причину».
Порядок расследования кода ошибкиШаблон расследования: привести запись к hex, определить слой по старшим цифрам, разобрать и извлечь исходный код, найти имя и определение инструментом, затем сопоставить с контекстомДесятичное0x80070xC0xDНормализовать в hexСтаршие цифры?Читать как ошибку Win32Младшие 16 бит → десятичноеЧитать как NTSTATUSСнять бит N и читатьНайти имя и определениеСопоставить с контекстом (Procmon)

Рис. 20: Порядок расследования. Нормализуйте запись, определите слой и разберите, найдите имя, затем сопоставьте с контекстом.

Вид Первая гипотеза Как разбирать и преобразовывать
1–5-значное десятичное (5, 1223 и т. п.) Код ошибки Win32 Как есть в net helpmsg или err.exe
Отрицательное десятичное (-2147024891 и т. п.) HRESULT Перевести в 8-значный hex, затем суждение строк ниже
0x8007xxxx HRESULT (FACILITY_WIN32) Перевести младшие 16 бит в десятичное и читать как Win32
0x8004xxxx HRESULT (FACILITY_ITF) Искать в документации компонента, который вернул код
0x8000xxxx HRESULT (FACILITY_NULL) Общий код вроде E_FAIL. Перенести расследование на контекст
0xCxxxxxxx NTSTATUS (ошибка) !error <code> 1; при необходимости преобразовать в Win32 и читать
0xDxxxxxxx Отображение NTSTATUS в HRESULT Снять бит N (0x10000000) и читать как NTSTATUS
Своя facility вроде 0x8024xxxx HRESULT конкретной подсистемы Определить область по значению Facility и идти в отдельные материалы (0x8024… — Windows Update)2

Что особенно помогает на шаге 5 «сопоставление с контекстом» — столбец Result в Process Monitor. Даже если приложение показывает только «0x80070002», Procmon в одной строке говорит, какой процесс, против какого пути, получил NAME NOT FOUND. Для поиска со стороны журнала событий см. также «Введение в журнал событий Windows и ETW».

9. Частые ошибки чтения — шаблоны, которые уводят расследование в сторону

Наконец, шаблоны неверного чтения, которые встречаются в реальных обращениях.

Ошибка чтения 1: считать 0x80004005 кодом конкретной причины

E_FAIL — «Unspecified failure», и то же значение появляется в Windows Update, сети и базах данных. Перебирать каждое средство, которое всплывает при поиске по этому коду, почти наверняка потеря времени. Сужайте не от кода, а от «какое приложение, какая операция, другие журналы в то же время».6

Ошибка чтения 2: не заметить, что отрицательное десятичное — HRESULT

Случай искать журнал, где написано «Произошла ошибка -2147467259», как есть, или путаться от «ошибка с минусом?». Увидев отрицательное, переведите в hex. Одно это скажет, что это 0x80004005 (E_FAIL), и свяжется со знанием ошибки чтения 1.

Ошибка чтения 3: искать все 8 цифр 0x8007xxxx и не смотреть на лежащую под ними ошибку Win32

Суть 0x80070005 — «5 = отказано в доступе». После извлечения младших 16 бит думать, что означает ошибка Win32 5 в контексте этой операции, быстрее доводит до сути, чем искать по всем 8 цифрам.

Ошибка чтения 4: считать, что «тот же код = та же причина»

Если однажды «ошибку 5 вызвал антивирус», вы склонны сразу применять то же средство при следующей ошибке 5. Даже при том же коде, если API, который не сработал, и целевой ресурс другие, причина — другая. Проверку смысла кода и определение цели через Procmon или аналог делайте каждый раз вместе.

Ошибка чтения 5: путать ошибку Win32 5 с 0xC0000005 и код STOP с NTSTATUS

Считать ERROR_ACCESS_DENIED и STATUS_ACCESS_VIOLATION одним и тем же из-за «пятёрки» уводит расследование в совершенно разные стороны — проблема прав против программной ошибки. Также код STOP синего экрана — другая система, чем NTSTATUS, поэтому поиск 0x9F в таблице NTSTATUS не даёт осмысленного ответа.14

Ошибка 5 и 0xC0000005 имеют разные направления расследованияОшибку Win32 5 следует расследовать как проблему прав, а NTSTATUS 0xC0000005 как программную ошибку; считать их одним уводит расследование в другую сторонуОшибка Win32 5Расследовать проблему правNTSTATUS 0xC0000005Расследовать программную ошибкуНесвязанные коды разных систем

Рис. 21: Не считайте их одним из-за «пятёрки». Ошибка 5 идёт к проблеме прав; 0xC0000005 — к программной ошибке.

10. Итог

  • Коды ошибок Windows — трёхслойная структура кодов ошибок Win32, HRESULT и NTSTATUS. Сначала определите, какой слой и кто вернул код.
  • Разные формы записи (десятичное / hex / отрицательное) можно выровнять формально. Переведите отрицательное в 8-значный hex и затем читайте.
  • HRESULT — структура битов S/R/C/N/X + Facility (11 бит) + Code (16 бит), и 0x8007xxxx — главный шаблон, упакованная ошибка Win32. Переведите младшие 16 бит в десятичное и извлеките исходный код.
  • Общий код вроде 0x80004005 (E_FAIL) не указывает причину. Решение остановить разбор кода и перейти к расследованию контекста возможно именно потому, что вы знаете структуру.
  • NTSTATUS вы встречаете как код исключения сбоя или в столбце Result Procmon. 0xC0000005 — нарушение доступа, не связанное с ошибкой Win32 5. Код STOP — ещё одна система.
  • В .NET HRESULT сопоставляется с типом исключения, и исходное значение остаётся в Exception.HResult. В P/Invoke используйте SetLastError=true и Marshal.GetLastWin32Error как пару.
  • Инструменты поиска — certutil -error и net helpmsg (стандарт), err.exe (машина разработки), однострочники PowerShell и !error в WinDbg.
  • Порядок — «нормализовать запись → определить слой → разобрать → найти имя → сопоставить с контекстом». Что говорит код — тип сбоя; где искать причину, говорит контекст.

В следующий раз, встретив незнакомый код ошибки, посмотрите на старшие несколько цифр, прежде чем вставлять его в поле поиска. Младшие 4 цифры, если 0x8007; NTSTATUS, если 0xC; перевести в hex, если отрицательное — этот 10-секундный разбор во многом решает время последующего расследования.

Похожие статьи

Смежные области консультирования

KomuraSoft LLC берёт разбор сбоев, который начинается с кода ошибки — «не знаю, что означает этот код ошибки», «0x80070005 появляется только в конкретной среде», — проектирование обработки ошибок для приложений, которые смешивают Win32 API, COM и .NET, и определение причин через дампы сбоев и Process Monitor. Консультация с одного снимка экрана диалога ошибки подходит.

Справочные ссылки

  1. Microsoft Learn, Debug system error codes. Указатель списка системных кодов ошибок Win32 (0–15999); получение сообщения для кода, который возвращает GetLastError, через FormatMessage и флаг FORMAT_MESSAGE_FROM_SYSTEM; то, что ошибки WinINet/WinHTTP (12000-е) определены в этом пространстве; и методы расследования через Microsoft Error Lookup Tool и команду !err. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  2. Microsoft Open Specifications, [MS-ERREF]: HRESULT. Размещение битов HRESULT (биты S, R, C, N и X, 11-битный Facility, 16-битный Code); то, что бит N указывает значение NTSTATUS, отображённое в пространство HRESULT; и список кодов facility, включая FACILITY_WINDOWS_UPDATE (36). ↩ ↩2 ↩3 ↩4 ↩5

  3. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. Размещение битов NTSTATUS (2-битный Sev, бит C, бит N, 12-битный Facility, 16-битный Code); и то, что серьёзность делится на четыре рода: успех (00), сведения (01), предупреждение (10) и ошибка (11). ↩ ↩2 ↩3

  4. Microsoft Learn, HRESULT_FROM_WIN32 macro. Определение макроса winerror.h, который отображает системный код ошибки Win32 на значение HRESULT. ↩ ↩2 ↩3

  5. Microsoft Learn, Structure of COM Error Codes. Роль бита серьёзности HRESULT и поля facility; значения FACILITY_NULL, FACILITY_RPC, FACILITY_ITF, FACILITY_WIN32 и FACILITY_WINDOWS; и то, что у кода FACILITY_ITF смысл задан на интерфейс и одно значение может значить другое. ↩ ↩2 ↩3

  6. Microsoft Learn, Common HRESULT values. То, что E_FAIL (0x80004005) — «Unspecified failure»; и определения часто встречающихся значений HRESULT вроде E_ACCESSDENIED (0x80070005), E_INVALIDARG (0x80070057) и E_OUTOFMEMORY (0x8007000E). ↩ ↩2 ↩3 ↩4

  7. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS values. Список значений NTSTATUS, включая STATUS_ACCESS_VIOLATION (0xC0000005), STATUS_DLL_NOT_FOUND (0xC0000135), STATUS_STACK_OVERFLOW (0xC00000FD), STATUS_HEAP_CORRUPTION (0xC0000374) и STATUS_BREAKPOINT (0x80000003). ↩ ↩2 ↩3

  8. Microsoft Learn, The Microsoft Error Lookup Tool. То, что это автономный инструмент, который показывает текст сообщения, связанный с шестнадцатеричным кодом состояния, по различным заголовочным файлам вроде Winerror.h; что имя файла загрузки — Err_6.4.5.exe; и что нужно учесть: комплект определений — на момент компиляции. ↩ ↩2 ↩3

  9. Microsoft Learn, certutil. То, что параметр -error у certutil показывает текст сообщения, связанный с кодом ошибки, и что запись ошибки, включающая имя символа, используется в виде вроде 0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND). ↩ ↩2

  10. Microsoft Learn, !error. То, что расширение !error в WinDbg декодирует и показывает значения ошибок Win32, Winsock, NTSTATUS и NetAPI; и что указание 1 как флага толкует как NTSTATUS. ↩ ↩2

  11. Microsoft Learn, How to: Map HRESULTs and exceptions. Механизм взаимного сопоставления HRESULT COM и исключений .NET; таблица соответствий вроде E_NOTIMPL → NotImplementedException; то, что HRESULT без явного соответствия преобразуется в COMException; и что Message, Source и подобные поля исключения инициализируются из сведений IErrorInfo. ↩ ↩2

  12. Microsoft Learn, RtlNtStatusToDosError function (winternl.h). То, что это функция, преобразующая код NTSTATUS в соответствующий системный код ошибки Win32; что ERROR_MR_MID_NOT_FOUND возвращается, когда соответствие не определено; и что функции обратного преобразования не существует. ↩ ↩2

  13. Microsoft Learn, Last-Error Code. То, что код последней ошибки хранится отдельно для каждого потока; что его следует забирать через GetLastError сразу после сбоя; что API, которые при успехе перезаписывают код нулём, и API, которые его не трогают, смешаны; и что бит 29 зарезервирован для кодов, определённых приложением. ↩ ↩2

  14. Microsoft Learn, Bug check code reference. Список кодов bug check (кодов STOP), показываемых на синем экране, и как показать сведения о коде расширением !analyze в WinDbg. То, что это своя система нумерации, отдельная от NTSTATUS, подтверждается списком. ↩ ↩2

  15. Microsoft Learn, Marshal.GetLastWin32Error Method. То, что это способ забрать код последней ошибки вызова P/Invoke, который поставил флаг SetLastError; что вызывать GetLastError напрямую через P/Invoke ненадёжно из-за перезаписи вызовом API внутри среды; и что с .NET 6 рекомендуется GetLastPInvokeError. ↩

Недавние статьи с теми же тегами помогут подробнее изучить близкие темы.

Эти страницы показывают тему статьи в более широком контексте услуг и решений.

Статья напрямую связана со следующими услугами.

Частые вопросы

Вопросы, которые часто возникают при консультациях по теме статьи.

Что означает ошибка 0x80004005?
0x80004005 — это HRESULT E_FAIL, и его смысл — «Unspecified failure» (неопределённый сбой). Иначе говоря, код лишь сообщает, что произошёл сбой, для которого нет подробной причины; сам по себе он причину не называет. Один и тот же 0x80004005 всплывает в несвязанных местах — сеть, Windows Update, VBA, драйвер базы данных — именно поэтому. Увидев этот код, не разбирайте его «в глубину». Сужайте причину по контексту: какое приложение и какая операция его вернули, и какие ещё сведения об ошибке есть в журнале событий или подробном журнале.
Что такое отрицательный код ошибки вроде -2147467259?
Это 32-битный HRESULT, показанный как знаковое десятичное число. У HRESULT при сбое установлен старший бит, поэтому в знаковом целом значение всегда отрицательное. В PowerShell команда '0x{0:X8}' -f -2147467259 возвращает шестнадцатеричную запись (в этом примере 0x80004005 = E_FAIL). Если в журнале или сообщении скрипта видно отрицательное число, которое начинается с -214…, первый шаг один: перевести в hex и уже потом искать.
Как проще всего узнать смысл кода ошибки?
Без дополнительной установки можно взять net helpmsg 5 в командной строке (для десятичного кода Win32) и certutil -error 0x80070005. certutil принимает и шестнадцатеричный HRESULT и показывает имя символа и текст сообщения. В PowerShell [System.ComponentModel.Win32Exception]::new(5).Message даёт локализованное сообщение. На машине разработки держите официальный инструмент Microsoft err.exe (Microsoft Error Lookup Tool): он ищет сразу по Win32, HRESULT и NTSTATUS и перечисляет подходящие определения.
Что за ошибка 0xC0000005?
Это NTSTATUS STATUS_ACCESS_VIOLATION, то есть нарушение доступа (некорректное обращение к памяти). Этот код чаще всего встречается как «код исключения» в журнале событий или в дампе при падении приложения и указывает на программную ошибку: разыменование неверного указателя или обращение к уже освобождённой памяти. По имени он похож на ошибку Win32 5 (ERROR_ACCESS_DENIED = отказано в доступе), но это несвязанный код другой системы; их нельзя путать. Надёжный способ найти причину — снять дамп сбоя и разобрать его в WinDbg.
Почему при одном и том же коде ошибки причина каждый раз разная?
Потому что код ошибки говорит только, какого рода сбой, а что именно не удалось и почему, определяет контекст вызова. Ошибка 5 (отказано в доступе), например, — один и тот же код при совершенно разных причинах: не хватает прав NTFS, нет прав администратора, антивирус блокирует доступ и так далее. В похожей ситуации, если другой процесс ещё держит файл открытым, придёт уже другой код (ошибка 32 = нарушение совместного доступа), и от того, как вы прочитаете код, зависит, куда смотреть. Ошибка 2 (файл не найден) часто тоже относится не к основному файлу, а к зависимой DLL или файлу настроек. Когда смысл кода понятен, краткий путь к причине — через Process Monitor или аналог проверить, какой API не сработал и против какого ресурса.

Об авторе

Страница с профилем автора статьи.

Го Комура

Представитель KomuraSoft LLC

Специализируется на разработке программного обеспечения для Windows, техническом консалтинге и расследовании сбоев, особенно в проектах с унаследованными системами и трудно воспроизводимыми ошибками.

Публичные ссылки

Вернуться в блог