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という3つの体系が層をなしており、しかも層をまたいで相互に変換されます。この構造を一度頭に入れておくと、「このコードはどの層の誰が返したのか」「本質のコードは何か」を自力で判定できるようになり、調査の初動が大きく速くなります。

この記事では、中小企業の情シス担当者とWindowsアプリ開発者を対象に、3つのエラーコード体系の見分け方と分解の仕方、.NET例外との関係、そしてerr.exeやPowerShellでの実務的な調べ方までを、2026年8月時点のMicrosoft Learnと公開仕様書[MS-ERREF]にもとづいて整理します。

1. まず結論

  • Windowsのエラーコードは主に3体系あります。Win32エラーコード(GetLastErrorが返す10進の小さな数)、HRESULT(COM以降の32bitコード、0x8で始まる16進か10進の負数)、NTSTATUS(カーネル層のコード、エラーは0xCで始まる)です。123
  • 10進と16進は同じコードの別表記です。「エラー5」と「0x5」と「0x80070005の下位16bit」はすべてERROR_ACCESS_DENIED(アクセス拒否)を指します。1
  • 0x8007xxxxは「Win32エラーの包み直し」です。HRESULTのFACILITY_WIN32(7)にWin32エラーコードを格納したもので、下位16bitを10進に直せば本質のコードが分かります。これがエラーコード読解の最重要パターンです。45
  • 0x80004005(E_FAIL)は原因コードではありません。意味は「未指定の失敗」であり、これ以上の情報を持ちません。このコードを深掘りするより、出どころの文脈と付随するログを探すべきです。6
  • 10進の負数(-2147467259など)はHRESULTです。32bitの最上位ビット(失敗ビット)が立っているため、符号付き表示では負になります。16進に直してから読みます。2
  • 0xCで始まる8桁はNTSTATUSです。0xC0000005(アクセス違反)や0xC0000135(DLLが見つからない)は、クラッシュ時のイベントログやダンプで頻出します。Win32エラーの5番とは無関係です。7
  • 同じコードでも意味は文脈で変わります。エラー5の原因はACL・権限昇格・ウイルス対策・占有などさまざまで、エラー2の「見つからないファイル」が依存DLLであることも珍しくありません。コードの意味と、どのAPIが何に対して失敗したかは、必ずセットで読みます。1
  • 変換・検索ツールは標準で揃っています。certutil -errornet helpmsgはWindows標準、PowerShellのWin32Exceptionでメッセージ取得、開発機にはerr.exe(Microsoft Error Lookup Tool)、ダンプ解析ではWinDbgの!errorが使えます。8910
  • .NETではHRESULTが例外型にマップされます。既知のHRESULTは対応する例外型(E_ACCESSDENIED→UnauthorizedAccessExceptionなど)へ、未知のものはCOMExceptionへ変換され、元の値はException.HResultに残ります。11

一文でまとめるなら、「表記を16進に揃える→どの層のコードか判定する→分解して本質のコードを取り出す→文脈と合わせて読む」が、Windowsエラーコード調査の型です。

2. Windowsには3つのエラーコード体系がある

まず全体地図です。Windowsのエラーコードは、返し手の層によって主に次の3体系に分かれます。

体系 主な返し手 典型的な見た目 代表例
Win32エラーコード Win32 API(GetLastError)、コマンドの終了コード 10進の小さな数(0〜15999) 5 = ERROR_ACCESS_DENIED
HRESULT COMコンポーネント、シェル、インストーラー、多くのフレームワーク 0x8で始まる8桁の16進、または10進の負数 0x80004005 = E_FAIL
NTSTATUS カーネル、ドライバー、ネイティブAPI(ntdll) エラーは0xCで始まる8桁の16進 0xC0000005 = STATUS_ACCESS_VIOLATION

歴史的には、MS-DOS由来のエラー番号を引き継いだWin32エラーコード、NT カーネルが内部で使うNTSTATUS、COMの導入時に「成功/失敗と発生源を32bitに詰める」ために設計されたHRESULTという順で積み重なってきました。現在のWindowsでは、カーネルがNTSTATUSを返し、Win32サブシステムがそれをWin32エラーコードに変換し、COM層がさらにHRESULTへ包み直す、という変換の流れが日常的に起きています。124

