LoginSignup
6
7

More than 5 years have passed since last update.

渡る世間(?)はバグばかり OwnerDraw

Last updated at Posted at 2014-10-21

時がいくら流れようとも過去を無かったことには出来ず、色んな情報と共に間違いが累積されて行く。
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重を超えた辺りから頭痛が酷くなった。

バグでバグを上書きして追加していくのは絶対にやめよう(提案)

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7