更新履歴(5件・最終更新 2026年09月07日)
この記事に加えた変更の記録です。アーカイブした更新前のバージョンは、DOI付きの固定URLから読めます。
- 元の主旨と調査方針を保ち、コード体系の見分け方、HRESULTの分解、ログ・例外からの取得、調査ツールと手順を小見出しと比較表で整理した。GetLastErrorを使うAPIと戻り値でエラーを返すAPIの例示も区別した。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの関係を総点検し、説明文と食い違っていた関係(向きの逆転・過剰な一般化・述語の取り違え)を修正しました。本文の説明は変えていません。
- 知識マップの「RtlNtStatusToDosErrorはNTSTATUSを実装する」という関係を、「NTSTATUSからWin32エラーコードへの変換を実装する」に改めました。本文の説明は変えていません。
- 仕組みの説明を図で追えるよう、Mermaid図を21点追加しました。3体系をまたぐ変換の流れ、表記の読み替え、GetLastErrorの読み方、FormatMessageによるメッセージ取得とログ記録、エラー998と5の違い、エラー5の原因分岐、HRESULTのSビットと負数の関係、0x80004005と0x80070005の分解の違い、HRESULT_FROM_WIN32の動作、0x8007と0x8004の調べ方の違い、NTSTATUSの種別判定と橋渡し、例外コードとSTOPコードの読み分け、IErrorInfoによる補足、.NET例外へのマップ、P/Invokeでのエラー取得、err.exe・標準コマンド・WinDbgでの調べ方、エラーコード調査手順の分岐、エラー5と0xC0000005の調査方向の違いを図にしています。本文の文章とコード、参考リンクは変えていません。
- 初版公開
この記事を引用する(DOI: 10.5281/zenodo.22054242)
この記事はZenodoにアーカイブされています。常に最新版へ解決されるDOIと、いま表示している版に固定されたDOIの両方を下に示します。
小村 豪(2026)「Windowsのエラーコードを読み解く ── Win32エラー・HRESULT・NTSTATUSの三層構造」合同会社小村ソフト. https://doi.org/10.5281/zenodo.22054242 https://comcomponent.com/blog/windows-error-codes-win32-hresult-ntstatus/
- DOI(最新版)
- 10.5281/zenodo.22054242
- DOI(この版)
- 10.5281/zenodo.22584765
「アプリの画面に0x80004005というエラーが出ました。どういう意味ですか」── 障害調査では定番のご相談です。数字をそのまま検索すると、Windows Update、共有フォルダー、VBA、データベース接続など、無関係な場面の対処法が並びます。
検索結果が散らばるのは、0x80004005(E_FAIL)が「詳細不明の失敗」という意味しか持たない汎用コードだからです。一方、0x80070005なら「Win32エラーの5番=アクセス拒否をHRESULTに包み直したもの」と分解できます。似た見た目でも、コードから読み取れる情報量は違います。
Windowsには、Win32エラーコード・HRESULT・NTSTATUSという3つの体系があり、層をまたぐときにコードが変換されます。調査を速くするには、数字を丸暗記するより、「どの層の誰が返したか」「包み直される前のコードは何か」を見分けるほうが有効です。
この記事は、中小企業の情シス担当者とWindowsアプリ開発者に向けた実務ガイドです。2026年8月時点のMicrosoft Learnと公開仕様書[MS-ERREF]をもとに、3体系の見分け方、HRESULTの分解、.NET例外との関係、err.exeやPowerShellによる調べ方を順につなぎます。
1. まず結論
最初に押さえるのは、次の3点です。
- 表記を整え、コード体系を見分ける。Win32エラーコード・HRESULT・NTSTATUSは別体系です。10進と16進は同じ値の別表記で、HRESULTが符号付きの負数で表示されることもあります。まず16進8桁に揃え、返したAPIや表示された場所と合わせて読みます。123
- 0x8007xxxxは分解し、E_FAILは文脈調査へ進む。0x80070005はFACILITY_WIN32(7)のHRESULTで、下位16bitは5=ERROR_ACCESS_DENIEDです。対して0x80004005(E_FAIL)は「未指定の失敗」で、コードだけでは原因を絞れません。456
- コードの意味と、失敗した操作・対象をセットで調べる。同じエラー5でも原因はACL、権限昇格、対策ソフトなどさまざまです。エラー2の対象が依存DLLのこともあれば、ファイルの占有はエラー32として現れることもあります。名称を調べたら、ログやProcess Monitorで「どのAPIが何に失敗したか」へ進みます。1
道具は、Windows標準のcertutil -errorとnet helpmsg、PowerShellのWin32Exception、開発機のerr.exe、ダンプ解析中のWinDbgの!errorを使い分けます。789 .NETの例外になっていても、元のHRESULTはException.HResultからたどれます。10
目的別の読み方
| 知りたいこと | 読む節 |
|---|---|
| 手元のコードを見分け、すぐ調べたい | 2章で表記を揃え、7章のコマンドと8章の調査手順へ |
| Win32 APIの失敗を正しくログに残したい | 3章のGetLastError・FormatMessage、6.3節のP/Invokeへ |
| 0x80004005と0x80070005、.NET例外の関係を理解したい | 4章のHRESULTの分解、6章のCOM・.NETへ |
| 0xC0000005など、クラッシュのコードを調べたい | 5章のNTSTATUSとSTOPコード、7.4節のWinDbgへ |
| 調査でよくある混同を避けたい | 9章の誤読例へ |
一文でまとめるなら、「表記を16進に揃える→どの層のコードか判定する→分解して本質のコードを取り出す→文脈と合わせて読む」が、Windowsエラーコード調査の型です。
図の実線は常に成り立つ関係、破線は条件付きの関係です(成立条件は詳細ページの各関係の説明に記載)。関係すべての一覧(全18件、根拠・確度つき)と主要概念の定義は知識マップ詳細ページにまとめています。データ: JSON-LD / Turtle
2. 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 |
この表の「見た目」は、体系を探すための手掛かりです。8章の判定表と同じく第一候補として使い、返したAPIやコンポーネントの情報と突き合わせます。
歴史的には、MS-DOS由来の番号を引き継ぐWin32エラーコード、NTカーネル内部のNTSTATUS、COMの導入時に成功/失敗と発生源を32bitに詰めるために設計されたHRESULTが積み重なってきました。
現在のWindowsでは、カーネルのNTSTATUS→Win32エラーコード→COM層のHRESULTという変換が日常的に起きています。上位層で見えたコードから下位層へたどり直すことが、調査の基本になります。114
flowchart TB
accTitle: 3体系をまたぐ変換の流れ
accDescr: カーネルが返したNTSTATUSをWin32サブシステムがWin32エラーコードへ変換し、COM層がさらにHRESULTへ包み直す
kernel["カーネル・ドライバー"] --> nt["NTSTATUS(エラーは0xC…)"]
nt -->|Win32サブシステムが変換| win["Win32エラーコード(5など)"]
win -->|COM層が包み直し| hr["HRESULT(0x8007xxxx)"]
図1: 層をまたぐ変換の流れ。カーネルのNTSTATUSがWin32エラーになり、さらにHRESULTへ包み直される。
2.1. 10進と16進の読み替えに慣れる
体系を調べる前に、表記の揺れをなくします。同じコードが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進へ直す。これだけで調査の入口の迷子がかなり減ります。
flowchart TB
accTitle: 同じコードの3つの見た目
accDescr: 10進のエラー5と16進の0x5と0x80070005の下位16bitはすべて同じERROR_ACCESS_DENIEDを指す
d["10進表記「エラー5」"] --> same["ERROR_ACCESS_DENIED"]
h["16進表記「0x5」"] --> same
l["0x80070005の下位16bit"] --> same
same -.-> memo["表記が違うだけで同じコード"]
図2: 10進・16進・HRESULTの下位16bitは、同じコードの別表記にすぎない。
3. Win32エラーコード ── GetLastErrorとFORMAT_MESSAGE
3.1. GetLastErrorの基本動作
戻り値を確認してから、最終エラーを保存する
CreateFileなど多くのWin32 APIは、失敗を戻り値(FALSE、NULL、INVALID_HANDLE_VALUEなど)で示し、詳細をスレッドごとの「最終エラーコード」に残します。この方式のAPIでは、失敗を確認した直後にGetLastErrorで取得します。12
ただし、エラーの取得方法はAPIごとに確認します。たとえばRegOpenKeyExは、最終エラーではなく戻り値そのものがエラーコードです。GetLastErrorを使う例とは分けて扱ってください。13
GetLastErrorを使うときの注意は、次の2つです。12
- 失敗の直後に読むこと。間に別のAPI呼び出し(ログ出力関数など)を挟むと、その呼び出しが最終エラーコードを上書きすることがあります。
- 成功時の値をあてにしないこと。成功時に最終エラーコードを0にクリアするAPIもあれば、触らないAPIもあります。戻り値で失敗を確認してから読むのが原則です。
sequenceDiagram
accTitle: GetLastErrorは失敗直後に読む
accDescr: 戻り値で失敗を確認したら他のAPI呼び出しを挟まず直後にGetLastErrorで最終エラーコードを取得する
participant app as アプリ
participant api as Win32 API
app->>api: CreateFile呼び出し
api-->>app: 失敗の戻り値
app->>api: GetLastError
api-->>app: コード5
Note over app: 間に別のAPIを挟むと上書きされ得る
図3: 最終エラーコードは失敗の直後に読む。間に別の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進の両方とメッセージ本文を残しておくと、後日の調査が一段速くなります。
flowchart TB
accTitle: コードからメッセージを引いてログに残す
accDescr: FormatMessageにFORMAT_MESSAGE_FROM_SYSTEMフラグを指定してエラーコードのメッセージ文字列を取得し、ログには10進と16進とメッセージ本文を残す
code["エラーコード(例: 5)"] --> fm["FormatMessageで文字列取得"]
fm --> msg["メッセージ本文"]
msg --> log["ログに記録"]
log -.-> both["10進と16進と本文を併記"]
図4: エラーコードはFormatMessageでメッセージ文字列に変換し、ログには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 | 操作がユーザーによって取り消された |
ここで混同しやすいのが、5番と998番です。998(ERROR_NOACCESS)は「アクセス拒否」ではなく、メモリアクセス違反のWin32表現です。後述するNTSTATUSのSTATUS_ACCESS_VIOLATIONが、Win32層へ変換された姿に当たります。
また、1223(ERROR_CANCELLED)はUACの昇格ダイアログで「いいえ」を選んだときなどに現れます。単に故障と捉えるのではなく、操作が「中止された」ことを示すコードとして読みます。
flowchart TB
accTitle: エラー998と5は別物
accDescr: 998はNTSTATUSのアクセス違反がWin32層に変換されたメモリアクセス違反であり、アクセス拒否を表す5とは意味が異なる
nt["NTSTATUS 0xC0000005"] -->|Win32層へ変換| e998["エラー998(ERROR_NOACCESS)"]
e998 -.-> m1["意味はメモリアクセス違反"]
e5["エラー5(アクセス拒否)"] -.-> m2["権限の問題。998とは別物"]
図5: エラー998はNTSTATUSのアクセス違反がWin32層に変換された姿で、アクセス拒否の5とは別物。
3.3. 同じコードでも文脈で意味が変わる
代表コードを覚えるだけでは、原因は特定できません。コードが教えるのは「失敗の種類」までで、その先に調べる対象が残ります。
| コード | 文脈によって変わること | 次に確かめること |
|---|---|---|
| エラー5(アクセス拒否) | NTFSのACL不足、管理者権限なしでの保護領域書き込み、ウイルス対策ソフトやAppLockerのブロック、サービスアカウントの権限不足など | どのAPIが、どの対象へのアクセスを拒否されたか |
| エラー2(ファイルが見つからない) | 指定ファイルとは限らず、暗黙にロードする依存DLL、32bit/64bitのレジストリリダイレクトで違う場所を見ていた設定ファイル、環境変数展開に失敗したパスなど | 「どのファイル」が見つからなかったか |
| エラー32(共有違反) | 別のプロセスが対象を使用している | 「どのプロセス」が掴んでいるか |
flowchart TB
accTitle: エラー5の原因は文脈で決まる
accDescr: 同じアクセス拒否でもACL不足や管理者権限なしなど原因の候補は複数あり、どのAPIが何に失敗したかの特定が必要になる
e5["エラー5(アクセス拒否)"] --> c1["ACL不足"]
e5 --> c2["管理者権限なし"]
e5 --> c3["対策ソフトのブロック"]
e5 --> c4["サービス権限不足"]
c1 --> next["Procmonで失敗した対象を特定"]
c2 --> next
c3 --> next
c4 --> next
図6: コードは「失敗の種類」しか教えない。エラー5の原因候補は複数あり、対象の特定が必要になる。
「どのAPIが・どのオブジェクト名に対して・どの結果を返したか」を実測するツールがProcess Monitorです。使い方は「Process Monitor(ProcMon)実践ガイド」で詳しく扱っています。エラーコードの意味を調べる作業と、失敗した対象を特定する作業は、車の両輪と考えてください。
4. HRESULT ── 32bitに詰め込まれた構造を読む
4.1. ビットレイアウト
HRESULTは、成功/失敗・発生源・詳細コードを1つの32bit値に詰めた形式です。まずSビットで成功/失敗、Facilityで発生源、Codeで詳細を見ると、後の分解例を追いやすくなります。公開仕様書[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…」の正体です。
flowchart TB
accTitle: Sビットと負数表示の関係
accDescr: 失敗のHRESULTは最上位のSビットが1のため16進では0x8以上で始まり、符号付き32bit整数として表示すると負数になる
s["Sビット=1(失敗)"] --> hex["16進は0x8以上で始まる"]
hex --> neg["符号付き表示では負数になる"]
neg --> back["負数を見たら16進に直して読む"]
図7: 失敗のHRESULTはSビットが1のため0x8以上で始まり、符号付き表示では負数になる。
Facilityは、次に引く資料の手掛かりになる
Facilityの代表値は次のとおりです。7ならWin32エラーの包み直し、4ならインターフェイスごとの定義、というように読み分けます。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を分解してみる
同じように見える2つのコードを、S・Facility・Codeに分けて比較します。
| 読み取る項目 | 0x80004005 | 0x80070005 |
|---|---|---|
| S | 1(失敗) | 1(失敗) |
| Facility | 0(FACILITY_NULL) | 7(FACILITY_WIN32) |
| Code | 0x4005 | 0x0005=5 |
| 定義 | E_FAIL:未指定の失敗 | E_ACCESSDENIED:アクセス拒否 |
| 次の調査 | 返したコンポーネントや付随ログを調べる | Win32エラー5として、拒否された操作・対象を調べる |
0x80004005は、コードだけでは原因を絞れません。Facilityは(0x80004005 >> 16) & 0x7FF = 0で、FACILITY_NULLの汎用コードE_FAILです。「未指定の失敗(Unspecified failure)」以上の詳細を持たないため、分解したら「どのコンポーネントが返したか」「同時刻のイベントログ・アプリログに詳細がないか」へ調査の軸足を移します。6
0x80070005は、Win32エラー5までたどれます。Facility=7、Code=5なので、ERROR_ACCESS_DENIEDをHRESULTに包み直した値と分かります。E_ACCESSDENIEDという別名も同じ値です。6
同じ「失敗」でも、分解して得られる情報量は違います。E_FAILをアクセス拒否と決めつけず、返ってきた値に応じて次の調査を選びます。
flowchart TB
accTitle: 0x80004005と0x80070005の分解
accDescr: 0x80004005はFACILITY_NULLの汎用コードE_FAILで詳細を持たず文脈調査へ移るべきで、0x80070005はFACILITY_WIN32でWin32エラー5番のアクセス拒否の包み直しと分かる
a["0x80004005"] --> af["Facility=0(FACILITY_NULL)"]
af --> ac["Code=0x4005 → E_FAIL"]
ac --> ax["未指定の失敗。文脈調査へ"]
b["0x80070005"] --> bf["Facility=7(FACILITY_WIN32)"]
bf --> bc["Code=0x0005 → 5"]
bc --> bx["ERROR_ACCESS_DENIED"]
図8: 同じ「失敗」でも分解すると情報量が違う。0x80070005はWin32エラー5番まで辿れる。
4.3. 最重要パターン: 0x8007xxxx = HRESULT_FROM_WIN32
Win32の失敗をHRESULTへ包み直す
下位層のWin32エラーを、HRESULTを返すCOMメソッドや.NETランタイムへ伝えるために、winerror.hにはHRESULT_FROM_WIN32が用意されています。以下の失敗コードの例では、下位16bitにWin32エラー、Facilityに7、Sビットに1を入れます。4
flowchart TB
accTitle: HRESULT_FROM_WIN32の動作
accDescr: Win32エラーコードを下位16bitに格納しFacilityに7をSビットに1を設定して0x8007xxxxのHRESULTを組み立てる
win["Win32エラーコード(例: 5)"] --> low["下位16bitに格納"]
low --> fac["Facilityに7を設定"]
fac --> sbit["Sビットに1を設定"]
sbit --> hr["0x80070005"]
図9: HRESULT_FROM_WIN32はWin32エラーを下位16bitに格納し、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)
逆向きに読むときは、下位16bitを取り出す
0x8007xxxxから元のWin32エラーを読むには、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は、返したコンポーネントの資料へ進む
同じ読み方を、0x8004xxxx(FACILITY_ITF)にそのまま当てはめてはいけません。こちらは意味を定義する主体がインターフェイスごとに異なるため、同じ32bit値でも返し手が違えば意味が違い得ます。5
見慣れない0x8004xxxxは、汎用の検索だけで決めず、それを返したコンポーネント(ライブラリ、ドライバーSDK、サーバー製品)のドキュメントで調べてください。
flowchart TB
accTitle: 0x8007と0x8004で調べ方が変わる
accDescr: FACILITY_WIN32の0x8007xxxxは下位16bitの機械的な分解で読めるが、FACILITY_ITFの0x8004xxxxは意味の定義主体がインターフェイスごとに異なるため返したコンポーネントの資料で調べる
hr{"Facilityは?"} -->|7のWIN32| w["下位16bitを10進化"]
hr -->|4のITF| i["意味は返し手ごとに異なる"]
w --> ww["Win32エラーとして読む"]
i --> ii["返し手の資料で調べる"]
図10: 0x8007xxxxは機械的に分解できるが、0x8004xxxxは返したコンポーネントの資料で調べる。
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 | 詳細コード |
HRESULTとの大きな違いは、重大度が2bitで、成功・情報・警告・エラーの4種類あることです。先頭の16進1桁では、たとえば0xC…がエラー(11)、0x8…が警告(10)、0x4…が情報(01)、0x0〜0x3…が成功に当たります。
そのため、0x8で始まるという見た目だけでHRESULTの失敗と決めてはいけません。NTSTATUSの0x80000003(STATUS_BREAKPOINT)はブレークポイント例外で、重大度は「エラー」ではなく「警告」です。314
flowchart TB
accTitle: NTSTATUSは先頭1桁で種別が読める
accDescr: 重大度が2bitあるためNTSTATUSは16進の先頭1桁が0xCならエラー0x8なら警告0x4なら情報0x0から0x3なら成功と読み分けられる
head{"先頭の16進1桁は?"} -->|0xC| e["エラー"]
head -->|0x8| w["警告"]
head -->|0x4| i["情報"]
head -->|0x0〜0x3| s["成功"]
w -.-> ex["例: 0x80000003は警告"]
図11: NTSTATUSは先頭の16進1桁で種別が読める。0x80000003は「エラーではなく警告」。
5.2. どこで出会うか ── 例外コード・STOPコード・イベントログ
NTSTATUSに出会う場所を、例外コード・STOPコード・Process Monitorに分けて見ていきます。
アプリケーションクラッシュの例外コード
イベントログの「Application Error(イベントID 1000)」に記録される「例外コード: 0xc0000005」はNTSTATUSです。クラッシュや起動失敗で見かける代表値には、次のものがあります。14
| 値 | シンボル | 意味 |
|---|---|---|
| 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とは別の独自番号体系です。専用のリファレンスを使います。15
「0xC0000005ならNTSTATUS、STOP 0x9Fならバグチェックコード」と分け、STOPコードをNTSTATUSの表で引かないことが大切です。
Process MonitorではResult列に現れる
ProcmonのResult列に出るNAME NOT FOUNDやACCESS DENIEDは、カーネルが返したNTSTATUS(STATUS_OBJECT_NAME_NOT_FOUNDやSTATUS_ACCESS_DENIED)の表示名です。ここではファイルI/Oの失敗をNTSTATUSの語彙で観測でき、それがWin32エラーに変換されてアプリに届く、という層の対応を確認できます。
flowchart TB
accTitle: 例外コードとSTOPコードの読み分け
accDescr: イベントログの例外コードはNTSTATUSとして読み、ブルースクリーンのSTOPコードは別体系のバグチェックコードの専用リファレンスで引く
q{"どこに出たコード?"} -->|例外コード| nt["NTSTATUSとして読む"]
q -->|STOPコード| bc["バグチェックコードの表で引く"]
nt -.-> n1["例: 0xC0000005"]
bc -.-> b1["例: 0x0000009F"]
図12: イベントログの例外コードはNTSTATUS、ブルースクリーンのSTOPコードは別体系。表の引き先を間違えない。
例外コードの先の調査、つまりクラッシュダンプの採取と解析については「Windowsクラッシュダンプ収集入門」と「WinDbg + SOSでクラッシュダンプを読む」を参照してください。
5.3. HRESULTとの関係 ── NビットとRtlNtStatusToDosError
NTSTATUSから他の体系へ渡す経路は2通りです。HRESULTへのマップと、Win32エラーへの変換は分けて考えます。
| 経路 | 行うこと | 例 |
|---|---|---|
| HRESULT空間へのマップ | HRESULT_FROM_NTでNビット(0x10000000)を立てる | 0xC0000005 → 0xD0000005 |
| Win32エラーへの変換 | RtlNtStatusToDosErrorで対応する番号へ変換する | STATUS_ACCESS_VIOLATION → ERROR_NOACCESS(998) |
HRESULTへのマップでは、Nビットを立ててNTSTATUS値をHRESULT空間に持ち込みます。したがって、0xDで始まるHRESULTはNビットを外し、NTSTATUSとして読むのが手順です。2
Win32エラーへの変換では、ntdllのRtlNtStatusToDosErrorを使います。対応がない値はERROR_MR_MID_NOT_FOUNDになります。11 0xC0000005は998へ、STATUS_OBJECT_NAME_NOT_FOUND(0xC0000034)はERROR_FILE_NOT_FOUND(2)へ変換されます。カーネル側の豊かな語彙がWin32層では粗い区分に丸められることもあるため、変換前後を区別して読みます。
flowchart TB
accTitle: NTSTATUSから他層への2つの橋渡し
accDescr: NTSTATUSはNビットを立ててHRESULT空間へマップする経路と、RtlNtStatusToDosErrorでWin32エラーコードへ変換する経路の2通りで他層へ渡る
nt["NTSTATUS(0xC0000005)"] -->|Nビットを立てる| hr["HRESULT(0xD0000005)"]
nt -->|RtlNtStatusToDosError| win["Win32エラー998(ERROR_NOACCESS)"]
win -.-> memo["対応未定義ならERROR_MR_MID_NOT_FOUND"]
図13: NTSTATUSの橋渡しは2通り。0xD始まりはNビットを外してNTSTATUSとして読む。
6. COMと.NET ── エラーコードは例外にどうマップされるか
6.1. COMの流儀 ── HRESULT + IErrorInfo
COMのメソッドはHRESULTを返すのが基本です。ただし、32bitのコードだけで伝えられる情報には限りがあります。
その補足がIErrorInfoです。エラーの説明文字列や発生源を別途伝えられ、C++ではコンパイラサポートの_com_errorクラスがHRESULTとIErrorInfoをまとめて扱います。ダイアログに「コード+説明文」が出るアプリでは、この仕組みで説明文を運んでいることが多いです。
flowchart TB
accTitle: HRESULTを補うIErrorInfo
accDescr: 32bitのHRESULTに詰められる情報には限りがあるため、エラーの説明文字列や発生源はIErrorInfoで別途伝えられ、C++では_com_errorクラスが両方をまとめて扱う
hr["HRESULT(32bitのみ)"] --> lim["詰められる情報に限りがある"]
lim --> ei["IErrorInfoが説明文を運ぶ"]
ei --> ce["_com_errorがまとめて扱う"]
ce -.-> dlg["ダイアログのコード+説明文"]
図14: 32bitのHRESULTに入らない説明文字列は、IErrorInfoが別途運ぶ。
6.2. .NETの流儀 ── HRESULTから例外型へ
.NETランタイムは、COM相互運用でHRESULTの失敗を受け取ると例外に変換します。既知のHRESULTは対応する例外型にマップされ、未知のものはCOMExceptionになります。10
flowchart TB
accTitle: HRESULTから.NET例外へのマップ
accDescr: COM相互運用で受け取った失敗のHRESULTは既知なら対応する例外型に、未知ならCOMExceptionに変換され、どちらでも元の値はException.HResultに保持される
hr["失敗のHRESULT"] --> known{"既知のマップがある?"}
known -->|はい| typed["対応する例外型へ変換"]
known -->|いいえ| comex["COMExceptionへ変換"]
typed --> keep["元の値はException.HResultに保持"]
comex --> keep
図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を使って、例外処理を分岐する
どの例外でも元のHRESULTはException.HResultに保持されます。たとえばファイルI/Oで「共有違反のときだけリトライしたい」なら、この値を条件にできます。次の例は、共有違反を表す0x80070020だけをcatchする部分です。
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が使える。16
GetLastError自体をP/Invoke定義して呼ぶ方法は避けます。ランタイム内部のAPI呼び出しで値が上書きされ得るため、正しい失敗理由を取得できないことがあるからです。16
flowchart TB
accTitle: P/Invokeでの最終エラー取得
accDescr: SetLastErrorをtrueにしてMarshal.GetLastWin32Errorで取得するのが正しく、GetLastErrorを直接P/Invokeするとランタイムの上書きで不正確になる
pi["P/InvokeでWin32 APIを呼ぶ"] --> ok["SetLastError=trueを指定"]
ok --> get["GetLastWin32Errorで取得"]
pi --> ng["GetLastErrorを直接呼ぶ定義"]
ng --> bad["ランタイムが上書きし不正確"]
図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);
// 戻り値は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. 変換・調査ツールの実務 ── コピペで使える早見
最初に、手元の環境と目的で道具を選びます。以下の各節に、そのまま使える例を置いています。
| 場面 | 道具 | 調べられること |
|---|---|---|
| 追加インストールなしで確認したい | certutil -error、net helpmsg | コードに対応する名称・メッセージ(7.2節) |
| 複数体系の定義を横断して調べたい | err.exe | ヘッダー内の定義候補(7.1節) |
| 数値を変換・分解したい | PowerShell | 10進/16進の変換、下位16bit、.NET例外へのマップ(7.3節) |
| ダンプ解析中に意味を確認したい | WinDbgの!error | Win32やNTSTATUSとしての解釈(7.4節) |
7.1. err.exe(Microsoft Error Lookup Tool)
Microsoftが配布する単体実行ファイルのエラー検索ツールです。winerror.hやntstatus.hなど多数のヘッダーファイルを横断して、指定したコードに一致する定義とメッセージを列挙します。7
err 0x80070005
err 5
err 0xC0000005
結果を見るときは、2点に注意します。
- 複数の候補から、文脈に合うものを選ぶ。たとえば「5」はWin32のERROR_ACCESS_DENIED以外の定義にも一致します。ヒットした名称を、そのまま原因と決めないでください。
- 収録された定義の時点を確認する。ダウンロードファイル名はバージョン付き(執筆時点ではErr_6.4.5.exe)で、コードの定義は同梱時点のヘッダーに基づきます。7
flowchart TB
accTitle: err.exeの検索結果は文脈で選ぶ
accDescr: err.exeは多数のヘッダーファイルを横断して一致する定義を列挙するため、同じ数値に複数の候補が出たらどれが妥当かを文脈で選ぶ
in["err 5 と入力"] --> scan["多数のヘッダーを横断検索"]
scan --> hits["複数の定義がヒット"]
hits --> pick["文脈で妥当な候補を選ぶ"]
図17: err.exeはヘッダー横断検索のため候補が複数出ることがあり、妥当なものは文脈で選ぶ。
7.2. Windows標準のコマンド
追加インストールなしで使えるのが、certutilとnet helpmsgです。certutilの-errorオプションはエラーコードに対応するメッセージテキストを表示し、16進HRESULTでも10進でも受け付けます。8
certutil -error 0x80070005
certutil -error 5
net helpmsg 5
net helpmsgはWin32エラーコードの10進数専用です。日本語環境ならメッセージが日本語で返るため、ユーザーへの説明にも使えます。16進のHRESULTを調べる場合は、上の例のようにcertutil -errorを選びます。
flowchart TB
accTitle: 標準コマンドの使い分け
accDescr: 10進のWin32エラーコードはnet helpmsgで調べられ、16進のHRESULTを含むコードはcertutilの-errorオプションで調べられる
q{"手元のコードは?"} -->|10進のWin32| net["net helpmsg"]
q -->|16進を含む| cert["certutil -error"]
net -.-> jp["日本語メッセージが返る"]
cert -.-> any["16進も10進も受け付ける"]
図18: 標準コマンドの使い分け。10進のWin32エラーはnet helpmsg、16進を含むならcertutil -error。
7.3. PowerShellワンライナー集
表記の変換、Win32メッセージの取得、HRESULTの分解と.NET例外へのマップをまとめた早見です。コードの意味を確認したあとも、失敗した操作と対象の調査は別に必要です。
# 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として解釈します。9
0:000> !error 5
Error code: (Win32) 0x5 (5) - アクセスが拒否されました。
0:000> !error 0xc0000005 1
Error code: (NTSTATUS) 0xc0000005 - <アクセス違反>
クラッシュダンプでは!analyze -vが例外コード(NTSTATUS)を自動表示するので、そこから!error <code> 1で意味を確認する、という流れになります。
flowchart TB
accTitle: WinDbgでの例外コード確認の流れ
accDescr: クラッシュダンプではanalyzeコマンドが例外コードを自動表示し、そのコードをerror拡張に第2引数1を付けて渡しNTSTATUSとして意味を確認する
dump["クラッシュダンプを開く"] --> an["!analyze -v を実行"]
an --> exc["例外コードが表示される"]
exc --> chk["!error コード 1 で意味確認"]
図19: ダンプ解析では!analyze -vが表示した例外コードを、!errorにフラグ1を付けて調べる。
8. 調査の手順 ── 層の判定から文脈との突き合わせまで
実際の調査では、次の5段階を順に進めます。名称を引いて終わりにせず、最後に失敗した操作と対象まで確かめるのがポイントです。
- 表記を整える。10進の負数なら16進8桁へ変換します。8桁未満の16進はゼロ埋めして読みます。
- どの層のコードか判定する。下の表で先頭の数桁から第一候補を絞り、返したAPIや表示された場所と突き合わせます。
- 分解して本質のコードを取り出す。0x8007xxxxのHRESULTなら下位16bit、0xDxxxxxxxのHRESULTならNビットを外して読みます。
- ツールで名称と定義を引く。err.exe、certutil、
!errorなどでシンボル名とメッセージを確認します。 - 文脈と突き合わせる。どのアプリの、どの操作で、どのAPIが何に失敗したのかを、アプリログ・イベントログ・Procmonで特定します。コードは「失敗の種類」、文脈が「原因の場所」です。
flowchart TB
accTitle: エラーコード調査の手順
accDescr: 表記を16進に整えて先頭の数桁で層を判定し、分解して本質のコードを取り出し、ツールで名称と定義を引いてから文脈と突き合わせるという調査の型
fix["表記を整える(負数は16進8桁へ)"] --> judge{"先頭の数桁は?"}
judge -->|10進表記| d1["Win32エラーとして読む"]
judge -->|0x8007| d2["下位16bitを10進化"]
judge -->|0xC| d3["NTSTATUSとして読む"]
judge -->|0xD| d4["Nビットを外して読む"]
d1 --> tool["ツールで名称と定義を引く"]
d2 --> tool
d3 --> tool
d4 --> tool
tool --> ctx["文脈と突き合わせる(Procmon等)"]
図20: 調査の型。表記を整え、層を判定して分解し、名称を引いてから文脈と突き合わせる。
| 見た目 | 第一候補 | 分解・変換の方法 |
|---|---|---|
| 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の具体例:0x80070002から、見つからないパスへ進む
アプリに「0x80070002」としか出なくても、ProcmonのResult列を見れば「どのプロセスが・どのパスに・NAME NOT FOUNDを返されたか」が分かります。コードの分解から、実際に失敗した対象の特定へ進むための観測です。
イベントログ側の調べ方は「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の表で引いても意味のある答えは出ません。15
flowchart TB
accTitle: エラー5と0xC0000005は調査方向が違う
accDescr: Win32のエラー5は権限の問題として調べ、NTSTATUSの0xC0000005はプログラムのバグとして調べるべきで、同一視すると調査が違う方向へ逸れる
a["Win32のエラー5"] --> ad["権限の問題を調べる"]
b["NTSTATUS 0xC0000005"] --> bd["プログラムのバグを調べる"]
a -.-> memo["別体系の無関係なコード"]
b -.-> memo
図21: 「5」繋がりで同一視しない。エラー5は権限の問題、0xC0000005はプログラムのバグへ向かう。
10. まとめ
まず体系を見分ける。Windowsの主なエラーコードはWin32エラーコード・HRESULT・NTSTATUSの3体系です。10進・16進・負数という表記の揺れを整え、どの層の誰が返したかを確認します。NTSTATUSはクラッシュの例外コードやProcmonのResult列で出会いますが、Win32のエラー5と0xC0000005は別物で、STOPコードもさらに別体系です。
次に構造を読み、必要な情報を取り出す。HRESULTはS/R/C/N/Xビット、11bitのFacility、16bitのCodeで構成されます。最重要パターンは0x8007xxxxで、下位16bitからWin32エラーを読めます。COM相互運用ではHRESULTが.NET例外型へマップされ、元の値はException.HResultに残ります。P/InvokeではSetLastError=trueとMarshal.GetLastWin32Errorをセットで使います。
最後は文脈と突き合わせる。E_FAIL(0x80004005)は原因を示すコードではありません。分解しても情報が増えないと分かったら、コードの深掘りをやめ、操作・対象・同時刻のログへ進みます。道具はcertutil・net helpmsg、err.exe、PowerShell、WinDbgの!errorを使い分けます。
調査の型は、「表記を整える→層を判定→分解→名称を引く→文脈と突き合わせる」です。コードが教えるのは失敗の種類まで。次に見慣れない数字に出会ったら、検索ボックスへ貼る前に先頭の数桁と出どころを確かめてください。この最初の分解が、その後に調べる場所を決めます。
関連記事
- WinDbg + SOSでクラッシュダンプを読む ── 収集した後の実務解析入門
- Windowsクラッシュダンプ収集入門 - WER/ProcDump/WinDbg
- 例外処理でcatchとログはどこに置くべきか
- Process Monitor(ProcMon)実践ガイド ── 「設定が読まれない」「ACCESS DENIED」を10分で特定する
- Windowsイベントログ・ETW入門 ── 業務アプリのログをOS標準の仕組みに乗せる
関連する相談領域
合同会社小村ソフトでは、「このエラーコードの意味が分からない」「特定の環境でだけ0x80070005が出る」といったエラーコード起点の障害調査、Win32 API・COM・.NETが混在するアプリのエラーハンドリング設計、クラッシュダンプやProcess Monitorを使った原因の特定を扱っています。エラーダイアログのスクリーンショット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
-
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
-
Microsoft Open Specifications, [MS-ERREF]: NTSTATUS. NTSTATUSのビットレイアウト(2bitのSev、Cビット、Nビット、12bitのFacility、16bitのCode)と、重大度が成功(00)・情報(01)・警告(10)・エラー(11)の4種に分かれることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, HRESULT_FROM_WIN32 macro. Win32システムエラーコードをHRESULT値にマップするwinerror.hのマクロの定義について。 ↩ ↩2 ↩3
-
Microsoft Learn, Structure of COM Error Codes. HRESULTの重大度ビットとファシリティフィールドの役割、FACILITY_NULL・FACILITY_RPC・FACILITY_ITF・FACILITY_WIN32・FACILITY_WINDOWSの各値、FACILITY_ITFのコードはインターフェイスごとに意味が定義され同じ値でも意味が異なり得ることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Common HRESULT values. E_FAIL(0x80004005)が「Unspecified failure(未指定の失敗)」であること、E_ACCESSDENIED(0x80070005)・E_INVALIDARG(0x80070057)・E_OUTOFMEMORY(0x8007000E)など頻出HRESULT値の定義について。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, The Microsoft Error Lookup Tool. 16進のステータスコードに関連付けられたメッセージテキストをWinerror.h等の各種ヘッダーファイル横断で表示する単体ツールであること、ダウンロードファイル名がErr_6.4.5.exeであること、収録定義がコンパイル時点のものである点に注意が必要なことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, certutil. certutilの-errorオプションがエラーコードに関連付けられたメッセージテキストを表示すること、および0x80070002 (WIN32: 2 ERROR_FILE_NOT_FOUND)のような形式でシンボル名を含むエラー表記が用いられることについて。 ↩ ↩2
-
Microsoft Learn, !error. WinDbgの!error拡張がWin32・Winsock・NTSTATUS・NetAPIのエラー値をデコードして表示すること、フラグに1を指定するとNTSTATUSとして解釈することについて。 ↩ ↩2
-
Microsoft Learn, How to: Map HRESULTs and exceptions. COMのHRESULTと.NET例外の相互マップの仕組み、E_NOTIMPL→NotImplementedExceptionなどの対応表、明示的なマップがないHRESULTはCOMExceptionに変換されること、IErrorInfoの情報から例外のMessageやSource等が初期化されることについて。 ↩ ↩2
-
Microsoft Learn, RtlNtStatusToDosError function (winternl.h). NTSTATUSコードを対応するWin32システムエラーコードへ変換する関数であること、対応が定義されていない場合はERROR_MR_MID_NOT_FOUNDが返ること、逆変換を行う関数は存在しないことについて。 ↩ ↩2
-
Microsoft Learn, Last-Error Code. 最終エラーコードがスレッドごとに保持されること、失敗直後にGetLastErrorで取得すべきこと、成功時にコードを0で上書きするAPIとしないAPIが混在すること、ビット29がアプリケーション定義コード用に予約されていることについて。 ↩ ↩2
-
Microsoft Learn, RegOpenKeyExW function. 成功時はERROR_SUCCESS、失敗時はWinerror.hで定義された非ゼロのエラーコードを戻り値として返すことについて。 ↩
-
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
-
Microsoft Learn, Bug check code reference. ブルースクリーンに表示されるバグチェックコード(STOPコード)の一覧と、WinDbgの!analyze拡張でコードの情報を表示する方法について。NTSTATUSとは別の独自番号体系であることが一覧から確認できる。 ↩ ↩2
-
Microsoft Learn, Marshal.GetLastWin32Error Method. SetLastErrorフラグを設定したP/Invoke呼び出しの最終エラーコードを取得する方法であること、GetLastErrorを直接P/Invokeするのはランタイム内部のAPI呼び出しによる上書きのため信頼できないこと、.NET 6以降はGetLastPInvokeErrorが推奨されることについて。 ↩ ↩2
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
Time Travel Debugging ── 長期稼働で再現しない不具合を「録画」して巻き戻す
月に一度しか出ない不具合は、クラッシュダンプでは結果しか写りません。WinDbgのTime Travel Debugging(TTD)で実行を録画して巻き戻す方法を、TTD.exeの録画設計、リングバッファ、TTD.Callsクエリ、ダンプとの使い分けまで解説します。
引数はなぜ壊れるか ── Windowsのコマンドライン引数の規則
Windowsでは引数の配列は存在せず、CreateProcessに渡るのは1本の文字列で、分割は受け取り側が行います。CommandLineToArgvW・CRT・.NETの分割規則と、.NETのArgumentList・C++での正しい組み立て方を解説します。
親が落ちたあとに何が残るか ── Job Objectで子プロセスを飼う
UIを強制終了してもSDKのヘルパーが残り、カメラやCOMポートを握ったままになるのはなぜか。Job Objectでプロセスツリーを一つの単位にし、KillOnJobCloseと完了ポートで子プロセスの寿命を設計する方法を計測アプリ目線で解説します。
Win32スレッドプールAPI ── CreateThreadpoolWorkで「スレッドを作らない」並行処理
ネイティブコードでCreateThreadを乱立させていませんか。Vistaで刷新されたWin32スレッドプールAPIのwork・timer・wait・ioの4オブジェクト、クリーンアップグループ、コールバックでの禁止事項までを一次情報にもとづいて解説します。
名前付きパイプの実務 ── Windowsプロセス間通信の定番を設計からセキュリティまで
Windowsのプロセス間通信の定番・名前付きパイプを実務目線で解説します。バイト/メッセージモードの選択、複数クライアントを捌くサーバー設計、ACLと偽装のセキュリティ、.NETのNamedPipeStreamまで、一次情報にもとづき整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
不具合調査・原因解析
再現しにくい障害、長期稼働後の不具合、通信停止などの調査を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- エラー 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などで確認するのが原因特定の近道です。