2013-12-22 47 views
5

我有一個* .ico文件包含多個以不同大小鏈接到我的可執行文件作爲資源的圖標。我用這個資源來設置我的應用程序的圖標與RegisterClassEx(),即:使用Win32 API找出圖標資源中的圖標數量

wcx.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)); 

除此之外,我還希望所有的單身圖標轉換在這個資源ARGB像素陣列。這應該可以通過在由GetIconInfo()返回的位圖上使用GetDIBits()來實現。

但是,有一個問題:我需要找出由LoadIcon()返回的HICON句柄中的圖標數量及其大小。我似乎沒有找到一個需要HICON句柄的API,並告訴我在那裏有多少圖標以及它們的大小是多少。

這是可能的某種方式,或者我需要去努力的方式和解析自己的資源嗎?

回答

17

原始圖標處理函數是古老的。它們是在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的第一個圖標組,並從每個條目的圖標目錄中打印信息。然後創建個別圖標並輸出xHotspotyHotspot數據。對於圖標,熱點位於中心:

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; 
} 

總結這件事:檢索所有的圖標大小和顏色變化的圖標資源包括兩個步驟:

  1. 檢索與信息圖標目錄用於圖標組中的所有圖標。
  2. 遍歷圖標目錄並使用CreateIconFromResourceEx構造單個圖標。

參考文獻: