
VBAでWinAPIエラーコードを「番号→名前→意味」まで一気に辿る実践ガイド(FormatMessageとError名の取得法)
WinAPIをVBAから呼び出すと、失敗時に「エラー番号(error code)」だけが返ってきて途方に暮れることがあります。0なら成功と分かっても、5や87、そして見慣れない5桁の数値が出た瞬間、調査コストが跳ね上がるのが現場のあるあるです。
この記事では、WinAPIのエラーコードを扱う基本(エラー番号・説明文・名前の違い)から、FormatMessageで説明文を得る方法、さらに「番号から ERROR_ACCESS_DENIED のような“エラー名”を返す」実装アイデア(Enum化モジュール方式)まで、VBA視点でまとめます。
WinAPIエラーコードの基礎:番号・説明文・名前は別物
WinAPIの多くは、戻り値で成功/失敗を返し、詳細は別途「最後のエラー」としてエラーコードが提供されます。VBAでは典型的に次のような情報が欲しくなります。
-
エラー番号:例)
5、87、15841 -
説明文:例)「アクセスが拒否されました。」のような人間向け文言
-
エラー名:例)
ERROR_ACCESS_DENIED、ERROR_INVALID_PARAMETER、ERROR_API_UNAVAILABLE
説明文はユーザー表示に向きますが、開発者としては「エラー名」の方が検索性・分類・ログ分析に圧倒的に便利です。番号だけだと意図が読めず、説明文は曖昧だったり環境依存(ローカライズ)だったりします。一方、エラー名はログの“キー”として強い、というわけです。
説明文を取るならFormatMessageが王道
エラー番号から説明文を得たい場合、Windowsの FormatMessage を使うのが定番です。VBAでも宣言して呼べば、OSが持つメッセージテーブルから説明文を引いてくれます。
ポイントは次の通りです。
-
取得できるのは基本的に説明文(ユーザー向けの文章)
-
言語・OSバージョンに左右される可能性がある
-
ログ用途なら便利だが、「ERROR_~」の定数名は返ってこない
つまり「説明文だけで足りる」ケースには最適ですが、「番号→エラー名」が欲しいケースでは別の手段が必要です。
なぜ“エラー名”はそのまま取れないのか
WinAPIのエラー名は、C/C++のヘッダ(例:WinError.h)で #define ERROR_ACCESS_DENIED 5 のように定義されている“定数名”です。
OSのAPIが直接「名前」を返す仕組みは一般的ではなく、Windowsが返すのはあくまで数値と(必要なら)説明文です。そのため「番号→名前」をやるなら、結局どこかに 番号と名前の対応表 を持つ必要があります。
現実解:Enumに“ほぼ全エラー”を載せて逆引きする
実務で繰り返し調べるのが面倒なら、VBA側に「対応表」を持たせるのが最短です。考え方はシンプルで、次のような構成にします。
-
Enum:
ERROR_SUCCESS = 0のように、エラー名と番号を網羅的に定義 -
Public関数:番号を渡すと、該当するEnumメンバー名(文字列)を返す
-
補助関数:VBEで「関数が大きすぎる」問題を回避するため分割
この方式のメリットは、ログに ERROR_INVALID_FUNCTION のような“意味のある文字列”を残せることです。番号のままより桁違いに読みやすく、説明文よりブレません。
実装イメージ(考え方の要点)
VBAで「値からEnum名」を直接取る仕組みはないため、実装では次のどれかを使います。
-
Select Caseを自動生成して名前を返す(高速だが巨大化しやすい) -
Enumの定義を使いつつ、内部で対応表(配列/Dictionary)を持つ
-
コード生成(外部で一覧を作り、モジュールに貼り込む)で保守
記事中の例のように「モジュール(.bas)をインポートして使う」設計は、配布と導入が簡単で、プロジェクト間の使い回しにも向きます。
使い方の流れ:VBAプロジェクトに組み込む
現場での運用は次の順で固めるとスムーズです。
-
エラー名を逆引きするモジュール(.bas)をVBAプロジェクトにインポート
-
WinAPI呼び出し後に得られたエラー番号を、公開関数へ渡す
-
返ってきた「エラー名」をログ・例外メッセージ・診断出力に使う
-
必要なら
FormatMessageで説明文も併記し、ユーザー向け文面を整える
ログ例としては「番号+名前+説明文」の3点セットが強力です。
障害調査ではまず名前で当たりを付け、必要に応じて説明文で補足する運用が最短距離になります。
「obsolete(廃止)」コードが含まれる点に注意
Microsoftのエラーコード一覧には「obsolete」とされるものが混ざります。Enumを“全網羅”しようとすると、次の判断が必要です。
-
今も発生しうるか(古いAPIのみ、互換性目的、など)
-
定義しておく価値があるか(ログ解析の互換性重視なら残す)
-
保守コスト(無理に完全一致を目指さず「主要なもの優先」も現実的)
実際には「頻出(アクセス拒否、引数不正、見つからない、権限、共有違反など)」を厚めにし、残りは段階的に追加する設計が破綻しにくいです。
開発者目線のおすすめ:ログは“人間が検索できる形”に寄せる
WinAPI連携の不具合は、再現が難しいほどログ品質がものを言います。おすすめは次の形です。
-
ログキー:エラー名(例:
ERROR_ACCESS_DENIED) -
補助情報:エラー番号(例:
5) -
表示文:FormatMessageの説明文(例:アクセスが拒否されました)
こうしておくと、コードレビューでも運用でも「読む→検索する→直す」が速くなります。
まとめ:番号だけの時代を終わらせる
WinAPIのエラーコードは膨大で、手作業の参照はすぐに限界が来ます。
説明文は FormatMessage で取れる一方、エラー名は対応表を持たない限り得られません。だからこそ、Enumと逆引き関数をモジュール化してプロジェクトに組み込み、「番号→名前」を即座に返せる状態を作るのが、VBAでWinAPIを扱う上での最短の投資対効果になります。
必要なときに、必要な形(ユーザー向け/開発者向け)でエラー情報を出せるようにしておく――それだけで、WinAPI連携のトラブルシューティングは一段ラクになります。