2.1. 10進と16進の読み替えに慣れる

3体系の判別の前に、表記の揺れを吸収する必要があります。同じコードが場面によって10進でも16進でも表示されるからです。

  • 「エラー5」「エラーコード: 0x5」→ 同じERROR_ACCESS_DENIED
  • 「エラー1223」「0x4C1」→ 同じERROR_CANCELLED
  • 「0x80070005」「-2147024891」→ 同じHRESULT

PowerShellなら読み替えは一行です。

# 10進 → 16進
'0x{0:X8}' -f 1223          # 0x000004C1
'0x{0:X8}' -f -2147024891   # 0x80070005 (負数=HRESULTを16進へ)

# 16進 → 10進
0x4C1                        # 1223

「-214…」で始まる10進の負数を見たら、反射的に16進へ直す。これだけで調査の入口の迷子がかなり減ります。

3. Win32エラーコード ── GetLastErrorとFORMAT_MESSAGE

3.1. GetLastErrorの基本動作

CreateFileRegOpenKeyExなど多くのWin32 APIは、失敗を戻り値(FALSE、NULL、INVALID_HANDLE_VALUEなど)で示し、詳細なエラーコードはスレッドごとに保持される「最終エラーコード」に格納します。呼び出し側は失敗を確認した直後にGetLastErrorで取得します。13

ここで実務上の注意が2つあります。13

  1. 失敗の直後に読むこと。間に別のAPI呼び出し(ログ出力関数など)を挟むと、その呼び出しが最終エラーコードを上書きすることがあります。
  2. 成功時の値をあてにしないこと。成功時に最終エラーコードを0にクリアするAPIもあれば、触らないAPIもあります。戻り値で失敗を確認してから読むのが原則です。

コードからメッセージ文字列を得るには、FORMAT_MESSAGE_FROM_SYSTEMフラグ付きのFormatMessageを使います。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);
}

自作アプリのログには、このように10進と16進の両方とメッセージ本文を残しておくと、後日の調査が一段速くなります。

3.2. 現場で頻出する代表コード

Win32エラーコードは0〜15999の範囲で定義されており、Microsoft Learnに全一覧があります。1 中でも障害調査で繰り返し出会うのは次の顔ぶれです。

10進 16進 シンボル 意味
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の昇格ダイアログでユーザーが「いいえ」を選んだときなどに現れる、エラーというより「中止された」ことを示すコードです。

3.3. 同じコードでも文脈で意味が変わる

代表コードの表を覚えるより重要なのが、エラーコードは「失敗の種類」しか教えてくれないという感覚です。

  • エラー5(アクセス拒否): NTFSのACL不足、管理者権限なしでの保護領域書き込み、ウイルス対策ソフトやAppLockerのブロック、サービスアカウントの権限不足など、原因の候補は多岐にわたります。
  • エラー2(ファイルが見つからない): ユーザーが指定したファイルとは限りません。EXEが暗黙にロードしようとした依存DLL、レジストリのリダイレクト(32bit/64bit)で違う場所を見ていた設定ファイル、環境変数展開に失敗したパスなど、「どのファイルが」見つからないのかはコードからは分かりません。
  • エラー32(共有違反): 「どのプロセスが掴んでいるのか」が本題ですが、コードはそれを教えてくれません。

「どのAPIが・どのオブジェクト名に対して・どの結果を返したか」を実測するツールがProcess Monitorです。使い方は「Process Monitor(ProcMon)実践ガイド」で詳しく扱っています。エラーコードの意味を調べる作業と、失敗した対象を特定する作業は、車の両輪と考えてください。

4. HRESULT ── 32bitに詰め込まれた構造を読む

4.1. ビットレイアウト

HRESULTは、成功/失敗・発生源・詳細コードを1つの32bit値に詰めた形式です。公開仕様書[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 発生源を示すファシリティコード(11bit)
15–0 Code ファシリティ内での詳細コード(16bit)

最上位のSビットが1、つまり16進表記が0x8以上で始まるHRESULTは失敗です。これを符号付き32bit整数として表示すると負数になる、というのが前述の「-214…」の正体です。

Facilityの代表値は次のとおりです。5

Facility 16進の見た目 意味
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とは情報量がまったく違います。

4.3. 最重要パターン: 0x8007xxxx = HRESULT_FROM_WIN32

Win32エラーコードしか返せない下位層の失敗を、HRESULTを返す上位層(COMメソッドや.NETランタイム)へ伝えるために、winerror.hにはHRESULT_FROM_WIN32マクロが用意されています。4 動作は「下位16bitにWin32エラーコード、FacilityにFACILITY_WIN32(7)、Sビットに1を設定する」というものです。

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)

