Как читать коды ошибок Windows — трёхслойная структура Win32, HRESULT и NTSTATUS

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

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

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

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

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

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
  • 8-значное значение, начинающееся с 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 → решить, какой это слой → разобрать и извлечь существенный код → прочитать его вместе с контекстом».

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 преобразование — одна строка.

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

# Hex → decimal
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 и т. п.) и кладут подробный код ошибки в «last-error code», хранимый на поток. Вызывающий забирает его через GetLastError сразу после подтверждения сбоя.13

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

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

Рис. 3: Читайте last-error code сразу после сбоя. Вставка другого вызова API между ними может его перезаписать.

Чтобы получить строку сообщения из кода, используйте FormatMessage с флагом 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);
}

Оставлять в журнале своего приложения и десятичное, и 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 (доступ запрещён): кандидаты причины широки — недостаточный NTFS ACL, запись в защищённую область без прав администратора, блокировка антивирусом или 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 Severity. 0 = успех, 1 = сбой
30 R Зарезервировано (часть severity при отображении 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, ITFFacility это?Перевести младшие 16 бит в десятичноеСмысл зависит от стороны, которая вернулаЧитать как ошибку Win32Искать в материалах вернувшей стороны

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

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

5.1. Раскладка и Severity

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

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

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

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

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

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

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

  • Код исключения сбоя приложения: «Exception code: 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 бита)Есть предел тому, что умещаетсяIErrorInfo несёт описание_com_error обрабатывает их вместеКод + описание диалога

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

6.2. Стиль .NET — от HRESULT к типу исключения

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

Отображение HRESULT на исключение .NETHRESULT сбоя, полученный в COM interop, преобразуется в соответствующий тип исключения, если известен, или в COMException, если неизвестен, и в любом случае исходное значение остаётся в Exception.HResultYesNoHRESULT сбояИзвестное отображение?Преобразовать в соответствующий тип исключенияПреобразовать в 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)
    // Another process is holding the file — wait a little and retry, for example
}

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

// 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 ищет строку сообщения ОС по коду ошибки 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 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 в WinDbg

Чтобы искать код при анализе дампа, расширение !error в WinDbg быстрое. По умолчанию оно толкует как код ошибки Win32; передайте 1 вторым аргументом — и оно толкует как 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>

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

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

Случай искать журнал, где написано «Error -2147467259 occurred», как есть, или путаться от «ошибка с минусом?». Увидев отрицательное, переведите в 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 одним и тем же из-за связи «5» уводит расследование в совершенно разные стороны — проблема прав против программной ошибки. Также код STOP синего экрана — другая система, чем NTSTATUS, поэтому поиск 0x9F в таблице NTSTATUS не даёт осмысленного ответа.14

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

Рис. 21: Не считайте их одним из-за связи «5». Ошибка 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); и то, что severity делится на четыре рода: успех (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. Роль бита severity 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. То, что 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. То, что это способ забрать last-error code вызова P/Invoke, который поставил флаг SetLastError; что вызывать GetLastError напрямую через P/Invoke ненадёжно из-за перезаписи вызовом API внутри среды; и что с .NET 6 рекомендуется GetLastPInvokeError. 

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

Приложения, которые ломаются после выхода из сна — как работают события питания Windows и как строить бизнес-приложения, которые это переживают

Открыли ноутбук — и соединения бизнес-приложения мертвы: причина в проекте, который не учитывал сон. Статья разбирает поток уведомлений W...

Что на самом деле значит «Не отвечает» — как Windows решает, что приложение зависло, и как проектировать приложения, которые не зависают

«Не отвечает» в Windows — механизм, в котором ОС судит, что окно не извлекало сообщение 5 секунд, и подменяет его окном-призраком. Статья...

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

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

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

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

Что означает ошибка 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, то есть нарушение доступа (незаконное обращение к памяти). Это код, который чаще всего виден как «Exception code» в журнале событий или в дампе сбоя при падении приложения, и он указывает на программную ошибку: разыменование неверного указателя или доступ к уже освобождённой памяти. По имени он похож на ошибку Win32 5 (ERROR_ACCESS_DENIED = доступ запрещён), но это несвязанный код другой системы; не путайте их. Надёжный способ найти причину — снять дамп сбоя и разобрать его в WinDbg.
Почему причина каждый раз разная, даже при одном и том же коде ошибки?
Потому что код ошибки представляет только «какой род сбоя», а «что не удалось и почему» решает контекст вызова. Ошибка 5 (доступ запрещён), например, — один и тот же код для совершенно разных причин: недостаточных прав NTFS, отсутствия прав администратора, блокировки антивирусом и так далее. В похожей ситуации, если другой процесс ещё держит файл открытым, вы получите другой код (ошибка 32 = нарушение совместного доступа), и правильное чтение кода меняет, куда смотреть. Ошибка 2 (файл не найден) часто тоже не основной файл, а зависимая DLL или файл настроек. Когда смысл кода найден, подтвердить, какой API не сработал против какого ресурса, через Process Monitor или аналог — короткий путь к причине.

Об авторе

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

Го Комура

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

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

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

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