Windowsのエラーコードを読み解く ── Win32エラー・HRESULT・NTSTATUSの三層構造

· 更新日: · · Windows, エラーコード, HRESULT, NTSTATUS, Win32 API, 障害調査, デバッグ, Windows開発

更新履歴(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点です。

  1. 表記を整え、コード体系を見分ける。Win32エラーコード・HRESULT・NTSTATUSは別体系です。10進と16進は同じ値の別表記で、HRESULTが符号付きの負数で表示されることもあります。まず16進8桁に揃え、返したAPIや表示された場所と合わせて読みます。123
  2. 0x8007xxxxは分解し、E_FAILは文脈調査へ進む。0x80070005はFACILITY_WIN32(7)のHRESULTで、下位16bitは5=ERROR_ACCESS_DENIEDです。対して0x80004005(E_FAIL)は「未指定の失敗」で、コードだけでは原因を絞れません。456
  3. コードの意味と、失敗した操作・対象をセットで調べる。同じエラー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

3体系をまたぐ変換の流れカーネルが返したNTSTATUSをWin32サブシステムがWin32エラーコードへ変換し、COM層がさらにHRESULTへ包み直すWin32サブシステムが変換COM層が包み直しカーネル・ドライバーNTSTATUS(エラーは0xC…)Win32エラーコード(5など)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進へ直す。これだけで調査の入口の迷子がかなり減ります。

同じコードの3つの見た目10進のエラー5と16進の0x5と0x80070005の下位16bitはすべて同じERROR_ACCESS_DENIEDを指す10進表記「エラー5」ERROR_ACCESS_DENIED16進表記「0x5」0x80070005の下位16bit表記が違うだけで同じコード

図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

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

図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進の両方とメッセージ本文を残しておくと、後日の調査が一段速くなります。

コードからメッセージを引いてログに残すFormatMessageにFORMAT_MESSAGE_FROM_SYSTEMフラグを指定してエラーコードのメッセージ文字列を取得し、ログには10進と16進とメッセージ本文を残すエラーコード(例: 5)FormatMessageで文字列取得メッセージ本文ログに記録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の昇格ダイアログで「いいえ」を選んだときなどに現れます。単に故障と捉えるのではなく、操作が「中止された」ことを示すコードとして読みます。

エラー998と5は別物998はNTSTATUSのアクセス違反がWin32層に変換されたメモリアクセス違反であり、アクセス拒否を表す5とは意味が異なるWin32層へ変換NTSTATUS 0xC0000005エラー998(ERROR_NOACCESS)意味はメモリアクセス違反エラー5(アクセス拒否)権限の問題。998とは別物

図5: エラー998はNTSTATUSのアクセス違反がWin32層に変換された姿で、アクセス拒否の5とは別物。

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

代表コードを覚えるだけでは、原因は特定できません。コードが教えるのは「失敗の種類」までで、その先に調べる対象が残ります。

コード 文脈によって変わること 次に確かめること
エラー5(アクセス拒否) NTFSのACL不足、管理者権限なしでの保護領域書き込み、ウイルス対策ソフトやAppLockerのブロック、サービスアカウントの権限不足など どのAPIが、どの対象へのアクセスを拒否されたか
エラー2(ファイルが見つからない) 指定ファイルとは限らず、暗黙にロードする依存DLL、32bit/64bitのレジストリリダイレクトで違う場所を見ていた設定ファイル、環境変数展開に失敗したパスなど 「どのファイル」が見つからなかったか
エラー32(共有違反) 別のプロセスが対象を使用している 「どのプロセス」が掴んでいるか
エラー5の原因は文脈で決まる同じアクセス拒否でもACL不足や管理者権限なしなど原因の候補は複数あり、どのAPIが何に失敗したかの特定が必要になるエラー5(アクセス拒否)ACL不足管理者権限なし対策ソフトのブロックサービス権限不足Procmonで失敗した対象を特定

図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…」の正体です。

Sビットと負数表示の関係失敗のHRESULTは最上位のSビットが1のため16進では0x8以上で始まり、符号付き32bit整数として表示すると負数になるSビット=1(失敗)16進は0x8以上で始まる符号付き表示では負数になる負数を見たら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をアクセス拒否と決めつけず、返ってきた値に応じて次の調査を選びます。

0x80004005と0x80070005の分解0x80004005は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へ包み直す

下位層のWin32エラーを、HRESULTを返すCOMメソッドや.NETランタイムへ伝えるために、winerror.hにはHRESULT_FROM_WIN32が用意されています。以下の失敗コードの例では、下位16bitにWin32エラー、Facilityに7、Sビットに1を入れます。4

HRESULT_FROM_WIN32の動作Win32エラーコードを下位16bitに格納しFacilityに7をSビットに1を設定して0x8007xxxxのHRESULTを組み立てるWin32エラーコード(例: 5)下位16bitに格納Facilityに7を設定Sビットに1を設定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、サーバー製品)のドキュメントで調べてください。

