Say, if I want to extract an icon out of a stock Windows executable. I can get that icon ID by opening it in Visual Studio:
Then I'll be interested in a 48x48 size icon:
So my assumption was to do:
HICON hIcons[4];
::ExtractIconEx(L"mstsc.exe", -13011, hIcons, NULL, 4);
hIconLogo = hIcons[3];
but when I run it, the method returns only 3 icons:
and only one of them is a 32x32 version of what I need.
I then found ExtractAssociatedIconEx API that I called as such:
WORD wIcnId = -13011;
WORD wIcnInd = 3;
hIconLogo = ::ExtractAssociatedIconEx(hInst, L"mstsc.exe", &wIcnInd, &wIcnId);
but that too gives me some other icon that I did not expect.
So what is the difference between those two APIs? And what am I doing wrong?
The
ExtractIconEx
function can return only two sizes of icons: large and small. Those are relative sizes, defined by the environment. A "large" icon is classically 32x32 pixels, but may be larger on certain system configurations. A "small" icon is classically 16x16 pixels, but the same caveat applies. The only guarantee is that a "small" icon is, well, smaller than a "large" icon. If you want to know the actual size on your system, you call theGetSystemMetrics
function withSM_CXICON
andSM_CYICON
for "large" icons, orSM_CXSMICON
andSM_CYSMICON
for "small" icons.The operating system uses "small" and "large" icons everywhere internally; most of the APIs deal only with "small" and "large" (also occasionally known as "big" icons). When you set an icon for a window, for example, you set either a "small" icon or a "big" icon. Those are your only two choices.
The
ExtractIconEx
function sets thephIconLarge
parameter to a pointer to an array of handles to large icons. ThephIconSmall
parameter is set to a pointer to an array of handles to small icons. Since you passedNULL
for thephIconSmall
parameter, you didn't get any small icons.hIcons
filled with handles to the "large" icons in the file, which, on your system, are different bit-depths of 32x32 icons.The
ExtractAssociatedIcon
function (and its Ex brother) returns only "large" icons. So you should be getting the same results when you call it as you do for the way that you callExtractIconEx
. I'm not really sure if you're saying that it is giving you different results or not. It might have something to do with the index. Negative indices mean something special toExtractIconEx
, but I'm not sure if they are valid forExtractAssociatedIcon
. The documentation doesn't give much of a hint.The
SHGetFileInfo
function, although more powerful in a number of senses, including the ability to extract icons from any file-system object, has the same fundamental limitation: it gives you choices ofSHGFI_LARGEICON
andSHGFI_SMALLICON
.If you need to extract icons of custom sizes (i.e., something other than the system's "small" and "large" sizes), then you'll need to do more work. There are essentially two options:
Call the
SHGetImageList
function, which is another shell helper function, but one that retrieves a shell image list containing icons. It gives you far more options for icon sizes:SHIL_SMALL
(generally 16x16),SHIL_LARGE
(generally 32x32),SHIL_EXTRALARGE
(generally 48x48), andSHIL_JUMBO
(generally 256x256—only on Vista and later). So if you ask forSHIL_EXTRALARGE
, you'll get the 48x48 icons that you're looking for.You'll still need the
SHGetFileInfo
function here, but this time it will be to retrieve the index of the desired icon in the shell image list. Retrieve that with theSHGFI_SYSICONINDEX
option.Completely untested sample code, never touched by a compiler:
Your other option is to extract the desired size icon from the file yourself. Although the icon resource format is well-documented, and various people have used this knowledge to write a bunch of ugly extraction code and posted it on the Internet, there is an easier way:
SHDefExtractIcon
.As Raymond Chen blogged about some time ago,
SHDefExtractIcon
is your more powerful fallback ifIExtractIcon::Extract
(which is what the code sample above attempts to use) fails. The power of this function is itsnIconSize
parameter, which specifies the actual size of the icon that you want to extract.Adapting Raymond's example:
Whatever you do, remember that whenever an API function returns an HICON, it is transferring ownership of that resource to you. This means that, when you are finished with the icon, you must destroy it by calling the
DestroyIcon
function to avoid a leak.