逆向きに読むときはPowerShellで下位16bitを取り出します。

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

2つめの例のように、WinINetやWinHTTPのエラー(12000番台)もWin32エラーコード空間に定義されているため1、ネットワーク系の0x8007xxxxも同じ手順で分解できます。「0x8007を見たら下位4桁を10進に直す」を体に覚えさせるのが、この記事でお持ち帰りいただきたい一番の実務スキルです。

なお、0x8004xxxx(FACILITY_ITF)には逆の注意があります。FACILITY_ITFのコードは意味を定義する主体がインターフェイスごとに異なるため、同じ32bit値でも返し手が違えば意味が違い得ます。5 見慣れない0x8004xxxxは汎用の検索ではなく、それを返したコンポーネント(ライブラリ、ドライバーSDK、サーバー製品)のドキュメントで調べてください。

5. NTSTATUS ── カーネル層のコードとクラッシュの世界

5.1. レイアウトとSeverity

NTSTATUSはカーネル、デバイスドライバー、ntdllのネイティブAPIが使う32bitコードで、レイアウトはHRESULTと似て非なるものです。3

ビット位置 名前 意味
31–30 Sev 重大度。00=成功、01=情報、10=警告、11=エラー
29 C Customerビット
28 N 予約(HRESULTへのマップを可能にするため0)
27–16 Facility ファシリティ(12bit)
15–0 Code 詳細コード

重大度が2bitあるため、先頭の16進1桁で種別が読めます。0xC…はエラー(11)、0x8…は警告(10)、0x4…は情報(01)、0x0〜0x3…は成功です。ブレークポイント例外の0x80000003(STATUS_BREAKPOINT)が「エラーではなく警告」の代表例です。37

5.2. どこで出会うか ── 例外コード・STOPコード・イベントログ

情シス担当者や開発者がNTSTATUSに出会う場面は、主にクラッシュ関連です。

  • アプリケーションクラッシュの例外コード: イベントログの「Application Error(イベントID 1000)」に記録される「例外コード: 0xc0000005」がNTSTATUSです。代表的な値は次のとおりです。7
シンボル 意味
0xC0000005 STATUS_ACCESS_VIOLATION アクセス違反(不正なメモリアクセス)
0xC0000135 STATUS_DLL_NOT_FOUND 必要なDLLが見つからず起動できない
0xC00000FD STATUS_STACK_OVERFLOW スタックオーバーフロー
0xC0000374 STATUS_HEAP_CORRUPTION ヒープ破損
  • ブルースクリーンのSTOPコード: 一見似ていますが、STOPコード(バグチェックコード)は0x0000009F(DRIVER_POWER_STATE_FAILURE)のようにNTSTATUSとは別の独自番号体系で、専用のリファレンスがあります。14 「0xC0000005ならNTSTATUS、STOP 0x9FならバグチェックコードでNTSTATUSの表を引いてはいけない」という区別だけ覚えておけば十分です。
  • Process MonitorのResult列: ProcmonのResult列に出るNAME NOT FOUNDやACCESS DENIEDは、カーネルが返したNTSTATUS(STATUS_OBJECT_NAME_NOT_FOUNDやSTATUS_ACCESS_DENIED)の表示名です。ファイルI/Oの失敗をNTSTATUSの語彙で観測し、それがWin32エラーに変換されてアプリに届く、という層の対応を実感できる場所でもあります。

例外コードの先の調査、つまりクラッシュダンプの採取と解析については「Windowsクラッシュダンプ収集入門」と「WinDbg + SOSでクラッシュダンプを読む」を参照してください。

5.3. HRESULTとの関係 ── NビットとRtlNtStatusToDosError

