potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

Win32 API NTSTATUSの覚書

Win32 APIの一部関数で実行結果を表す戻り値の型に使われるNTSTATUS型の覚書です。

C++

C++で使用する場合の情報です。

定義

ntstatus.hで32ビット符号付き整数(int)のエイリアスとして定義されます1。Win32 Errorのint型、HRESULTもintなので相互に代入可能ですが、ビット単位の扱いは異なります。

typedef LONG NTSTATUS;

関連ヘッダーファイル

C++では次のヘッダーをインクルードして使用できます。

  • ntdef.h
  • ntstatus.h

状態判定

NTSTATUS型にはビットマスクを用いたいくつかの状態が定義されており、次のマクロで確認できます。

  • NT_SUCCESS(x)
  • NT_INFORMATION(x)
  • NT_WARNING(x)
  • NT_ERROR(x)

Win32エラーコード、HRESULTとの変換

Win32エラーコードおよびHRESULT型とはマクロや関数を使用することで相互変換できます。

変換 マクロ・関数 ヘッダー
NTSTATUS → HRESULT HRESULT_FROM_NT(x)1 winerror.h
NTSTATUS → Win32 Error RtlNtStatusToDosError(Status)1 winternl.h
Win32 Error → NTSTATUS NTSTATUS_FROM_WIN32(x) ntstatus.h

HRESULTからNTSTATUSを取得するにはHRESULTをWin32 Errorに変換する必要があります。MAKE_HRESULTHRESULT_CODEを組み合わせることで実装可能とのことです。

C#

C#で使用する場合の情報です。C++からの移植です。

状態判定

マクロを関数へ移植することで実装できます。

public static partial class NTStatusUtility
{
    public static bool IsSuccess(int status) => status >= 0;
    public static bool IsInformation(int status) => (status >> 30) == 1;
    public static bool IsWarning(int status) => (status >> 30) == 2;
    public static bool IsError(int status) => (status >> 30) == 3;
}

HRESULTへの変換

HRESULT_FROM_NTマクロを関数へ移植して実装できます。

public static partial class NTStatusUtility
{
    public static int HResultFromNTStatus(int status)
    {
        const int FACILITY_NT_BIT = 0x10000000;
        return status | FACILITY_NT_BIT;
    }
}

例外クラス

COMExceptionクラスを継承した例外クラスを作成します。NTStatusUtilityクラスを使用する場合はこのクラスでHResultFromNTStatusを定義する必要はありません。

public sealed class NTStatusException : COMException
{
    public NTStatusException()
        : base()
    {
        Status = 0;
    }

    public NTStatusException(int status)
        : base(null, HResultFromNTStatus(status))
    {
        Status = status;
    }

    public NTStatusException(string message, int status)
        : base(message, HResultFromNTStatus(status))
    {
        Status = status;
    }

    public NTStatusException(string message, Exception inner)
        : base(message, inner)
    {
        Status = 0;
    }

    public NTStatusException(string message)
        : base(message)
    {
        Status = 0;
    }

    public readonly int Status;

    private static int HResultFromNTStatus(int status)
    {
        const int FACILITY_NT_BIT = 0x10000000;
        return status | FACILITY_NT_BIT;
    }
}