Web/DB プログラミング徹底解説

ホーム > Windows 徹底解説 > C++ 例外処理と構造化例外処理 (2)

C++ 例外処理と構造化例外処理 (2)

スポンサーリンク

構造化例外から C++ 例外への明示的な変換

前回は構造化例外処理 (SEH) における例外と C++ 例外は異なるものであることを説明しました。 考えてみれば名前からして別物なのですが同じ「例外」ですし、さらに /EHa コンパイラオプションの元では、 SEH も (キャッチできれば) キャッチしますから、混乱するのは当然ともいえます。

今回は SEH が発生したときに、C++ 例外を明示的にスローするための方法を説明します。

_set_se_translator 関数による変換関数の指定

Visual C++ では _set_se_translator 関数 が用意されています。 これに変換関数を渡すと、構造化例外が発生したときにその変換関数が呼び出されるようになります。 そして、変換関数で C++ 例外をスローすればよいのです。

変換関数の型は次の通りです。

typedef void (*_se_translator_function)(unsigned int, struct _EXCEPTION_POINTERS* );

尚、_set_se_translator 関数はスレッド毎に呼び出す必要があります。

実行例

以下に _set_se_translator 関数の使用例を示します。main 関数に入った後、 _set_se_translator 関数で変換関数 TransSEHtoCEH を指定しています。 TransSEHtoCEH のなかで、ここで定義した CSEHException という名前の例外クラスをスローしています。

#include <windows.h>
#include <iostream>
using namespace std;

class CSEHException {
public:
     CSEHException (
          unsigned int ExceptionCode, 
          EXCEPTION_POINTERS* ExceptionPointers )
          : m_ExceptionCode( ExceptionCode ), 
          m_ExceptionPointers( ExceptionPointers ) {}
     
     void PrintER();

private:
     unsigned int m_ExceptionCode;
     EXCEPTION_POINTERS* m_ExceptionPointers;

};


void CSEHException::PrintER () {

     cout << "Entering CSEHException::PrintER" << endl;

     PEXCEPTION_RECORD p = m_ExceptionPointers->ExceptionRecord;

     printf("|Exception Code:    0x%08x\n", p->ExceptionCode);
     printf("|Exception Falgs:   0x%08x\n", p->ExceptionFlags);
     printf("|Exception Address: 0x%p\n", p->ExceptionAddress);
     printf("|Parameters:\n");

     cout << "Exit CSEHException::PrintER" << endl;
     
}


void TransSEHtoCEH ( unsigned int ExceptionCode, PEXCEPTION_POINTERS ExceptionPointers ) {

     throw CSEHException ( ExceptionCode, ExceptionPointers );

}


int main( int argc, char* argv[] ) {

     cout << "Entering main()" << endl;

     _set_se_translator ( TransSEHtoCEH );

     try {
          strcpy(NULL, NULL);          
     }
     catch( CSEHException &ex ) {
          ex.PrintER ();
     }

     cout << "Exit main()" << endl;

     return 0;
}

尚、このプログラムのコンパイルには /EHa オプションが必要であることに注意してください。

スポンサーリンク