NTSTATUSと他の2層の橋渡しは、2通りあります。

  1. HRESULT空間へのマップ: HRESULTのNビット(0x10000000)を立てると、NTSTATUS値をそのままHRESULT空間に持ち込めます(winerror.hのHRESULT_FROM_NTマクロ)。0xC0000005をマップすると0xD0000005になる、という具合です。0xDで始まるHRESULTを見たら、Nビットを外してNTSTATUSとして読むのが正しい手順です。2
  2. Win32エラーコードへの変換: ntdllのRtlNtStatusToDosErrorが、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層では粗い区分に丸められることがある、という点も覚えておくと役立ちます。

6. COMと.NET ── エラーコードは例外にどうマップされるか

6.1. COMの流儀 ── HRESULT + IErrorInfo

COMのメソッドはHRESULTを返すのが基本ですが、32bitに詰められる情報には限りがあるため、補足としてIErrorInfoという仕組みでエラーの説明文字列や発生源を別途伝えられます。C++ではコンパイラサポートの_com_errorクラスがHRESULTとIErrorInfoをまとめて扱います。エラーダイアログに「コード+説明文」が出るアプリは、この仕組みで説明文を運んでいることが多いです。

6.2. .NETの流儀 ── HRESULTから例外型へ

.NETランタイムは、COM相互運用でHRESULTの失敗を受け取ると例外に変換します。既知のHRESULTは対応する例外型にマップされ、未知のものはCOMExceptionになります11

HRESULT .NETの例外型
E_ACCESSDENIED (0x80070005) UnauthorizedAccessException
E_OUTOFMEMORY (0x8007000E) OutOfMemoryException
E_INVALIDARG (0x80070057) ArgumentException
E_NOTIMPL (0x80004001) NotImplementedException
マップ未定義の値 COMException(ErrorCodeプロパティに元の値)

どの例外でも、元のHRESULTはException.HResultプロパティに保持されています。ファイルI/Oの例外処理で「共有違反のときだけリトライしたい」といった分岐は、この値で書けます。

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

P/InvokeでWin32 APIを直接呼ぶ場合は、DllImport(またはLibraryImport)にSetLastError = trueを指定したうえで、Marshal.GetLastWin32Error(.NET 6以降は同等のGetLastPInvokeError)で取得します。GetLastError自体をP/Invoke定義して呼ぶのは、ランタイム内部のAPI呼び出しが値を上書きし得るため不正確です。15

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

// 戻り値はIntPtrではなくSafeFileHandleで受け、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エラーコードからOSのメッセージ文字列を引いてくれるため、ログにコードとメッセージの両方を残す用途にそのまま使えます。例外をどの層でcatchしてどうログに残すべきかという設計論は「例外処理でcatchとログはどこに置くべきか」で扱っています。

7. 変換・調査ツールの実務 ── コピペで使える早見

7.1. err.exe(Microsoft Error Lookup Tool)

Microsoftが配布する単体実行ファイルのエラー検索ツールです。winerror.hやntstatus.hなど多数のヘッダーファイルを横断して、指定したコードに一致する定義とメッセージを列挙します。8

err 0x80070005
err 5
err 0xC0000005

1つの数値が複数のヘッダーでヒットすることがあり(たとえば「5」はWin32のERROR_ACCESS_DENIED以外にも各所の定義に一致します)、候補の中からどれが妥当かは文脈で選ぶ必要があります。ダウンロードファイル名はバージョン付き(執筆時点ではErr_6.4.5.exe)で、コードの定義は同梱時点のヘッダーに基づく点にも注意してください。8

7.2. Windows標準のコマンド

追加インストールなしで使えるのが、certutilとnet helpmsgです。certutilの-errorオプションはエラーコードに対応するメッセージテキストを表示し、16進HRESULTでも10進でも受け付けます。9

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

net helpmsgはWin32エラーコードの10進数専用ですが、日本語環境ならメッセージが日本語で返るため、ユーザーへの説明にそのまま使えます。

7.3. PowerShellワンライナー集

# Win32エラーコード → OSのメッセージ文字列
[System.ComponentModel.Win32Exception]::new(5).Message
# → アクセスが拒否されました。

# 10進の負数 → 16進表記(HRESULTの正体を確認)
'0x{0:X8}' -f -2147467259     # 0x80004005

