第1回 アイコン

 

BTMemoでは、ファイルのリンクにアイコンを表示しています。

ここでは、アイコンの取得・描画・印刷の仕方をお伝えします。

 

(1)アイコンの取得

 

BTMemoでは、SHGetFileInfoというAPIを使用してアイコンを取得しています。

このAPIは、拡張子に関連付けされているアイコンを取得してくれます。

ファイル名を指定すると、その拡張子に関連付けられている情報(アイコン等)を取り出してくれる便利なAPIです。

コード例を以下に示します。

// ファイル(拡張子)に関連付けられている「小さいアイコン」を取得します

HICON GetFileIcon(char *pszPathName)

{

      SHFILEINFO shfi;

      ::SHGetFileInfo( pszPathName, 0, &shfi, sizeof(SHFILEINFO),SHGFI_ICON | SHGFI_SMALLICON );

      return shfi.hIcon;

}

 

 

 

(2)アイコンの描画

 

アイコンの描画を行うためには、通常は DrawIcon や DrawIconEx といったAPIを使用します。

こんな感じです。

     

      HDC hDC;                                  // デバイスコンテキストハンドラ

      int x, y;                                 // アイコンを描画する位置

      int cx, cy;                               // アイコンの大きさ

      char szPathName[_MAX_PATH];               // 対象となるファイルのパス名

     

      HICON hIcon = GetFileIcon(szPathName);    // アイコンを取得。(1)を参照

      if (hIcon != NULL) {

            ::DrawIconEx(hDC, x, y, hIcon, cx, cy, 0, NULL, DI_NORMAL);       // アイコンを描画

            ::DestroyIcon(hIcon);               // 使い終わったアイコンは忘れずに削除しましょう!

      }

     

 

でも、BTMemoでは、上記の方法は使用していません。理由は(3)を参照

 

 

(3)アイコンの印刷

 

Windowsでは、画面に描画するのもプリンタに印刷するのも基本的には同じです。画面のデバイスコンテキストに対して描画APIを実行すれば画面表示できますし、プリンタのデバイスコンテキストに対して描画APIを実行すれば印刷できます。(出力先デバイスの解像度が違ったり、印刷の場合は前後に特殊な処理が必要とはなりますが、ここでは無視します)

したがってアイコンを印刷するのにも、(2)のAPIが使用できると思っていたのですが、残念ながらうまくいきませんでした。(何種類かのプリンタで試してみましたが全てだめだったので、プリンタドライバなどの問題ではなく、APIのバグではないかと考えています。)

あれこれ試してみた結果、以下のような関数を作成し、(2)のDrawIconEx の代わりに使用しています。

// アイコンを描画する

void MyDrawIcon(HDC hdc, int xLeft, int yTop, HICON hIcon, int cxWidth, int cyWidth, COLORREF colBg)

{

      // アイコンからカラービットマップとマスクビットマップを取得

      ICONINFO ii;

      GetIconInfo(hIcon, &ii);

 

      // 作業用のデバイスコンテキストを2つ作成

      HDC dcImage = ::CreateCompatibleDC(NULL);

      HDC dcTrans = ::CreateCompatibleDC(NULL);

 

      // アイコンと同じサイズのビットマップを作成し、指定背景色で塗りつぶす

      BITMAP bmap;

      int nBit = GetObject(ii.hbmColor, sizeof(bmap), &bmap);

 

      HBITMAP hBmp = CreateCompatibleBitmap(hdc, bmap.bmWidth, bmap.bmHeight);     

      HBITMAP hOldBitmapTrans = (HBITMAP)::SelectObject(dcTrans, hBmp);

 

      HBRUSH br = CreateSolidBrush(colBg);

      RECT rc;

      rc.left = 0; rc.top = 0; rc.right = bmap.bmWidth; rc.bottom = bmap.bmHeight;

      FillRect(dcTrans, &rc, br);

      DeleteObject(br);

 

      // マスクビットマップを登録し、作成先へ AND で描画

      HBITMAP hOldBitmapImage = (HBITMAP)::SelectObject(dcImage, ii.hbmMask);

      BitBlt(dcTrans, 0, 0, bmap.bmWidth, bmap.bmHeight, dcImage, 0, 0, SRCAND);

 

      // カラービットマップを登録し、作成先へ OR で描画

      ::SelectObject(dcImage, ii.hbmColor);

      BitBlt(dcTrans, 0, 0, bmap.bmWidth, bmap.bmHeight, dcImage, 0, 0, SRCPAINT);

 

      // 出来上がったビットマップを目的のDCへ描画

      StretchBlt(hdc, xLeft, yTop, cxWidth, cyWidth, dcTrans, 0, 0, bmap.bmWidth, bmap.bmHeight, SRCCOPY);

 

      // 元のビットマップをDCへ戻す

      SelectObject(dcImage, hOldBitmapImage);

      SelectObject(dcTrans, hOldBitmapTrans);

 

      // 作成したGDIオブジェクトの廃棄

      DeleteObject(ii.hbmColor);

      DeleteObject(ii.hbmMask);

      DeleteObject(hBmp);

      DeleteDC(dcImage);

      DeleteDC(dcTrans);

}