VC++の例外処理の仕組みを追う その3
catchした任意のオブジェクトをコピーするところまで出来ました。
#include <windows.h> extern "C" { // CRTのTLSデータ struct _tiddata; _tiddata* __cdecl _getptd(); } // extern "C" // C++例外を示すコード const ::DWORD cxx_exception_code = 0xE06D7363; // 捕捉中の例外レコードを取得する const ::EXCEPTION_RECORD* get_current_exception_record() { _tiddata* p = _getptd(); #if _MSC_VER < 1400 return reinterpret_cast< ::EXCEPTION_RECORD**>(p)[31]; #else return reinterpret_cast< ::EXCEPTION_RECORD**>(p)[34]; #endif } // 0引数のメンバ関数を呼ぶ inline void call_pmfn0(_PMFN f, void* p) { if (f) { __asm { mov ecx, p call f } } } // 1引数のメンバ関数を呼ぶ inline void call_pmfn1(_PMFN f, void* p0, void* p1) { if (f) { __asm { mov ecx, p0 push p1 call f } } } // ここからお試しコード #include <iostream> struct my_exception { int a; my_exception() { std::cout << "construct: " << static_cast<void*>(this) << std::endl; } my_exception(const my_exception&) { std::cout << "copy: " << static_cast<void*>(this) << std::endl; } ~my_exception() { std::cout << "destruct: " << static_cast<void*>(this) << std::endl; } my_exception& operator=(const my_exception&) { std::cout << "assign: " << static_cast<void*>(this) << std::endl; return *this; } }; int main() { void* e = 0; _PMFN d = 0; try { throw my_exception(); } catch (...) { const ::EXCEPTION_RECORD* er = get_current_exception_record(); if (er) { if (er->ExceptionCode == cxx_exception_code) { // 例外オブジェクト void* data = reinterpret_cast<void*>(er->ExceptionInformation[1]); // 例外情報 _s__ThrowInfo* ti = reinterpret_cast<_s__ThrowInfo*>( er->ExceptionInformation[2] ); // 多分0番目が最派生クラス const _s__CatchableType* t = ti->pCatchableTypeArray->arrayOfCatchableTypes[0]; e = ::operator new(t->sizeOrOffset); // FIXME: 例外安全じゃない call_pmfn1(t->copyFunction, e, data); d = ti->pmfnUnwind; } } } std::cout << "-----------------"<< std::endl; if (e) { call_pmfn0(d, e); ::operator delete(e); } return 0; }
結果はこんな感じです。
construct: 0012FF20
copy: 009F7F10
destruct: 0012FF20
- -
destruct: 009F7F10