The system maintains four differently sized image lists; small (16x16), large (32x32), extra large (48x48) and jumbo (256x256).
But note that the sizes are only the typical standard ones. If the system is set to a different DPI scaling factor, the sizes can change (e.g. on a 200% DPI system, the large image list will be 64x64).
When the system adds an icon to the system image list, it picks the closest size from the icon resource to avoid scaling as much as possible. That means that, if a program contains a 64x64 pixel icon, it MIGHT get used for the extra large image, it MIGHT get used for the large image, it MIGHT even get used for the small image (on a 400% DPI scaled system) - but there are no guarantees.
The only way to definitively extract an icon of a specific size from an executable is to load it yourself.
Instead of using SHGetFileInfo
to retrieve the icon (or icon index) for you, instead you can ask it to tell you where the icon comes from (that is, the executable containing the icon resource and the resource index). To do this, use the SHGFI_ICONLOCATION
flag. This will return you the executable path that contains the icon in szDisplayName
, and the icon's index in iIcon
.
You can then pass that information to the SHDefExtractIcon
function, using its nIconSize
parameter to request an icon of a specific size.
Psuedo-code:
// find icon location for .txt file icons
SHFILEINFO sfi{};
SHGetFileInfo(L".txt", FILE_ATTRIBUTE_NORMAL, &sfi, sizeof(sfi), SHGFI_USEFILEATTRIBUTES | SHGFI_ICONLOCATION);
// extract the 64x64 pixel icon
HICON hIcon;
SHDefExtractIcon(sfi.szDisplayName, sfi.iIcon, 0, nullptr, &hIcon, MAKELONG(0, 64));
SHGetImageList
, the docs for that say you need to useSHIL_SYSSMALL
and These images are the size specified by GetSystemMetrics called with SM_CXSMICON and GetSystemMetrics called with SM_CYSMICON. – DavidG