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()」マクロによって判定すること。