今回のサンプルファイルです。ウインドウにファイルをドロップするとその中のアイコンをicon???.icoという名前で保存します。
次に、アイコンを保存する手順を示します。
SaveIcons.c内のSaveIcons関数で
hFile=LoadLibraryEx(lpFileName,NULL,LOAD_LIBRARY_AS_DATAFILE | LOAD_WITH_ALTERED_SEARCH_PATH);として、読み込んでいます。
//アイコンの列挙に使われるコールバック関数
static BOOL CALLBACK EnumResNameProc(HANDLE hModule,LPCTSTR lpszType,LPTSTR lpszName,LONG lParam)
{
DWORD Size,wSize;
PBYTE pMem;
char IcoName[MAX_PATH];
HANDLE hFile;
//lpszNameにアイコンリソース名が入っているので、そのアイコンのデータを取得
Size=GetGroupIconData(hModule,lpszName,&pMem);
if(Size){
wsprintf(IcoName,"icon%03d.ico",g_Index);
hFile=CreateFile(IcoName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
if(hFile){
WriteFile(hFile,pMem,Size,&wSize,NULL);
CloseHandle(hFile);
g_Index++;
}
GlobalFree(pMem);
}
return TRUE;
}
//グループアイコン内の全アイコンデータを取得する
// HANDLE hFile モジュールハンドル
// LPTSTR lpStr リソースの名前
// =>PBYTE データバッファアドレス(要:GlobalFree)
DWORD GetGroupIconData(HANDLE hFile,LPTSTR lpStr,PBYTE *pRetMem)
{
HANDLE hGIcon,hLoadGIcon;
DWORD AllSize;
PBYTE pMem;
LPICONRESHEAD lpIconResHead;
*pRetMem=NULL;
//グループアイコンリソースを検索
hGIcon=FindResource(hFile,lpStr,RT_GROUP_ICON);
if(hGIcon==NULL) return 0;
//見つけたリソースをロード
hLoadGIcon=LoadResource(hFile,hGIcon);
if(hLoadGIcon==NULL) return 0;
//リソースをロックして、メモリアドレスを得る
lpIconResHead=(LPICONRESHEAD)LockResource(hLoadGIcon);
//アイコン全体のサイズを計算する
AllSize=GetGroupIconSize(lpIconResHead);
pMem=(PBYTE)GlobalAlloc(GMEM_FIXED,AllSize);
if(pMem==NULL) return 0;
//全てのアイコンをコピー
if(StoreAllIconData(hFile,lpIconResHead,pMem)==FALSE){
GlobalFree(pMem);
return 0;
}
*pRetMem=pMem;
return AllSize;
}
//グループアイコンの格納に必要なサイズを取得する
static DWORD GetGroupIconSize(LPICONRESHEAD lpIconResHead)
{
int i,num;
DWORD Size;
num=(int)lpIconResHead->num;
//使えそうなAPIがないので、それぞれのアイコンのサイズを合計して
//全体の大きさを求める
Size=sizeof(ICONFILEHEAD)+sizeof(ICONFILEINF)*num;
for(i=0;i<num;i++){
Size+=lpIconResHead->IconInf[i].size;
}
return Size;
}
変換が必要なのはICONFILEINF構造体のDWORD adr;の部分で、リソースヘッダではこの部分にはリソースIDが入っていますが、アイコンファイルではここに各アイコンデータがファイルの先頭から何バイト目にあるかという情報を入れます。
その他は同じなので、そのままコピーしています。unknownについては使われてなさそうなのでコピーしていません。ただし、ICONFILEHEADのunknown3は、1にするみたいです(経験則)。
ヘッダを初期化し、そのうしろに各アイコンのデータをコピーしていきます。このときに、先ほどのadrを設定します。 これでアイコンファイルの形になるので、後はファイルに保存して終わりです。
//グループアイコン内の全てのアイコンをバッファにコピーする
static BOOL StoreAllIconData(HANDLE hFile,LPICONRESHEAD lpIconResHead,PBYTE pMem)
{
int i,num,HeadSize,IconSize;
PBYTE pMemTmp;
LPICONFILEHEAD lpIconFileHead;
//グループアイコン内のアイコンの総数
num=(int)lpIconResHead->num;
lpIconFileHead=(LPICONFILEHEAD)pMem;
//保存するアイコンファイルのヘッダサイズの計算
HeadSize=sizeof(ICONFILEHEAD)+sizeof(ICONFILEINF)*num;
ZeroMemory(lpIconFileHead,HeadSize);
lpIconFileHead->num=num;
lpIconFileHead->unknown3=1;
pMemTmp=pMem+HeadSize;
//アイコンを列挙する
//リソースとアイコンファイルで、少し構造体の中身が違うので変換しつつコピー
for(i=0;i<num;i++){
//各アイコンデータを取得
IconSize=StoreIconData(hFile,lpIconResHead->IconInf[i].ID,pMemTmp);
if(IconSize==0) return FALSE;
//ヘッダ情報の更新
lpIconFileHead->IconInf[i].cx=lpIconResHead->IconInf[i].cx;
lpIconFileHead->IconInf[i].cy=lpIconResHead->IconInf[i].cy;
lpIconFileHead->IconInf[i].col=lpIconResHead->IconInf[i].col;
lpIconFileHead->IconInf[i].size=IconSize;
//アイコンデータのあるアドレス
lpIconFileHead->IconInf[i].adr=pMemTmp-pMem;
pMemTmp+=IconSize;
}
return TRUE;
}