# 0x8007xxxx → 下位16bitのWin32エラーコード
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. WinDbgの!error

ダンプ解析中にコードを調べるなら、WinDbgの!error拡張が手早いです。既定ではWin32エラーコードとして、第2引数に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で意味を確認する、という流れになります。

8. 調査の手順 ── 層の判定から文脈との突き合わせまで

ここまでの知識を、実際のエラーコード調査の手順に組み立てます。

  1. 表記を整える。10進の負数なら16進8桁へ変換します。8桁未満の16進はゼロ埋めして読みます。
  2. どの層のコードか判定する。下の判定表のとおり、先頭の数桁でほぼ決まります。
  3. 分解して本質のコードを取り出す。0x8007xxxxなら下位16bit、0xDxxxxxxxならNビットを外す、という機械的な操作です。
  4. ツールで名称と定義を引く。err.exe、certutil、!errorのいずれかで、シンボル名とメッセージを確認します。
  5. 文脈と突き合わせる。どのアプリの・どの操作で・どのAPIが・何に対して失敗したのかを、アプリログ・イベントログ・Procmonで特定します。コードは「失敗の種類」、文脈が「原因の場所」です。
見た目 第一候補 分解・変換の方法
1〜5桁の10進数(5、1223など) Win32エラーコード そのままnet helpmsgやerr.exeへ
10進の負数(-2147024891など) HRESULT 16進8桁に直してから下の行の判定へ
0x8007xxxx HRESULT(FACILITY_WIN32) 下位16bitを10進化しWin32として読む
0x8004xxxx HRESULT(FACILITY_ITF) 返したコンポーネントのドキュメントで調べる
0x8000xxxx HRESULT(FACILITY_NULL) E_FAIL等の汎用コード。文脈調査へ軸足を移す
0xCxxxxxxx NTSTATUS(エラー) !error <code> 1、必要ならWin32へ変換して読む
0xDxxxxxxx NTSTATUSのHRESULTマップ Nビット(0x10000000)を外してNTSTATUSとして読む
0x8024xxxxなど独自Facility 機能領域固有のHRESULT Facility値から領域を特定して専用資料へ(0x8024…はWindows Update)2

手順5の「文脈との突き合わせ」で特に効くのがProcess MonitorのResult列です。アプリには「0x80070002」としか出ていなくても、Procmonで見れば「どのプロセスが・どのパスに・NAME NOT FOUNDを返されたか」が1行で分かります。イベントログ側の調べ方は「Windowsイベントログ・ETW入門」も参考にしてください。

9. よくある誤読 ── 調査を遠回りさせるパターン

最後に、実際の相談で見かける誤読のパターンを挙げます。

誤読1: 0x80004005を「特定の原因を示すコード」だと思う

E_FAILは「未指定の失敗」であり、Windows Updateでもネットワークでもデータベースでも同じ値が出ます。このコードで検索して出てきた対処法を手当たり次第に試すのは、ほぼ確実に遠回りです。コードではなく「どのアプリ・どの操作・同時刻の他のログ」から絞り込んでください。6

誤読2: 10進の負数がHRESULTだと気づかない

「エラー -2147467259 が発生しました」というログを、そのまま検索したり「マイナスのエラー?」と混乱したりするケースです。負数を見たら16進に直す。それだけで0x80004005(E_FAIL)だと分かり、誤読1の知識に接続できます。

誤読3: 0x8007xxxxを8桁まるごと調べて、下位のWin32エラーを見ない

0x80070005の本質は「5=アクセス拒否」です。8桁全体で検索するより、下位16bitを取り出して「Win32のエラー5が、この操作の文脈で何を意味するか」を考えるほうが速く核心に届きます。

誤読4: 「同じコード=同じ原因」だと思い込む

過去に「エラー5はウイルス対策ソフトが原因だった」経験があると、次のエラー5でも同じ対処に飛びつきがちです。コードが同じでも、失敗したAPIと対象リソースが違えば原因は別物です。コードの意味の確認と、Procmon等による対象の特定は毎回セットで行ってください。

誤読5: Win32のエラー5と0xC0000005、STOPコードとNTSTATUSを混同する

