今日はお行儀のよいSelectObjectマクロを作成してみたよ。
子供たちも知っているように、Win32のGDIプログラミングではSelectObjectしたら必ず最後に、以前にセットされていたオブジェクトでSelectObjectしなおさないといけないんだったね。具体的にはその返り値のHGDIOBJ変数をとっておいて、用が済んだら、それを使って再びSelectObjectを呼ぶということだ。しかし、これをやっているとソースがさんざん見にくくなるね!古いHGDIOBJ変数は定義されるわ、SelectObjectは2回呼ばれるわ、しかもこれをやり忘れると「何てお行儀の悪い‥」というレッテルを貼られてしまうことになる。
そんな状況への改善提案が今回のSelectObjectPoliteだ。ソースは以下のようになったよ。
struct SelectObjectPolite_t { SelectObjectPolite_t(){} SelectObjectPolite_t( HDC& hdc, HGDIOBJ obj ): _hdc(hdc){ _default = SelectObject( _hdc, obj ); } ~SelectObjectPolite_t( void ){ SelectObject( _hdc, _default ); } operator bool(){ return !0; } HDC _hdc; HGDIOBJ _default; }; #define SelectObjectPolite( hdc, obj ) \ if( SelectObjectPolite_t tmp = SelectObjectPolite_t( hdc, obj) ) \ // 上記if文スコープの終端を処理が必ず通過することが前提です。 // 途中のreturnやbreakなどで、本マクロスコープを中断するような // 場合は処理を分岐させる前に必ず、 // SelectObject( tmp._hdc, tmp._default ); // をして下さい!
これの使い方を見てみよう。今まで、
HBITMAP prev = SelectObject( hdc, bmp ); // // bmpを使った自分のやりたい描画処理 // SelectObject( hdc, prev );
と書いていたコードは、
SelectObjectPolite( hdc, bmp ) { // // bmpを使った自分のやりたい描画処理 // }
という感じですっきり書けるという話だ。すっきり書けるというよりは、もとの描画オブジェクトでSelectObject()し忘れるのを防ぐことができることの方が使う意味あいとしては大きいかな。
もちろん、これが適用できるのはSelectObjectが、きれいな入れ子構造に書き直せる場合のみだし、またパフォーマンスが大事なところでは使うものではないかも知れないから気をつけてくれ。