.NET TIPS

Win32エラー・コードからエラー・メッセージを取得するには?[C#、VB]

デジタルアドバンテージ 一色 政彦
2008/05/15

 「TIPS:Win32 APIのWin32エラー・コードを取得するには?」では、Win32エラー・コードを取得する方法を紹介した。取得したWin32エラー・コードの中には、それに対応するエラー・メッセージが存在する場合がある(※存在しない場合もある)。コード番号だけではエラーの意味がよく分からないことが多いだろうが、エラー・メッセージを提示すればそれがエラーを解消する助けとなることもあるだろう。

 そこで本稿ではエラー・メッセージを取得する方法について紹介する。

エラー・メッセージを取得するには?

 Win32エラー・コードからエラー・メッセージを取得するには、FormatMessage関数(Win32 API)を利用すればよい。実際にこの関数を.NETのコードで利用するには、まずは次のような定義を行う。

[DllImport("kernel32.dll")]
static extern uint FormatMessage(
  uint dwFlags, IntPtr lpSource,
  uint dwMessageId, uint dwLanguageId,
  StringBuilder lpBuffer, int nSize,
  IntPtr Arguments);
<DllImport("Kernel32.dll")> _
Public Function FormatMessage( _
  ByVal dwFlags As Integer, ByRef lpSource As IntPtr, _
  ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, _
  ByVal lpBuffer As StringBuilder, ByVal nSize As Integer, _
  ByRef Arguments As IntPtr) As Integer
End Function
エラー・メッセージを取得するFormatMessage関数の定義(上:C#、下:VB)

 第1引数のdwFlagsにはメッセージの出力オプションを指定する。本稿の例では、次の出力オプションを指定する。これはシステムからメッセージを取得するというオプションである。

private const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
本TIPSで使用するメッセージの出力オプション(上:C#、下:VB)

 第2引数のlpSourceには、メッセージが定義されている場所(=ソース)を指定するが、ここでは限定しないことを意味する「IntPtr.Zero」(=0)を指定する。

 第3引数のdwMessageIdには(前掲のTIPSで取得した)Win32エラー・コードを指定する。

 第4引数のdwLanguageIdには言語識別子を指定するが、ここでは特定の言語に依存しないことを示す「0」を指定する。

 第5引数のlpBufferには文字列バッファを、第6引数のnSizeにはその文字列バッファに格納できる文字数を指定する。本TIPSでは、255文字分の文字列バッファを持つStringBuilderクラス(System.Text名前空間)のオブジェクト作成して第5引数に指定し、第6引数にはそのStringBuilderオブジェクトに格納できる文字数を返すCapacityプロパティの値を指定する。

 第6引数のArgumentsはメッセージをカスタマイズするときに使うが、本TIPSでは使用しないので「IntPtr.Zero」(=0)を指定する。

 それではFormatMessage関数を使った実際のサンプル・コードを示そう。次のコードは、「TIPS:Win32 APIのWin32エラー・コードを取得するには?」で示したサンプル・プログラムを拡張したものである。追記したのは太字の部分で、そこでFormatMessage関数を使ってWin32エラー・メッセージを取得してコンソールに出力している。

using System;
using System.Runtime.InteropServices;
using System.Text;

class BeepProgram {
  [DllImport("kernel32.dll", SetLastError = true)]
  private extern static bool Beep(uint dwFreq, uint dwDuration);

  [DllImport("kernel32.dll")]
  static extern uint FormatMessage(
    uint dwFlags, IntPtr lpSource,
    uint dwMessageId, uint dwLanguageId,
    StringBuilder lpBuffer, int nSize,
    IntPtr Arguments);

  private const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

  private static void Main() {
    bool ret = Beep(0x8000, 500);
    if (ret == false) {
      // エラーが発生
      int errCode = Marshal.GetLastWin32Error();
      Console.WriteLine("Win32エラー・コード:" +
        String.Format("{0:X8}", errCode));

      StringBuilder message = new StringBuilder(255);

      FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM,
        IntPtr.Zero,
        (uint)errCode,
        0,
        message,
        message.Capacity,
        IntPtr.Zero);
     
      Console.WriteLine("Win32エラー・メッセージ:" +
        message.ToString());
      // 出力結果:
      // Win32エラー・メッセージ:パラメータが間違っています。
    }
  }
}
Imports System.Runtime.InteropServices
Imports System.Text

Module BeepProgram

  <DllImport("kernel32.dll", SetLastError:=True)> _
  Private Function Beep _
    (ByVal dwFreq As Integer, ByVal dwDuration As Integer) As Boolean
  End Function

  <DllImport("Kernel32.dll")> _
  Public Function FormatMessage( _
    ByVal dwFlags As Integer, ByRef lpSource As IntPtr, _
    ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, _
    ByVal lpBuffer As StringBuilder, ByVal nSize As Integer, _
    ByRef Arguments As IntPtr) As Integer
  End Function

  Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000

  Sub Main()

    Dim ret As Boolean = Beep(&H8000, 500)
    If ret = False Then
      ' エラーが発生
      Dim errCode As Integer = Marshal.GetLastWin32Error()
      Console.WriteLine("Win32エラー・コード:" & _
        String.Format("{0:X8}", errCode))

      Dim message As New StringBuilder(255)

      FormatMessage( _
        FORMAT_MESSAGE_FROM_SYSTEM, _
        IntPtr.Zero, _
        errCode, _
        0, _
        message, _
        message.Capacity, _
        IntPtr.Zero)

      Console.WriteLine("Win32エラー・メッセージ:" & _
        message.ToString())
      ' 出力結果:
      ' Win32エラー・メッセージ:パラメータが間違っています。
    End If

  End Sub

End Module
Win32エラー・コードからエラー・メッセージを取得するサンプル・プログラム(上:C#、下:VB)

 このサンプル・プログラムの場合では「パラメータが間違っています。」というエラー・メッセージが表示される。これは、開発者にとって問題を解決するヒントになるだろう。なお、実際にはBeep関数の第1引数(パラメータ)に指定している(16進数で)「8000」という数値が範囲外のためエラーが発生している。End of Article

カテゴリ:クラス・ライブラリ 処理対象:Win32 API
使用ライブラリ:StringBuilderクラス(System.Text名前空間)
関連TIPS:Win32 APIのWin32エラー・コードを取得するには?

この記事と関連性の高い別の.NET TIPS
Win32 APIのWin32エラー・コードを取得するには?
実行ファイルからアプリケーションのアイコンを取得するには?
Win32 APIやDLL関数を呼び出すには?
INIファイルを読み書きするには?
ドライブをフォーマットするためのダイアログを表示するには?
このリストは、(株)デジタルアドバンテージが開発した
自動関連記事探索システム Jigsaw(ジグソー) により自動抽出したものです。
generated by

「.NET TIPS」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間