原始圖標處理函數是古老的。它們是在16位Windows中引入的,專爲僅定義一個圖標大小的系統而設計。因此,大多數這些功能都不知道可能存在多個圖標大小。要獲得資源中不同大小的圖標,需要額外的工作。
繼ICO文件格式,包含圖標目錄和實際圖標圖像後,圖標資源也由兩部分組成:RT_GROUP_ICON
類型的圖標目錄和各個圖標(RT_ICON
)。該目錄是由以下結構表示:
#pragma pack(push)
#pragma pack(2)
typedef struct
{
WORD idReserved; // Reserved (must be 0)
WORD idType; // Resource type (1 for icons)
WORD idCount; // How many images?
GRPICONDIRENTRY idEntries[1]; // The entries for each image
} GRPICONDIR, *LPGRPICONDIR;
#pragma pack(pop)
和
#pragma pack(push)
#pragma pack(2)
typedef struct
{
BYTE bWidth; // Width, in pixels, of the image
BYTE bHeight; // Height, in pixels, of the image
BYTE bColorCount; // Number of colors in image (0 if >=8bpp)
BYTE bReserved; // Reserved
WORD wPlanes; // Color Planes
WORD wBitCount; // Bits per pixel
DWORD dwBytesInRes; // how many bytes in this resource?
WORD nID; // the ID
} GRPICONDIRENTRY, *LPGRPICONDIRENTRY;
#pragma pack(pop)
爲一個圖標組ID的圖標目錄可以使用以下代碼來檢索:
typedef std::list<GRPICONDIRENTRY> IconDirectory;
IconDirectory GetIconDirectory(HMODULE hMod, WORD Id) {
HRSRC hRsrc = FindResourceW(hMod, MAKEINTRESOURCE(Id), RT_GROUP_ICON);
HGLOBAL hGlobal = LoadResource(hMod, hRsrc);
GRPICONDIR* lpGrpIconDir = (GRPICONDIR*)LockResource(hGlobal);
IconDirectory dir;
for (size_t i = 0; i < lpGrpIconDir->idCount; ++i) {
dir.push_back(lpGrpIconDir->idEntries[ i ]);
}
return dir;
}
隨着信息從圖標目錄中可以用此代碼構建各個圖標:
HICON LoadSpecificIcon(HMODULE hMod, WORD Id) {
HRSRC hRsrc = FindResourceW(hMod, MAKEINTRESOURCE(Id), RT_ICON);
HGLOBAL hGlobal = LoadResource(hMod, hRsrc);
BYTE* lpData = (BYTE*)LockResource(hGlobal);
DWORD dwSize = SizeofResource(hMod, hRsrc);
HICON hIcon = CreateIconFromResourceEx(lpData, dwSize, TRUE, 0x00030000,
0, 0, LR_DEFAULTCOLOR);
return hIcon;
}
將所有碎片放在一起,以下內容作爲資源文件加載explorer.exe
,檢索ID爲101
的第一個圖標組,並從每個條目的圖標目錄中打印信息。然後創建個別圖標並輸出xHotspot
和yHotspot
數據。對於圖標,熱點位於中心:
void PrintIconDirEntry(const GRPICONDIRENTRY& DirEntry) {
_wprintf_p(L"ID: %04d; width=%02d; height=%02d; bpp=%02d\n",
DirEntry.nID,
DirEntry.bWidth, DirEntry.bHeight, DirEntry.wBitCount);
}
void PrintIconInfo(HICON hIcon) {
ICONINFO ii = { 0 };
GetIconInfo(hIcon, &ii);
_wprintf_p(L"xHotspot=%02d; yHotspot=%02d\n", ii.xHotspot, ii.yHotspot);
}
typedef std::list<GRPICONDIRENTRY>::const_iterator IconDirectoryCIt;
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hMod = LoadLibraryExW(L"C:\\Windows\\system32\\explorer.exe",
NULL, LOAD_LIBRARY_AS_IMAGE_RESOURCE);
IconDirectory dir = GetIconDirectory(hMod, 101);
for (IconDirectoryCIt it = dir.begin(); it != dir.end(); ++it) {
PrintIconDirEntry(*it);
HICON hIcon = LoadSpecificIcon(hMod, it->nID);
PrintIconInfo(hIcon);
DestroyIcon(hIcon);
}
return 0;
}
總結這件事:檢索所有的圖標大小和顏色變化的圖標資源包括兩個步驟:
- 檢索與信息圖標目錄用於圖標組中的所有圖標。
- 遍歷圖標目錄並使用
CreateIconFromResourceEx
構造單個圖標。
參考文獻: