2011-09-10 4 views
2

私は、COM相互運用機能を介してC#クライアントから呼び出されるさまざまなC++ COM DirectShowフィルタに取り組んでいます。コードにはC++の例外はほとんどありません。主な例外はbad_alloc例外をスローするoperator newです。C++ COMオブジェクトの中に投げ込まれたbad_alloc例外をきれいに処理する方法はありますか?

bad_alloc例外をC#クライアントが捕まえることができる方法で処理するきれいな方法がありますか?

新しいハンドラがCOM相互運用機能クライアントによってキャッチされる可能性のあるSEH例外をスローできますか?

または、Visual Studioライブラリのbackwardly互換非投げバージョンの新しいバージョンとリンクして、すべての割り当てをチェックする方が良いでしょうか?

退屈な選択肢の1つは、bad_alloc例外がめったに回復できないので、価値のないように見える何百ものCOMエントリポイントに対してtry/catchを書き込むことです。

DirectShowの基本クラスは、bad_alloc例外をスローしなかった以前のバージョンのVisual C++で記述されているように、operator newからのnull戻りを一般的にチェックします。

+0

例外処理コードを書くのが簡単になる方法は、この質問の受け入れられた回答に概説されています。例外処理でコードを再利用 – Laserallan

答えて

3

COM API契約では、ANY C++例外がCOM API境界を越えて流れることを許可しないことが必要です。

つまり、すべて C++例外を捕捉し、COM APIから離れる前にHRESULTに変換する必要があります。

(たとえば、COMクライアントとCOMサーバーが同じバージョンのコンパイラでビルドされていることを保証できる場合など)、これを回避することは可能ですが、無数のCOMサーバーがプロキシ/スタブ(複数のアパートメントがある場合やサーバーがアウトオブプロシージャになっている場合に発生する可能性があります)の背後にあるか、COMサーバーが別の言語から呼び出されている場合CLR言語のように)。一般的に

、のようなもの:あなたのCOM APIをそれぞれの終わりに

catch (...) 
{ 
    return E_FAIL; 
} 

はあなたのコードの堅牢性を向上させるための長い道のりを行くだろう。

+0

ありがとう、Larry。おそらくcatch(...)のケースでE_UNEXPECTEDを返して、 '予期しない例外'の失敗モードを区別していたでしょう。未知の例外から回復しようとすると、プロセスが未知の状態でデータの破損やその他の損傷を引き起こす可能性があります。クライアントコードはこの可能性に敏感であるべきですか? – persiflage

3

例外をキャッチしてE_OUTOFMEMORYを返す必要があります。大きな割り当ての場合にのみこれを実行します。小さなものが失敗したときにつまずいてみることにはほとんど意味がありません。プログラムが2ギガバイトの仮想メモリを消費した後に良いことは起こりません。アドレス空間の断片化のために大量の割り当てが失敗する可能性がありますが、未使用領域が残っています。

0

お返事ありがとうございます。 C++例外がCOM境界を確実に渡すことができない理由を知ることができます。 COMの境界を越えて流れる構造化された例外に関して、COM契約は何を言いますか?

演算子の新しい障害を構造化された例外に変える次の手法はどうですか?あるいは、これが悪い考えである理由がありますか?

void __cdecl OutOfMemoryHandler() 
{ 
    RaiseException(STATUS_NO_MEMORY, 0, 0, NULL); 
} 

std::set_new_handler(OutOfMemoryHandler); 

私は、ATLは、動作が定義されたプリプロセッサシンボルにもよるがSTATUS_NO_MEMORY構造化例外を上げることによってE_OUTOFMEMORY HRESULTを扱うAtlThrowで同様のトリックを行うことができることに気づきます。

ネイティブコードでは、/ EHaコンパイラオプションはスタックアンワインドが発生し、構造化例外に対してデストラクタが呼び出されるように設定することを推奨します。私は、多くのtry/catch節を使用していた場合、これがパフォーマンス・ヒットを引き起こすことがわかりましたが、現在のコンテキストではtry/catch節をまったく使用していません。/EHaを使用してもパフォーマンスは低下しますか?

いずれの場合でも、構造体例外処理のコンパイラ設定が良い考えです。別のスタックオーバーフローポスターは、呼び出されたモジュールで構造化例外が発生したときに、C++オブジェクトラップクリティカルセクション(DirectShowベースクラスでよく使用される)がロック解除に失敗した厄介なバグを記述します。コンパイラの設定はC++の例外処理のみに設定され、クリティカルセクションをラップするオブジェクトは、構造化された例外が発生し、デッドロックが発生したときに破棄されませんでした。

+0

いいえ、COM境界、期間を通過する例外は許可しないでください。 – sharptooth

1

はい、大きなtry-catchにすべてのメソッドをラップ:

#define BEGIN_COM_METHOD try { 

#define END_COM_METHOD \ 
} catch(const std::bad_alloc&) {\ 
    return E_OUTOFMEMORY;\ 
} catch(...) {\ 
    return E_FAIL;\ 
}\ 
return S_OK; 

HRESULT YourComClass::SomeMethod() 
{ 
    BEGIN_COM_METHOD 
     DoUsefulStuff(); 
    END_COM_METHOD 
} 

をあなたはもはやCOM境界を通じて例外を伝播し、これを使用していません。

関連する問題