HRESULT型とは?

HRESULTとはlong型の数値だ。この型はCOMインターフェース関連の関数の戻り値として利用されることが多い。

関数の戻り値として使われることの多いBOOL型が成功を意味するのは「1」(=TRUE)で失敗が「0」(=FALSE)なのと似ている。

大きな違いはBOOL型がTRUEとFALSEの2値しか取らないのに対して、HRESULT型では0x00000000~0xFFFFFFFFまでの多くの値が利用される。そのためBOOL型では失敗の原因を取得するためにGetLastError()を利用する必要があったが、HRESULT型では値を見るだけで失敗の原因まで分かる。

HRESULT型として使われる値は下のような規則に則って決定されている。これは「winerror.h」のコメント内に記述されているものだ。

//  HRESULTs are 32 bit values layed out as follows:
//
//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
//  +-+-+-+-+-+---------------------+-------------------------------+
//  |S|R|C|N|r|    Facility         |               Code            |
//  +-+-+-+-+-+---------------------+-------------------------------+
//
//  where
//
//      S - Severity - indicates success/fail
//
//          0 - Success
//          1 - Fail (COERROR)
//
//      R - reserved portion of the facility code, corresponds to NT's
//              second severity bit.
//
//      C - reserved portion of the facility code, corresponds to NT's
//              C field.
//
//      N - reserved portion of the facility code. Used to indicate a
//              mapped NT status value.
//
//      r - reserved portion of the facility code. Reserved for internal
//              use. Used to indicate HRESULT values that are not status
//              values, but are instead message ids for display strings.
//
//      Facility - is the facility code
//
//      Code - is the facility's status code


要約すると

・上位1bitが「1」なら"失敗"、「0」なら"成功"
・16~26bitまでの11ビットの値はカテゴリ
・0~15bitまでの下位WORDの値は詳細情報

のように値が決定されている。つまり、あるHRESULT型の値が"成功"を示しているか、それとも"失敗"を示しているのかは

	HRESULT	hr;

	hr = function_example();

	if(hr & 0x80000000)
	{
		//上位1bitが「1」なので成功
	}
	else
	{
		//失敗
	}


というように判定できる。

この判別を簡単にするために「winerror.h」内では以下の2つのマクロが定義されている。

#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
#define FAILED(hr) (((HRESULT)(hr)) < 0)


これを利用すると成功と失敗の判別は以下のようにできる。

	HRESULT	hr;

	hr = function_example();

	if(SUCCEEDED(hr))
	{
		//成功
	}
	else
	{
		//失敗
	}

	if(SUCCEEDED(hr))
	{
		//成功
	}

	if(FAILED(hr))
	{
		//失敗
	}


また、前に述べたようにHRESULT型では値を参照することで失敗の原因を知ることができる。例えば...

	HRESULT	hr;

	hr = function_example();

	switch(hr)
	{
	case	S_OK:
		//成功
		break;

	case	E_FAIL:
		//一般的な失敗
		break;

	case	E_OUTOFMEMORY:
		//メモリー不足による失敗
		break;

	case	E_INVALIDARG:
		//引数不正による失敗
		break;

	case	E_UNEXPECTED:
		//予期せぬ失敗
		break;

	case	E_OUTOFMEMORY:
		//による失敗
		break;

	case	E_POINTER:
		//不正なポインターによる失敗
		break;

	(...省略...)

	default:
		//その他(の失敗時もしくは成功時)
		break;
	}


のようにできる。ここで、例えば「E_OUTOFMEMORY」が示す数値はWin32の場合は「0x8007000E」だがMacの場合は「0x80000002」のようにプラットフォームによって値が変わることがある。そのため具体的な数値をソースコードに記述してはいけない。

定義されている値から推測できるように「S_」から始まるものは"成功"を示し、「E_」から始まるものは"失敗"を示す。また、多くの場合成功時は「S_OK」が返る。しかし、成功時は必ずS_OKというわけではない。そのため先に述べた「SUCCEEDED()」マクロによって判定すること。


カテゴリー「コラム」 のエントリー