ゆとりーなの日記

日記的な事を書いて行くと思はれる

WM_PAINTで例外を投げたら残当したでござる

 WM_PAINTで例外対策にBOOST_SCOPE_EXITを使って描画中に例外が飛んでもちゃんと描画終了するようにしたぞと粋がっていたら思わぬところから伏兵が現れました。

// 適当なプロシージャの中身
case WM_PAINT: {
  BOOST_SCOPE_EXIT((&hwnd)) {
    // たまたまDirect2Dを使ってたのでEndPaintとかではない
    ValidateRect(hwnd, nullptr);
  }
  BOOST_SCOPE_EXIT_END;
  // 描画する
  throw std::exception(); // ドヤ顔で例外を投げてみる
  break;
}

 問題はcatchした例外をMessabeBoxで表示した場合です。

HWND hWnd;

try {
  // ウィンドウ作って表示したりメッセージループ回したり...
} catch(const std::exception) {
  MessageBox(hWnd, "例外を", "キャッチしたぞよ", MB_OK);
 // なんかまた例外が投げられた?
}

 実行すると恐らくメッセージボックスが出てきた後catchしていない例外なんたらでこけるかと思います。おいおい例外はちゃんとcatchしてるし、MessageBoxは流石にC++例外投げんだろうと思ったあとハッとするわけです。
 メッセージボックスは表示してあるウィンドウの上に表示されます。するとあら不思議、無効領域が発生してもう一回WM_PAINTが発行されるじゃありませんか。プロシージャはまたもドヤ顔で例外を投げるというわけです。多分。
 取り敢えず回避策としては、以前gtkmmのときに使ったstd::exception_ptrを使う方法を応用すればなんとかなるような気はしますが、そこそもプロシージャで例外を投げるのは結構危険なのかもと思える一例でした。