はじめに
Windowsプログラミングをしているとき"すごい"と思うことの一つにツールバーがある。リソースエディタ で簡単にアイコンの絵を描いただけでビルドするとツールバーに新しいアイコンを追加できる。文字列とコマンドID、そして画像をきちんと結びつけた状態で簡単に管理することができる。しかしこんな にすばらしい機能があるのに、ツールバーだけで使われているだけでほかの場面での出番はない。
というよりもリソースを呼び出して活用する術がなかなかない。もちろんツールバーに対してSendMessageで TB_GETIMAGELISTコマンドを送りつけてイメージリストを取得することはできる。しかしこれはツールバーが ウインドウとして作られていないとダメという欠点がある。
ということで直接リソースからツールバーに関連付けられている情報を取得する関数を作成した。
処理の流れ自体はWTLのソースコードをそのまま利用している。
解説
WTLなどで自動的に生成されるツールバーリソースは以下のようになる。IDR_MAINFRAME TOOLBAR 16, 15 BEGIN BUTTON ID_FILE_NEW BUTTON ID_FILE_OPEN BUTTON ID_FILE_SAVE SEPARATOR BUTTON ID_EDIT_CUT BUTTON ID_EDIT_COPY BUTTON ID_EDIT_PASTE SEPARATOR BUTTON ID_FILE_PRINT BUTTON ID_APP_ABOUT END
太字部分から分かるようにツールバーはRT_TOOLBARという形式でリソースファイルに保存されている。
つまり::FindResource(hInstance,MAKEINTRESOURCE(nResourceID),(LPTSTR)RT_TOOLBAR);を使えば リソースに直接アクセスすることができる。
ここで取り出せるバイナリ形式のツールバーに関するデータは
struct _ToolBarData
{
WORD wVersion; //常に1
WORD wWidth; //画像(ボタン1つ)の幅
WORD wHeight; //画像の高さ
WORD wItemCount; //ツールバーアイテム数(セパレータとボタンの総数)
WORD aItems[wItemCount] //コマンドID(セパレータは0)
};
このような形の構造体で保存されている。
実際の画像はRT_BITMAP、文字列はSTRINGTABLEとして格納されている。文字列の取得はコマンドID が分かれば簡単なのでここではBITMAP画像を取り出してIMAGELISTに格納するまでをしている。
使い方
画面の座標(100,100)にツールバーの1つ目の画像(アイコン)を描画する。
CDnpArrayExはMFCのCArray互換クラス。
void Test()
{
HDC hDC;
HIMAGELIST hImageList;
CDnpArrayEx anID;
hImageList = NULL;
LoadToolbarResource(_Module.m_hInst,IDR_MAINFRAME,hImageList,anID);
hDC = ::GetDC(NULL);
::ImageList_Draw(hImageList,0,hDC,100,100,ILD_NORMAL | ILD_TRANSPARENT);
::ReleaseDC(NULL,hDC);
}
ソースコード
// // ツールバーリソースからのイメージリスト&コマンドID取得 // // WTLのatlctrlw.h内のCCommandBarCtrlImpl::_LoadImagesHelper()をほぼそのまま利用している // // nResourceIDに示されるツールバーリソースの.... // // ボタンの画像をhImageListに、コマンドIDをanIDに出力する。 // 画像のマスクはcolorMaskにより設定する。 // bool LoadToolbarResource(HINSTANCE hInstance,UINT nResourceID,HIMAGELIST& hImageList,CDnpArrayEx& anID,COLORREF colorMask=RGB(0xc0,0xc0,0xc0)) { // //リソース保存形式 // struct _ToolBarData // toolbar resource data { WORD wVersion; WORD wWidth; WORD wHeight; WORD wItemCount; //WORD aItems[wItemCount] WORD* items() { return (WORD*)(this+1); } }; WORD* pItems; int nItems; CBitmap bmp; BITMAP sBitmap; UINT nFlags; HRSRC hRsrc; HGLOBAL hGlobal; _ToolBarData* pData; //引数で渡すhImageListはNULLでない場合Destroyする。 //そのためhImageListはNULLで渡した方が安全! ATLASSERT(hImageList == NULL); //NULLでない場合は警告を出す if(hImageList) ::ImageList_Destroy(hImageList); //ImageListの破壊 hImageList = NULL; //ID格納用配列の破壊 anID.RemoveAll(); //ツールバーリソースを探す hRsrc = ::FindResource(hInstance,MAKEINTRESOURCE(nResourceID),(LPTSTR)RT_TOOLBAR); if(hRsrc == NULL) return false; //ツールバーリソースの読み込み hGlobal = ::LoadResource(hInstance, hRsrc); if(hGlobal == NULL) return false; //ツールバーリソースにアクセスするためのロック pData = (_ToolBarData*)::LockResource(hGlobal); if(pData == NULL) return false; ATLASSERT(pData->wVersion == 1); //ツールバーリソースの保存形式バージョンのチェック。通常は1。将来的に2とか出るかも... pItems = pData->items(); //ボタンに割り当てられたIDの配列 nItems = pData->wItemCount; //ツールバーアイテム数(セパレータを含むので画像の数とは一致しない!) //ツールバー画像の取り込み bmp = (HBITMAP)::LoadImage(hInstance,MAKEINTRESOURCE(nResourceID), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION | LR_DEFAULTSIZE); ATLASSERT(bmp.m_hBitmap != NULL); if(bmp.m_hBitmap == NULL) //ツールバー画像の取り込み失敗 return false; //ツールバー画像の情報取得 ZeroMemory(&sBitmap,sizeof(BITMAP)); bmp.GetBitmap(&sBitmap); if(sBitmap.bmBitsPixel >= 24) nFlags = ILC_COLOR24; else if(sBitmap.bmBitsPixel == 16) nFlags = ILC_COLOR16; else if(sBitmap.bmBitsPixel == 8) nFlags = ILC_COLOR8; else if(sBitmap.bmBitsPixel == 4) nFlags = ILC_COLOR8; else nFlags = ILC_COLOR8; nFlags |= ILC_MASK; //ImageListの作成 hImageList = ::ImageList_Create(pData->wWidth,pData->wHeight,nFlags,sBitmap.bmWidth/pData->wWidth,5); if(hImageList == NULL) return false; //ツールバー画像をイメージリストに代入 //マスク色の設定も! if(::ImageList_AddMasked(hImageList,bmp,colorMask) == -1) { ::ImageList_Destroy(hImageList); hImageList = NULL; return false; } //ツールバーのコマンドIDを配列に格納 for(int i = 0; i < nItems; i++) { if(pItems[i] == 0) //セパレータはゼロなので無視 continue; anID.Add(pItems[i]); } //ツールバーのアイコン数とコマンドIDの数が一致するかのチェック if(::ImageList_GetImageCount(hImageList) != anID.GetSize()) { //数が一致しなかった! anID.RemoveAll(); ::ImageList_Destroy(hImageList); hImageList = NULL; return false; } return true; }
