FC2ブログ

ホーム > アイコンファイルフォーマット > アイコンリソースの読み込み

アイコンリソースの読み込み



アイコンリソースは単体のアイコンリソースとそれら単体のアイコンリソースを複数総括するグループアイコンリソースからなり、以下の構造体から構成されます。

  1. GRPICONDIR構造体
    アイコンファイル内にあるアイコン数アイコン/カーソルの区別のための情報と、最初のアイコンの分のGRPICONDIRENTRY構造体が格納されています。
  2. GRPICONDIRENTRY構造体
    アイコンのサイズ/ビット深度と、ICONIMAGE構造体を格納した単体のアイコンリソース(RT_ICON/RT_CUTRSOR)のID番号とバイト数が格納されています。アイコンが2つ以上格納されている場合に存在し、GRPICONDIR構造体のすぐ後に続いて、2つ目のアイコンの分からアイコンの個数-1個だけ存在します。
  3. Xホットスポット(WORDデータ)
    カーソルリソース(RT_CURSOR)の場合にのみ存在します。
  4. Yホットスポット(WORDデータ)
    カーソルリソース(RT_CURSOR)の場合にのみ存在します。
  5. ICONIMAGE構造体(単体のアイコンリソース)
    アイコンDIBヘッダーカラーテーブルXOR/ANDイメージピクセルデータが格納されています。アイコンの個数分だけ存在します。




PNGファイルの読み込み」で解説した_PNGStreamIn関数、並びに「libpngのインストール」でダウンロードしたlibpngを使用するためのインクルード定義です。

#include "png.h"
#include "PNGFile.h"
#include "DIBFile.h"


上記インクルード定義で必要となるファイルです。

PNGFile.h PNGFile.cpp
DIBFile.h DIBFile.cpp
Rle.h Rle.cpp
MedianCut.h MedianCut.cpp
Dither.h Dither.cpp


アイコンリソースの一番先頭にあるGRPICONDIR構造体です。