「5」繋がりでERROR_ACCESS_DENIEDとSTATUS_ACCESS_VIOLATIONを同一視すると、権限の問題とプログラムのバグという全く違う方向へ調査が逸れます。また、ブルースクリーンのSTOPコードはNTSTATUSとは別体系なので、0x9FをNTSTATUSの表で引いても意味のある答えは出ません。14

10. まとめ

  • Windowsのエラーコードは、Win32エラーコード・HRESULT・NTSTATUSの三層構造です。どの層の誰が返したコードかを最初に判定します。
  • 表記の揺れ(10進/16進/負数)は機械的に揃えられます。負数は16進8桁に直してから読みます。
  • HRESULTはS/R/C/N/Xビット+Facility(11bit)+Code(16bit)の構造で、0x8007xxxxはWin32エラーの包み直しという最重要パターンです。下位16bitを10進化して本質のコードを取り出します。
  • 0x80004005(E_FAIL)のような汎用コードは原因を示しません。コードの深掘りをやめて文脈調査に切り替える判断も、構造を知っているからこそできます。
  • NTSTATUSはクラッシュの例外コードやProcmonのResult列で出会います。0xC0000005はアクセス違反で、Win32のエラー5とは無関係です。STOPコードはさらに別体系です。
  • .NETではHRESULTが例外型にマップされ、元の値はException.HResultに残ります。P/InvokeではSetLastError=trueとMarshal.GetLastWin32Errorをセットで使います。
  • 調べる道具は、certutil -error・net helpmsg(標準)、err.exe(開発機)、PowerShellワンライナー、WinDbgの!errorで揃います。
  • 手順は「表記を整える→層を判定→分解→名称を引く→文脈と突き合わせる」。コードが教えるのは失敗の種類まで、原因の場所は文脈が教えてくれます。

次に見慣れないエラーコードに出会ったら、検索ボックスに貼り付ける前に、まず先頭の数桁を見てください。0x8007なら下位4桁、0xCならNTSTATUS、負数なら16進化 ── この10秒の分解が、その後の調査時間を大きく左右します。

関連記事

関連する相談領域

合同会社小村ソフトでは、「このエラーコードの意味が分からない」「特定の環境でだけ0x80070005が出る」といったエラーコード起点の障害調査、Win32 API・COM・.NETが混在するアプリのエラーハンドリング設計、クラッシュダンプやProcess Monitorを使った原因の特定を扱っています。エラーダイアログのスクリーンショット1枚からのご相談でも構いません。

