プロが教えるわが家の防犯対策術!

Windows XP SP3 + Visual Studio 2008 C++
で、リストビューを使用したダイアログベースのソフトを作っています。
リストビューには、ファイル名、ファイルサイズ、最終更新日時を「詳細」で表示させています。(よくあるファイル一覧です。)
エクスプローラと同じように、ファイル名等のテキストを

NTFS の圧縮ファイルは青
暗号化ファイルは緑

で表示させようと思い、カスタムドローを使用しています。
また、圧縮でもなく暗号化でもないファイルに対しては、ChooseFont() で選択された色 ( CHOOSEFONT 構造体の rgbColors ) を設定しています。

ChooseFont() で選択した色のうち、濃紺以外の色は問題なく表示されているのですが、なぜか、ChooseFont で濃紺 ( 0x00800000 ) を選択した場合だけ、第一列 ( ファイル名 ) のみ濃紺になり、第二列目以降 ( ファイルサイズ、最終更新日時 ) が、システム設定値 ( 黒 ) となります。
しかも、リストビューのスタイルを拡張スタイルの
LVS_EX_FULLROWSELECT ( 行選択モード? )
にすると、濃紺の場合でも、第二列目以降も正常に表示されます。

コーディングは、カスタムドローの部分だけを抜粋すると以下のような感じになっています。

LPNMLVCUSTOMDRAW pnmlvcd;
LVITEM lvi;
DWORD dwAttributes;

switch( message ) {
case NM_CUSTOMDRAW:
  pnmlvcd = ( LPNMLVCUSTOMDRAW )lParam;

  switch( pnmlvcd->nmcd.dwDrawStage ) {
  case CDDS_PREPAINT:
    SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_NOTIFYITEMDRAW );
    return( TRUE );

  case CDDS_ITEMPREPAINT:
    lvi.mask = LVIF_PARAM;
    lvi.iSubItem = 0;
    lvi.iItem = pnmlvcd->nmcd.dwItemSpec; // 描画しようとしている行のインデックス
    if( ListView_GetItem( hwndList, &lvi ) ) {

      // 属性を取得
      // lvi.lParam はファイルの情報を格納した構造体 FILEITEM へのポインタです。
      dwAttributes = ( ( PFILEITEM )lvi.lParam )->dwAttributes;

      if( 通常ファイルの場合 ) {  // dwAttributes を使用して属性を判定
        // ChooseFont で選択した色を設定
        pnmlvcd->clrText = cfList.rgbColors;
        SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );
        return( TRUE );

      } else if( 圧縮ファイルの場合 ) {  // dwAttributes を使用して属性を判定
        // 青
        pnmlvcd->clrText = RGB( 0, 0, 0xff );
        SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );
        return( TRUE );

      } else if( 暗号化ファイルの場合 ) {  // dwAttributes を使用して属性を判定
        // 緑
        pnmlvcd->clrText = RGB( 0, 0xff, 0 );
        SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );
        return( TRUE );
      }
    }
  }
  break;

hwndMain はダイアログのウィンドウハンドル、hwndList はリストビューのウィンドウハンドルです。
(見やすくするため、スペースに全角スペースを使用しています。また、属性の判定部分は実際には dwAttributes との、&、| を使用しています。)

コーディング的には、ChooseFont() で何色が選択されようが知ったこっちゃないという感じなのですが・・・。
試しに、ChooseFont() で選択した色ではなく、RGB( 0, 0, 0x80 ) を指定しても同様の現象でした。

濃紺の場合でも、LVS_EX_FULLROWSELECT でなくても第二列目以降が正しい色で表示されるようにする方法はないでしょうか。
このリストビューは Drag & Drop のソース側の機能も実装していまして、その影響で、LVS_EX_FULLROWSELECT だと、Drag 操作による複数行選択の操作が難しくなるので、LVS_EX_FULLROWSELECT は避けたいと考えています。
あるいは、上記のコーディングで、何かおかしいんじゃないかという部分がありましたら教えていただけませんでしょうか。
よろしくお願いします。

A 回答 (1件)

カスタムドロー、その辺りまで試したことはありませんが…



CommCtrl.hに
#if (_WIN32_IE >= 0x0400)
#define CDDS_SUBITEM 0x00020000
#endif
なんてのがありますが……

case CDDS_ITEMPREPAINT:
だけだと、CDDS_SUBITEMのビットが設定されている場合は対応できません…よね?

_WIN32_IEが0x0400以上に設定されている必要はあるかと思われますが…

  case (CDDS_SUBITEM | CDDS_ITEMPREPAINT):
  case CDDS_ITEMPREPAINT:
    lvi.mask = LVIF_PARAM;
とかやってみたらどうなりますかね?

この回答への補足

早速の回答ありがとうございます。

CDDS_ITEMPREPAINT に対して CDRF_DODEFAULT を返すと、それ以降のサブアイテムに対しては「デフォルト」の処理が行われるようで、CDDS_SUBITEM | CDDS_ITEMPREPAINT のメッセージは送られてきませんでした。
CDDS_ITEMPREPAINT に対して CDRF_NOTIFYSUBITEMDRAW を返すように、

case CDDS_ITEMPREPAINT:
  pnmlvcd->clrText = cfList.rgbColors;
  ・・・
  SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_NOTIFYSUBITEMDRAW );
  return( TRUE );

case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
  pnmlvcd->clrText = cfList.rgbColors;
  ・・・
  SetWindowLong( hwndMain, DWL_MSGRESULT, ( LONG )CDRF_DODEFAULT );
  return( TRUE );

とすることで CDDS_SUBITEM | CDDS_ITEMPREPAINT の場合の処理が実行されるようになりました。(ブレークポイントを設定して確認しました。)
が、状況は変わりませんでした。

case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
なしの場合でも、ありの場合でも、濃紺以外の色でしたらサブアイテムも設定した色で表示されていますので、Microsoft のバグのような気がしてきました・・・。

補足日時:2009/11/04 02:39
    • good
    • 0
この回答へのお礼

エクスプローラだとどうなるのか試してみましたところ、エクスプローラでも同じ現象が確認できました。
エクスプローラは、標準の状態ではNTFS圧縮ファイル、NTFS圧縮フォルダを青 ( RGB( 0, 0, 0xff ) ) で表示しますが、
レジストリのキー
HKEY_CURRENT_USER\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer

"AltColor"=hex:00,00,80,00
を追加して、Windows を再起動したところ、エクスプローラでもファイル名のみが濃紺で、サイズなどの項目は黒になりました。
リストビューコントロールのバグなのか、私が使用しているシステムがおかしくなっているのかはわかりませんが、少なくとも、自作プログラムのバグでないことはわかりましたので、この質問は締め切らせていただきます。

お礼日時:2009/11/04 20:46

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!