//GRPICONDIR構造体
#pragma pack(push)
#pragma pack(2)
typedef struct tagGRPICONDIR{
WORD idReserved; //予約済み(常に0)
WORD idType; //リソースタイプ アイコン:1、カーソル:2
WORD idCount; //アイコンの数
GRPICONDIRENTRY idEntries[1]; //GRPICONDIRENTRY構造体の配列
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack(pop)


アイコンリソースに格納されたアイコンの個数分存在するGRPICONDIRENTRY構造体です。

//GRPICONDIRENTRY構造体
#pragma pack(push)
#pragma pack(2)
typedef struct tagGRPICONDIRENTRY{
BYTE bWidth; //画像幅(単位:ピクセル)
BYTE bHeight; //画像高さ(単位:ピクセル)
BYTE bColorCount; //画像の色数(8ビット以上は0)
BYTE bReserved; //予約済み(常に0)
WORD wPlanes; //カラープレーン数
WORD wBitCount; //ピクセルのビット深度
DWORD dwBytesInRes; //ピクセルデータのバイト数
WORD nID; //アイコンのリソースID
}GRPICONDIRENTRY,*LPGRPICONDIRENTRY;
#pragma pack(pop)


これら上記の構造体については「MSDNライブラリーのIcons」に詳しい解説があります。

リソースを格納しているファイル(DLL、EXEファイル)を開いてリソースハンドルを取得し、同じ名前のLoadResource関数を呼び出します。

//DLL/EXEリソースの読み込み
//lpNameはリソース名で、リソースIDをMAKEINTRESOURCEマクロで型キャストした値が入ります。
//lpTypeはリソース形式で、この関数では以下の4種類のリソースが読み込めます。
// 単体のアイコン :RT_ICON
// 単体のカーソル :RT_CURSOR
// グループアイコン:RT_GROUP_ICON
// グループカーソル:RT_GROUP_CURSOR
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CGroupIcon::LoadResource(LPCTSTR lpszExeName,LPCTSTR lpName,LPCTSTR lpType,BOOL bDeleteDIB)
{
//DLLの読み込み
HMODULE hModule=::LoadLibraryEx(lpszExeName,NULL,
LOAD_LIBRARY_AS_DATAFILE|LOAD_WITH_ALTERED_SEARCH_PATH);
//失敗したら、FALSEを返して終了します。
if (!hModule) return FALSE;
//リソースからグループアイコンを読み込む関数を呼び出します。
BOOL bResult=LoadResource(hModule,lpName,lpType,bDeleteDIB);
::FreeLibrary(hModule);
return bResult;
}


リソースから CGroupIconクラスを読み込む関数です。

//リソースからグループアイコンを読み込む
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CGroupIcon::LoadResource(HMODULE hModule,LPCTSTR lpName,LPCTSTR lpType,BOOL bDeleteDIB)
{
//単体のアイコン/カーソルリソースの時はアイコンヘッダーがないので、直に読み込みます。
if ((lpType==RT_ICON)||(lpType==RT_CURSOR)){
Delete(); //すべてのアイコンを消去します。
BOOL bIcon=(lpType==RT_ICON);
//CIconクラスを作成
CIcon* pIcon=new CIcon();
//単体のアイコンリソースを読み込む
BOOL bResult=pIcon->LoadResource(hModule,lpName,bIcon,bDeleteDIB);
if (bResult){
m_listIcon.Add(pIcon); //読み込めたらリストに追加
SetType(lpType); //リソース形式を保存
SetName(lpName); //リソース名を保存
}
else delete pIcon; //読み込みに失敗したらCIconクラスを削除
m_indexIcon=0; //アイコンが一つしかないので、アクティブなアイコン番号を0とします。
return bResult; //結果を返して終了する。
}

//グループアイコンの読み込み
//リソース内で、指定したリソース名のリソースハンドルを取得します。

HRSRC hResInfo=::FindResource(hModule,lpName,lpType);
if (!hResInfo) return FALSE; //失敗したら、FALSEを返して終了する。

//リソースをグローバルメモリにロードします。
HGLOBAL hGlobal=::LoadResource(hModule,hResInfo);
if (!hGlobal) return FALSE; //失敗したら、FALSEを返して終了する。

//メモリ内の指定されたリソースをロックします。
LPVOID pGlobal=::LockResource(hGlobal);
if (!pGlobal) return FALSE; //失敗したら、FALSEを返して終了する。

//指定したリソースのサイズ( バイト数)を取得します。
DWORD dwResSize=::SizeofResource(hModule,hResInfo);
if (!dwResSize) return FALSE; //失敗したら、FALSEを返して終了する。

//グローバルメモリの先頭をGRPICONDIR構造体へのポインタとする。
GRPICONDIR* pGrpIcDir=(GRPICONDIR*)pGlobal;
//リソースサイズがGRPICONDIR構造体のサイズに満たなければ、FALSEを返して終了する。
if (dwResSize<sizeof(GRPICONDIR)) return FALSE;
//リソースタイプがアイコンでもカーソルでもない時は、FALSEを返して終了する。
int idType=pGrpIcDir->idType;
if ((idType!=1)&&(idType!=2)) return FALSE;
BOOL bIcon=(idType==1);

//すべてのアイコンを消去しておきます。
Delete();
int idCount=pGrpIcDir->idCount; //格納されたアイコンの個数を取得します。
for(int i=0;i<idCount;i++){
//CIconクラスを作成
CIcon* pIcon=new CIcon();
LPCTSTR lpName=MAKEINTRESOURCE(pGrpIcDir->idEntries[i].nID);
//単体のアイコンリソースを読み込む
if (pIcon->LoadResource(hModule,lpName,bIcon,bDeleteDIB))
m_listIcon.Add(pIcon); //読み込めたらリストに追加
else delete pIcon; //読み込みに失敗したらCIconクラスを削除
}
//一つも読めなかったので、FALSEを返して終了する。
if (!m_listIcon.GetCount()) return FALSE;

//アイコンリストの中からサイズとビット深度が一番大きいアイコンを選択します。
m_indexIcon=FindBestIcon(256,256,32);
SetType(lpType); //リソース形式を保存
SetName(lpName); //リソース名を保存
return TRUE;
}


単体のアイコンリソースからICONIMAGE構造体を読み込みます。

//アイコンリソースからの読み込み
//bDeleteDIB TRUE:アイコン作成時に使用したDIBを削除する。

BOOL CIcon::LoadResource(HMODULE hModule,LPCTSTR lpName,BOOL bIcon,BOOL bDeleteDIB)
{
//リソース内で、指定したリソース名のリソースハンドルを取得します。
LPCTSTR lpType=(bIcon)? RT_ICON:RT_CURSOR;
HRSRC hResInfo=::FindResource(hModule,lpName,lpType);
if (!hResInfo) return FALSE; //失敗したら、FALSEを返して終了する。

//リソースをグローバルメモリにロードします。
HGLOBAL hGlobal=::LoadResource(hModule,hResInfo);
if (!hGlobal) return FALSE; //失敗したら、FALSEを返して終了する。

//メモリ内の指定されたリソースをロックします。
LPVOID pGlobal=::LockResource(hGlobal);
if (!pGlobal) return FALSE; //失敗したら、FALSEを返して終了する。

//指定したリソースのサイズ( バイト数)を取得します。
DWORD dwResSize=::SizeofResource(hModule,hResInfo);
if (!dwResSize) return FALSE; //失敗したら、FALSEを返して終了する。

//ICONIMAGE構造体へのワードポインタを作成します。
WORD* lpwIconImage=(WORD*)pGlobal;
//カーソルの時はリソースデータの先頭にX/Yホットスポット値(ワード)があるので、
//ポインタを2ワード分(4バイト)進めます。

DWORD xHotspot=(bIcon)?0:*lpwIconImage++;
DWORD yHotspot=(bIcon)?0:*lpwIconImage++;

//ICONIMAGE構造体へのポインタを再定義します。
#define lpICONIMAGE ((ICONIMAGE*)lpwIconImage)

//ICONIMAGE構造体からDIBを取得します。
HBITMAP hbmMask=0;
HBITMAP hbmColor=_IconImageToDIB(&hbmMask,(ICONIMAGE*)lpICONIMAGE,dwResSize);

//PNG圧縮フラグOFF
BOOL bCompressedPNG=FALSE;
//BITMAP構造体の取得
BITMAP bm;
//DIB作成に失敗していたら、PNGストリームとして再度読み込んでみる。
if (!::GetObject(hbmColor,sizeof(BITMAP),&bm)){
//アイコンのイメージデータを元にCMemFileクラスを作成する。
CMemFile infile((PBYTE)lpICONIMAGE,dwResSize);
//PNGファイルストリームとして読み込んでみる。
hbmColor=_PNGStreamIn(&infile);
infile.Close();
//DIBの作成に失敗していたら、FALSEを返して終了する。
if (!::GetObject(hbmColor,sizeof(BITMAP),&bm)) return FALSE;
//DIBが作成できたら空のマスクDIBを作成します。
hbmMask=::CreateBitmap(bm.bmWidth,bm.bmHeight,1,1,0);
//PNG圧縮フラグをONにする。
bCompressedPNG=TRUE;
}

//DIBからアイコンを作成する
ICONINFO IconInfo;
IconInfo.fIcon=bIcon;
IconInfo.xHotspot=(bIcon)?0:xHotspot;
IconInfo.yHotspot=(bIcon)?0:yHotspot;
IconInfo.hbmColor=hbmColor;
IconInfo.hbmMask =hbmMask;
//アイコン作成に失敗したらFALSEを返して終了する。
if (!CreateIndirect(&IconInfo,lpName,bCompressedPNG)){
::DeleteObject(hbmColor);
::DeleteObject(hbmMask);
return FALSE;
}

//DIBを削除する場合
if (bDeleteDIB){
::DeleteObject(hbmColor);
::DeleteObject(hbmMask);
}
//DIBを保存する場合
else{
m_IconInfo.hbmColor=hbmColor;
if (bCompressedPNG){
m_IconInfo.hbmMask=(HBITMAP)::CopyImage(hbmMask,IMAGE_BITMAP,0,0,LR_CREATEDIBSECTION);
::DeleteObject(hbmMask);
}
else m_IconInfo.hbmMask=hbmMask;
}
return TRUE;
}



サンプルプログラム(VisualC++net2003ソリューション)IconFileTest02B.zip

上記のzipファイルをダウンロードしてからWinRAR等で解凍し、IconFileTest02Bフォルダー内にある「IconFileTest.sln」を開きます。「F5」キーを押すとビルド確認のダイヤログが表示されるので、「Yes」ボタンを押してソリューションをビルドします。



ビルドが終わると、直ちにプログラムが自動起動してウィンドウが表示されます。メニューから「ファイル」/「開く」を選択して、「ファイルを開く」ダイヤログを表示させます。



"C:\WINDOWS\system32"フォルダー(※システムフォルダーがドライブC:にある場合)内の「shell32.dll」を選択し「開く」ボタンを押すと、「shell32.dll」のリソースにあるすべてのグループカーソルとグループアイコンがリストビューに表示されます。



任意のアイコンを左クリックして選択すると、ウィンドウの右端にあるダイヤログバーにアイコン画像と格納しているアイコンの内容が反映されるので、「アイコン番号の選択」コンボボックスで複数個のアイコンが読み込まれているか確認してください。

※今回サンプルプログラムを作成する上で、リストビューに32ビットアルファチャンネル付きのアイコンを正しく表示させることに大変苦労しました。VisualC++net2005では問題ないようですが、VisualC++net2003ではMFCアプリケーションをWindows XPスタイルにするには、まず新規プロジェクト作成時にMFCアプリケーションウィザードの「高度な機能」で「コモンコントロールマニフェスト」をチェックを入れてマニフェストファイルを作成します。



次にソリューションエクスプローラーで「IconFileTest.rc2」を開き、手書きで作成したマニフェストを追加する内容を追加します。




//
// IconFileTest.RC2 - Microsoft Visual C++ で直接編集しないリソース
//


#ifdef APSTUDIO_INVOKED
#error このファイルは、Microsoft Visual C++ で編集できません。
#endif //APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
// 手動で編集されたりソースをここに追加します...

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "res\IconFileTest.manifest" //←この行を追加します。

/////////////////////////////////////////////////////////////////////////////


以上の2つの手順を踏むことより、ビルド時にコンパイラがコモンコントロール バージョン6を選択するようになり、32ビットアルファチャンネル付きのアイコンが正しく表示されます。


スポンサーサイト



コメント: 0

この記事へのコメント
ブログ著者にのみ知らせます。

Trackback+Pingback: 0

TrackBack URL for this entry
http://hiroshi0945.blog75.fc2.com/tb.php/22-9100f241
Listed below are links to weblogs that reference
アイコンリソースの読み込み from マルチメディアファイルフォーマット

Home > アイコンファイルフォーマット > アイコンリソースの読み込み

タグクラウド
ブロとも申請フォーム

この人とブロともになる

ブロとも一覧

このページの先頭へ戻る