ENGLISH page is here.
GET DinopSearchBar
サイト内検索:
HOME
VC++ TIPS
ダウンロード
DinopExifReader
DinopSearchBar
DinopSearchBar mini
DinopTabbingBar
for Firefox
大阪湾の生き物
甲子園浜の自然
甲子園浜の干潟
甲子園浜の水中
甲子園浜の野鳥
近畿の山々
植物図鑑
箕面マップ
水中機材
カメラ
ランキング
望遠鏡の世界
顕微鏡の世界
Googleのすべて
GoogleマップAPI
ニュース
読んだ本
日記
変な料理の作り方
遺伝子操作
論文紹介
デイトレード
自動売買でFX
ネットで小遣い稼ぎ
Solaris
電子工作
その他
問い合わせ
VC++用コード集
大阪湾の生き物
水中用機材
since:2000/11/15
dinopcom@gmail.com
www.dinop.comは
だいのっぷ・どっと・こむ
と読んでください。







« 掲載ソースコードについて | メイン | ディスク容量取得 »

HRESULT型の判定にSUCCEEDEDやFAILEDは使えない(ことがある)




解説

 COMインターフェースは結果をHRESULT型で返すことが多い。しかしその戻り値を単純にFAILEDやSUCCEEDED マクロを使って判定すると実行時に例外などのエラーが発生することがある。

 それは失敗時にS_FALSEを返す関数があるためだ。この値はSUCCEEDEDマクロでTRUE、FAILEDマクロでFALSE となる「成功」タイプの値だ。成功とは言うもののFALSEという微妙な値になっている。

 BOOL型でも同じような問題がある。BOOLの場合はif(ret == TRUE)は正常に判定できないことがあるので if(ret != FALSE)やif(ret)のように成功判定をする。しかしHRESULT型の場合は単純にif(!FAILED(hr))の ようには解決できない。



HRESULT関連の実装

 HRESULT型でよく使われるS_OKやSUCCEEDEDマクロなどはヘッダーの中で以下のように定義 されている。

 ここから分かるようにS_OKもS_FALSEもSUCCEEDEDマクロで真(TRUE)となる。

#define S_OK                                   ((HRESULT)0x00000000L)
#define S_FALSE                                ((HRESULT)0x00000001L)

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




間違えたプログラミング

 COMを使ったプログラミングで以下のようなコーディングをすることは多いのではないだろうか?
 つまり、ある関数の呼び出しに対してif(FAILED(hr))やif(SUCCEEDED(hr))を使ったエラー分岐処理をだ。

 このソースコードの中で使われているIEnumWbemClassObject::Next()は戻り値としてHRESULT型を返す。 しかしその値は失敗時にS_FALSEとなる。S_FALSEはSUCCEEDEDマクロでTRUEとなることがエラーの原因だ。

bool	Test()
{
	HRESULT	hr;

	CComPtr		pInstance;
	CComPtr	pEnumerator;

	省略

	pInstance = NULL;
	hr = pEnumerator->Next(WBEM_INFINITE,1,&pInstance,&dwCount);
	if(FAILED(hr))
		return	false;

	hr = pInstance->GetNames(NULL,WBEM_FLAG_ALWAYS | WBEM_MASK_CONDITION_ORIGIN,NULL,&pvNames);
	//  ↑ pInstance == NULLでエラーになることがある

	省略
}



エラーにならないプログラミング

 IEnumWbemClassObject::Next()はIWbemClassObjectを取得するためのものなので戻り値は無視して IWbemClassObjectで判定すればいい。

 ここでは例としてIEnumWbemClassObjectという見慣れないインターフェースを使った。しかしQueryInterface など多用される関数の戻り値をチェックする場合も同様にインターフェースへのポインタの値でチェック をした方が安心だ。通常QueryInterfaceなどではS_FALSEが返ることはない。しかしインターフェースの 開発者がうっかりミスなどで(また見た目的にエラーと思われやすいので)S_FALSEを使ってしまってい る可能性があるためだ。

bool	Test()
{
	HRESULT	hr;

	CComPtr		pInstance;
	CComPtr	pEnumerator;

	省略

	pInstance = NULL;
	hr = pEnumerator->Next(WBEM_INFINITE,1,&pInstance,&dwCount);
	if(pInstance == NULL)
		return	false;

	hr = pInstance->GetNames(NULL,WBEM_FLAG_ALWAYS | WBEM_MASK_CONDITION_ORIGIN,NULL,&pvNames);

	省略
}








Copyright (c) 1999-2007 issei. All rights reserved. (運営者情報