参考リンク

  1. Microsoft Learn, Debug system error codes. Win32システムエラーコード(0〜15999)の一覧への索引と、GetLastErrorが返すコードのメッセージをFORMAT_MESSAGE_FROM_SYSTEMフラグ付きのFormatMessageで取得すること、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ビット、11bitのFacility、16bitのCode)、NビットがNTSTATUS値をHRESULT空間にマップしたことを示すこと、FACILITY_WINDOWS_UPDATE(36)を含むファシリティコードの一覧について。  2 3 4 5

  3. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. NTSTATUSのビットレイアウト(2bitのSev、Cビット、Nビット、12bitのFacility、16bitのCode)と、重大度が成功(00)・情報(01)・警告(10)・エラー(11)の4種に分かれることについて。  2 3

  4. Microsoft Learn, HRESULT_FROM_WIN32 macro. Win32システムエラーコードをHRESULT値にマップするwinerror.hのマクロの定義について。  2 3

  5. Microsoft Learn, Structure of COM Error Codes. HRESULTの重大度ビットとファシリティフィールドの役割、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(未指定の失敗)」であること、E_ACCESSDENIED(0x80070005)・E_INVALIDARG(0x80070057)・E_OUTOFMEMORY(0x8007000E)など頻出HRESULT値の定義について。  2 3 4

  7. Microsoft Open Specifications, [MS-ERREF]: NTSTATUS values. STATUS_ACCESS_VIOLATION(0xC0000005)、STATUS_DLL_NOT_FOUND(0xC0000135)、STATUS_STACK_OVERFLOW(0xC00000FD)、STATUS_HEAP_CORRUPTION(0xC0000374)、STATUS_BREAKPOINT(0x80000003)を含むNTSTATUS値の一覧について。  2 3

  8. Microsoft Learn, The Microsoft Error Lookup Tool. 16進のステータスコードに関連付けられたメッセージテキストをWinerror.h等の各種ヘッダーファイル横断で表示する単体ツールであること、ダウンロードファイル名がErr_6.4.5.exeであること、収録定義がコンパイル時点のものである点に注意が必要なことについて。  2 3

  9. Microsoft Learn, certutil. certutilの-errorオプションがエラーコードに関連付けられたメッセージテキストを表示すること、および0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND)のような形式でシンボル名を含むエラー表記が用いられることについて。  2

  10. Microsoft Learn, !error. WinDbgの!error拡張がWin32・Winsock・NTSTATUS・NetAPIのエラー値をデコードして表示すること、フラグに1を指定するとNTSTATUSとして解釈することについて。  2

  11. Microsoft Learn, How to: Map HRESULTs and exceptions. COMのHRESULTと.NET例外の相互マップの仕組み、E_NOTIMPL→NotImplementedExceptionなどの対応表、明示的なマップがないHRESULTはCOMExceptionに変換されること、IErrorInfoの情報から例外のMessageやSource等が初期化されることについて。  2

  12. Microsoft Learn, RtlNtStatusToDosError function (winternl.h). NTSTATUSコードを対応するWin32システムエラーコードへ変換する関数であること、対応が定義されていない場合はERROR_MR_MID_NOT_FOUNDが返ること、逆変換を行う関数は存在しないことについて。  2

  13. Microsoft Learn, Last-Error Code. 最終エラーコードがスレッドごとに保持されること、失敗直後にGetLastErrorで取得すべきこと、成功時にコードを0で上書きするAPIとしないAPIが混在すること、ビット29がアプリケーション定義コード用に予約されていることについて。  2

  14. Microsoft Learn, Bug check code reference. ブルースクリーンに表示されるバグチェックコード(STOPコード)の一覧と、WinDbgの!analyze拡張でコードの情報を表示する方法について。NTSTATUSとは別の独自番号体系であることが一覧から確認できる。  2

  15. Microsoft Learn, Marshal.GetLastWin32Error Method. SetLastErrorフラグを設定したP/Invoke呼び出しの最終エラーコードを取得する方法であること、GetLastErrorを直接P/Invokeするのはランタイム内部のAPI呼び出しによる上書きのため信頼できないこと、.NET 6以降はGetLastPInvokeErrorが推奨されることについて。 

同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。

このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。

この記事は次のサービスページにつながります。近い入口からご覧ください。

よくある質問

この記事のテーマについて、相談時によくある質問をまとめています。

エラー 0x80004005 とはどういう意味ですか?
0x80004005はHRESULTのE_FAILで、意味は「未指定の失敗(Unspecified failure)」です。つまり「詳細な理由を報告できない失敗が起きた」ことを示すだけで、原因そのものを表すコードではありません。ネットワーク、Windows Update、VBA、データベースドライバーなど無関係な場面で同じ0x80004005が出るのはこのためです。このコードを見たら、コードの意味を深掘りするのではなく、どのアプリのどの操作で出たのかという文脈と、イベントログや詳細ログに残る別のエラー情報から原因を絞り込んでください。
-2147467259 のような負の数のエラーコードは何ですか?
32bitのHRESULTを符号付き10進数で表示したものです。HRESULTは失敗時に最上位ビットが1になるため、符号付き整数として表示すると必ず負の数になります。PowerShellで '0x{0:X8}' -f -2147467259 を実行すると16進表記(この例では0x80004005=E_FAIL)に戻せます。ログやスクリプトのエラーメッセージで-214…から始まる負の数を見たら、まず16進に直してから調べるのが定石です。
エラーコードの意味を調べる一番手軽な方法は何ですか?
追加インストールなしで使えるのは、コマンドプロンプトの net helpmsg 5(Win32エラーの10進数用)と certutil -error 0x80070005 です。certutilは16進の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や設定ファイルが見つからないケースが珍しくありません。コードの意味を調べたら、どのAPIがどのリソースに対して失敗したのかをProcess Monitorなどで確認するのが原因特定の近道です。

著者プロフィール

記事の著者プロフィールページです。

小村 豪

合同会社小村ソフト 代表

Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る