0x8007と0x8004で調べ方が変わるFACILITY_WIN32の0x8007xxxxは下位16bitの機械的な分解で読めるが、FACILITY_ITFの0x8004xxxxは意味の定義主体がインターフェイスごとに異なるため返したコンポーネントの資料で調べる7のWIN324のITFFacilityは?下位16bitを10進化意味は返し手ごとに異なるWin32エラーとして読む返し手の資料で調べる

図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

NTSTATUSは先頭1桁で種別が読める重大度が2bitあるためNTSTATUSは16進の先頭1桁が0xCならエラー0x8なら警告0x4なら情報0x0から0x3なら成功と読み分けられる0xC0x80x40x0〜0x3先頭の16進1桁は?エラー警告情報成功例: 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エラーに変換されてアプリに届く、という層の対応を確認できます。

例外コードとSTOPコードの読み分けイベントログの例外コードはNTSTATUSとして読み、ブルースクリーンのSTOPコードは別体系のバグチェックコードの専用リファレンスで引く例外コードSTOPコードどこに出たコード?NTSTATUSとして読むバグチェックコードの表で引く例: 0xC0000005例: 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層では粗い区分に丸められることもあるため、変換前後を区別して読みます。

NTSTATUSから他層への2つの橋渡しNTSTATUSはNビットを立ててHRESULT空間へマップする経路と、RtlNtStatusToDosErrorでWin32エラーコードへ変換する経路の2通りで他層へ渡るNビットを立てるRtlNtStatusToDosErrorNTSTATUS(0xC0000005)HRESULT(0xD0000005)Win32エラー998(ERROR_NOACCESS)対応未定義なら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をまとめて扱います。ダイアログに「コード+説明文」が出るアプリでは、この仕組みで説明文を運んでいることが多いです。

HRESULTを補うIErrorInfo32bitのHRESULTに詰められる情報には限りがあるため、エラーの説明文字列や発生源はIErrorInfoで別途伝えられ、C++では_com_errorクラスが両方をまとめて扱うHRESULT(32bitのみ)詰められる情報に限りがあるIErrorInfoが説明文を運ぶ_com_errorがまとめて扱うダイアログのコード+説明文

図14: 32bitのHRESULTに入らない説明文字列は、IErrorInfoが別途運ぶ。

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

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

HRESULTから.NET例外へのマップCOM相互運用で受け取った失敗のHRESULTは既知なら対応する例外型に、未知ならCOMExceptionに変換され、どちらでも元の値はException.HResultに保持されるはいいいえ失敗のHRESULT既知のマップがある?対応する例外型へ変換COMExceptionへ変換元の値はException.HResultに保持

図15: .NETはHRESULTを例外型へマップし、どの例外でも元の値はException.HResultに残る。

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

元のHRESULTを使って、例外処理を分岐する

どの例外でも元の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を直接呼ぶ場合は、宣言と取得方法をセットにします。

  1. DllImport(またはLibraryImport)にSetLastError = trueを指定する。
  2. 失敗を確認した直後に、Marshal.GetLastWin32Errorで取得する。.NET 6以降なら同等のGetLastPInvokeErrorが使える。16

