How do you obtain the icon for a shortcut without the shortcut overlay?


The easy one-stop-shopping way to get the icon for a file is to use the SHGet­File­Info function with the SHGFI_ICON flag. One quirk of the SHGet­File­Info function is that if you pass the path to a shortcut file, it will always place the shortcut overlay on the icon, regardless of whether you passed the SHGFI_ADD­OVERLAYS flag. (Exercise: What is so special about the shortcut overlay that makes it exempt from the powers of the SHGFI_ADD­OVERLAYS flag? The information you need is on the MSDN page for SHGet­File­Info, though you'll have to apply some logic to the sitaution.)

I'm using SHGet­File­Info to get the icon of a file to display in my application. When the file is a shortcut, rather than displaying the exe icon with a link overlay (as in SHGFI_LINK­OVERLAY) I'd like to display the original exe icon. Is there a way to do this with SHGet­File­Info? Thanks,

First, correcting a minor error in the question: The icon for a shortcut is, by default, the icon for the shortcut target, but it doesn't have to be. The IShell­Link::Set­Icon­Location method lets you set the icon for a shortcut to anything you like. (This is the method used when you click Change Icon on the shortcut property page.)

Anyway, the SHGet­File­Info function gets the icon first by asking the shell namespace for the icon index in the system imagelist, and then converting that imagelist/icon index into a HICON. If you want to change the conversion, you can just ask SHGet­File­Info to stop halfway and then finish the process the way you like.

HICON GetIconWithoutShortcutOverlay(PCTSTR pszFile)
{
 SHFILEINFO sfi;
 HIMAGELIST himl = reinterpret_cast<HIMAGELIST>(
  SHGetFileInfo(pszFile, 0, &sfi, sizeof(sfi),
                SHGFI_SYSICONINDEX));
 if (himl) {
  return ImageList_GetIcon(himl, sfi.iIcon, ILD_NORMAL);
 } else {
  return NULL;
 }
}

Of course, if you're going to be doing this for a lot of files, you may want to just stop once you have the imagelist and the index, using Image­List_Draw to draw the image when necessary, instead of creating thousands of little icons.

Comments (12)
  1. Billy O'Neal says:

    Quick link to save Goog^H^H^H^H Bing queries -> msdn.microsoft.com/…/bb762179.aspx

  2. Crescens2k says:

    Drew:

    This kind of thing is common. What is usually expected is that you read everything in the documentation before you start using it. This way you would know there is a type HIMAGELIST and see the handle to the system image list and think, oh, there is a perfect type to describe that, HIMAGELIST. But this is usually because it is written by people who know the functions pretty well and don't realse that maybe not everyone knows that a particular type exists. In general though, when it says handle, always assume Hxxxxx or HANDLE and look to see if there is a more specific type available, otherwise use HANDLE.

    There are pleanty of cases in any documentation where it doesn't give exactly everything but it does give enough information for you to work it out yourself. If you think the content is inadiquate then instead of randomly complaining on a blog entry, instead do something like add community content, complain on the connect website or something. To get the documentation useful for everyone, Microsoft need feedback, so give feedback in a very constructive way.

    [I think part of the problem is that people tend to ignore the Overview and Using and Guide topics and go straight for the raw function documentation. You need to build an overall understanding before you dig into the minutiae. It's like learning to drive a car by studying traffic regulations. -Raymond]
  3. Abso says:

    For the exercise: it looks like the shortcut overlay predates the SHGFI_ADD­OVERLAYS flag, since that flag requires version 5.0 of Shell32.dll and the SHGFI_LINKOVERLAY flag doesn't.

  4. Joshua says:

    Well, if you're running on Windows this sure beats parsing the file format. Nasty file format that one.

  5. Drew says:

    This is what's so frustrating about Windows programming – the documentation does not explain or reference the difference between the system image list icon (SHGFI_SYSICONINDEX) and icon (SHGFI_ICON).  It looks like the same functionality can be achieved by using SHGFI_ICONLOCATION, and then using SHGFI_ICON.

    Also, how does a programmer who has never done this before know that A – it returns a HIMAGELIST (documentation says it returns a handle to the system image list, doesn't explicitly say HIMAGELIST), and B – that the ideal way to retrieve an icon from a HIMAGELIST is to use the ImageList_* functions.

    Note – I used the VS2008 documentation for reference.

    [The connection between "image list" and "HIMAGELIST" could be made clearer. But I think it's self-evident that if you have an HIMAGELIST then you call the ImageList_* functions to access it. (If you do an MSDN search for HIMAGELIST it shows up in the "Image Lists" chapter, which is probably a clue.) It's like saying "This function returns an HACCEL. How am I expected to know that I can use this with the Accelerator functions?" -Raymond]
  6. Vaibhav Garg says:

    "though you'll have to apply some logic to the sitaution"

    The 'situation' had me stumped for a while!!

  7. Worf says:

    Blind guess to the exercise – the reason shortcuts are special is because their icon isn;t overlaid – when you create the shortcut or change its icon, Windows creates the icon for the LNK file with overlay, and saves it inside the LNK file. So requesting an ucon without overlay is fruitless as Windows says the icon doesn't have the overlay to begin with. Add the overlay option, and Windows draws the overlay on top of the flattened overlaid icon, so nothing changes.

    Given overlays were for Windows 95, this would seem a reasonable optimization and save RAM…

  8. Miral says:

    I haven't tried SHGetFileInfo myself, but the thing I find surprising about this explanation is that I would have assumed that the system image list would have already contained the icon-with-shortcut-overlay, since you can't make SHGFI_ICON not give you that one.

    (And maybe I'm just dense, but I can't see anything on the MSDN page which seems like it would suggest either behaviour described here.  The only thing that seems even partially suggestive is that you need to DestroyIcon the resulting icon, but that could just mean that the function copies the icon instead of copying+compositing it.)

    "I think part of the problem is that people tend to ignore the Overview and Using and Guide topics and go straight for the raw function documentation."

    On the MSDN website, at least, you can't *get* to the Overview and Using docs from the function documentation — at least not without jumping through quite a few navigational hoops and possibly losing your place.

    I did, however, notice the link to FileIconInit — which I just find disturbing.  The docs basically say "you must call this function when X and Y happen" but it's not even a public exported API.

  9. Neil says:

    Presumably this is better than simply reading the icon location out of the link, since it works on all files, not just links?

  10. WndSks says:

    @Miral: FileIconInit gives you THE system image list, this is normally not required, just use SHGetFileInfo to get the imagelist and every time you call SHGetFileInfo to get the index of a icon, windows will make sure that your copy of the system image list has that icon. You only really need FileIconInit if you want to create an app that displays every icon in the system image list. (There are probably performance benefits to using the real system image list also, I assume that's why explorer uses it)

    @Worf: When you change a .lnk's icon, only the path is stored. (The .lnk binary format is documented and there is no datablock to store a HICON or any other kind of image)

  11. Gabe says:

    It's not that people ignore the Overview and Using and Guide topics — it's that the search engine doesn't return them. When I need to learn how to use function XXXX(), I put XXXX into a search engine and read one of the first few links. Those first few links are rarely the sort of overview topics that would tell me all I need to know about how to use the function, nor do those pages link to such topics.

    The problem is that MSDN is not designed to be accessed from an Internet search engine.

    And you can easily imagine that, were there not a requirement to have a license before being allowed to drive, plenty of people would drive around not even knowing basic things like what turn signals are because they learned to drive from watching TV and people on TV never use turn signals.

  12. Drizzt says:

    OT side, I really loved the old MSDN, the one that existed when VS5 and VS6 were around, it really was like reading a book, you could start from the overview and after reaching the end of the chapter you had a solid understanding of the argument. Current MSDN (for C# and WPF, that's what I'm on in these days) to me is totally useless, and most of all is really poor, often it seems an auto-generated page, typical is: method bool A(int b, bool c), explanation "it does A, take an integer B and a boolean C, output a boolean". Now, I CAN read a method declaration, no need for an MSDN for this…and worst of all for inherited method or events, where you are sent to method's/event's base class explanation about it…even if the thing has been ovverided in the new class and act differently (many WPF classes expose events because they have inherited them from class X, swallow the event firing because they feel it's not right for this event to be fired from this class, but their help still send you to class X for explanation about the event…so you spend an entire day or two trying to puzzle out why a perfectly supported, exposed, simple, documented event doesn't fire at all.

    Old MSDN was really good for those case, everything was well documented, current MSDN is…well, current MSDN for me is Google, 'cause M$ one is really useless.

    Going back IT, instead:

    Shouldn't it be that the shortcut file icon is the shortcut file icon, and the original file icon is the original file icon? I mean, those are two different things, if I want the original file icon I should go back to the file itseslf, the shortcut icon is a different thing and a different view for the user. If the user has an icon on his desktop that is, let's say, a ball with the overlay of an arrow, the icon I'm going to show in my application is the one of a ball and an arrow. Or, if the user ask for it, it's the original icon picked up from the original file.

    Or not?

Comments are closed.