時がいくら流れようとも過去を無かったことには出来ず、色んな情報と共に間違いが累積されて行く。
Qiitaは間違いを指摘してうpでとしていくのが利点として挙げられていた気がするので、インターネットにあるサンプルコードの間違いや負の遺産を少しずつ載せたいと思う。
今時MFCの需要がどんだけなのか良く分からないけど、遺産はいくらでもあるので、間違いを指摘したい。
Win32も永いので、その変遷によって動かなくなったのかも知れないが、それも指摘する。
###オーナードローコントロール
オーナードローで使うサブクラス化コードは以下のようになっていることが多いが間違いである。
void CMyButton::PreSubclassWindow()
{
ModifyStyle( 0, BS_OWNERDRAW );
CButton::PreSubclassWindow();
}
ボタンスタイルの下位4ビットは数値扱いで上位28ビットばビットマスク扱いという変なことになっている。
ModifyStyleはビットマスク用なので、最初からビットが立ってるとORで追加されてしまう。
なお、ボタンでは4ビットなだけで、他のコントロールは5ビットだったりするのでチェックする必要がある。
//WinUser.h
#define BS_PUSHBUTTON 0x00000000L
#define BS_DEFPUSHBUTTON 0x00000001L
#define BS_CHECKBOX 0x00000002L
#define BS_AUTOCHECKBOX 0x00000003L
#define BS_RADIOBUTTON 0x00000004L
#define BS_3STATE 0x00000005L
#define BS_AUTO3STATE 0x00000006L
#define BS_GROUPBOX 0x00000007L
#define BS_USERBUTTON 0x00000008L
#define BS_AUTORADIOBUTTON 0x00000009L
#define BS_PUSHBOX 0x0000000AL
#define BS_OWNERDRAW 0x0000000BL
#define BS_TYPEMASK 0x0000000FL
なのでラジオボタンなど0x04を含むボタンでは先にあげたコードではオーナードローに成らない可能性がある(偶然0x0Bになれば動作はする)。正しくは以下のようにModifyStyleの第1引数で落とすフラグを指定してオーナードローに書き換えなければならない。
void CMyButton::PreSubclassWindow()
{
DWORD dwStyle = GetStyle();
ModifyStyle( dwStyle&BS_TYPEMASK, BS_OWNERDRAW );
CButton::PreSubclassWindow();
}
通常のボタン以外でオーナードローしようとする奴なんて殆ど居ないだろうけど間違いは間違いである。
###今日のバグ
ここは頭痛が痛いコード紹介所である。本編とはあまり関係ない。
うろ覚えなものを再現しているのでコンパイル出来なくても一笑に付して欲しい。なおコメントも再現している。
//カスタムCListCtrlの内部で
DWORD dwStyle = GetExtendedStyle();
dwStyle |= LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_SHOWSELALWAYS;
// 自動選択されるバグ対策
if( dwStyle&LVS_EX_TRACKSELECT ) {
dwStyle &= ~LVS_EX_TRACKSELECT;
}
SetExtendedStyle( dwStyle );
3つ間違いがある。
拡張スタイルに通常スタイルをぶち込んだことと、それを打ち消して直したつもりになったことである。
LVS_SHOWSELALWAYSとLVS_EX_TRACKSELECTは同じ数値と言うオチに気付いていない。
更に修正でSHOWSELALWAYSが反映されないバグをそのままにしている辺りが痛い。
これはまだ微笑ましいバグであった。これを書いた人間はメモリ破壊や例外や到達不能コードやモジュール結合度高すぎコードやメモリリークや確率的動作やバグコピペや超非効率コードやありとあらゆるバグを量産しながら試験もろくにしないで地獄を地上に具現化させた実力の持ち主であった。
俺はバグが4重、5重を超えた辺りから頭痛が酷くなった。
バグでバグを上書きして追加していくのは絶対にやめよう(提案)