GetLastError自体をP/Invoke定義して呼ぶ方法は避けます。ランタイム内部のAPI呼び出しで値が上書きされ得るため、正しい失敗理由を取得できないことがあるからです。16

P/Invokeでの最終エラー取得SetLastErrorをtrueにしてMarshal.GetLastWin32Errorで取得するのが正しく、GetLastErrorを直接P/Invokeするとランタイムの上書きで不正確になるP/InvokeでWin32 APIを呼ぶ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);

// 戻り値は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
err.exeの検索結果は文脈で選ぶerr.exeは多数のヘッダーファイルを横断して一致する定義を列挙するため、同じ数値に複数の候補が出たらどれが妥当かを文脈で選ぶerr 5 と入力多数のヘッダーを横断検索複数の定義がヒット文脈で妥当な候補を選ぶ

図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を選びます。

標準コマンドの使い分け10進のWin32エラーコードはnet helpmsgで調べられ、16進のHRESULTを含むコードはcertutilの-errorオプションで調べられる10進のWin3216進を含む手元のコードは?net helpmsgcertutil -error日本語メッセージが返る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で意味を確認する、という流れになります。

WinDbgでの例外コード確認の流れクラッシュダンプではanalyzeコマンドが例外コードを自動表示し、そのコードをerror拡張に第2引数1を付けて渡しNTSTATUSとして意味を確認するクラッシュダンプを開く!analyze -v を実行例外コードが表示される!error コード 1 で意味確認

図19: ダンプ解析では!analyze -vが表示した例外コードを、!errorにフラグ1を付けて調べる。

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

実際の調査では、次の5段階を順に進めます。名称を引いて終わりにせず、最後に失敗した操作と対象まで確かめるのがポイントです。

  1. 表記を整える。10進の負数なら16進8桁へ変換します。8桁未満の16進はゼロ埋めして読みます。
  2. どの層のコードか判定する。下の表で先頭の数桁から第一候補を絞り、返したAPIや表示された場所と突き合わせます。
  3. 分解して本質のコードを取り出す。0x8007xxxxのHRESULTなら下位16bit、0xDxxxxxxxのHRESULTならNビットを外して読みます。
  4. ツールで名称と定義を引く。err.exe、certutil、!errorなどでシンボル名とメッセージを確認します。
  5. 文脈と突き合わせる。どのアプリの、どの操作で、どのAPIが何に失敗したのかを、アプリログ・イベントログ・Procmonで特定します。コードは「失敗の種類」、文脈が「原因の場所」です。
エラーコード調査の手順表記を16進に整えて先頭の数桁で層を判定し、分解して本質のコードを取り出し、ツールで名称と定義を引いてから文脈と突き合わせるという調査の型10進表記0x80070xC0xD表記を整える(負数は16進8桁へ)先頭の数桁は?Win32エラーとして読む下位16bitを10進化NTSTATUSとして読むNビットを外して読むツールで名称と定義を引く文脈と突き合わせる(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

エラー5と0xC0000005は調査方向が違うWin32のエラー5は権限の問題として調べ、NTSTATUSの0xC0000005はプログラムのバグとして調べるべきで、同一視すると調査が違う方向へ逸れるWin32のエラー5権限の問題を調べるNTSTATUS 0xC0000005プログラムのバグを調べる別体系の無関係なコード

図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を使い分けます。

調査の型は、「表記を整える→層を判定→分解→名称を引く→文脈と突き合わせる」です。コードが教えるのは失敗の種類まで。次に見慣れない数字に出会ったら、検索ボックスへ貼る前に先頭の数桁と出どころを確かめてください。この最初の分解が、その後に調べる場所を決めます。

関連記事

関連する相談領域

合同会社小村ソフトでは、「このエラーコードの意味が分からない」「特定の環境でだけ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

  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

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

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

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

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

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

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

  13. Microsoft Learn, RegOpenKeyExW function. 成功時はERROR_SUCCESS、失敗時はWinerror.hで定義された非ゼロのエラーコードを戻り値として返すことについて。 ↩

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

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

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

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

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

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

よくある質問

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

エラー 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 ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。

ブログ一覧に戻る