Item icon and thumbnail support

What’s the difference between icons and thumbnails?

Icon: this is a Windows binary format. An Icon may contain one or more small images at multiple sizes and color depths, such that they may be scaled appropriately. Since ShellBoost only supports Windows Vista and higher, we recommend you use 32 bits color depth format, if you must create icons. Icons can be stored in .ICO files (that can contain all images at multiple sizes), or in binary files like .EXE or .DLL, as Win32 resources. In this case, the icon (and all images at multiple sizes) is represented by the binary file path and an icon index. Note icon index is not the same as resource index.

Thumbnail: these are images the Windows Shell uses to represent Shell Items. They are not stored in icon binary format, but in standard PNG, JPG or BMP format. We recommend the PNG format.

Note the maximum size of an image displayed by the Windows shell in the standard folder view is 256 pixels (icon or thumbnail). This is different from what can be displayed by the Explorer’s preview pane. Although there is a maximum size, the Shell is capable of resizing images, to some extent, and at variable quality level.

The best way to support transparency for Shell icons and thumbnails is to use 1) icon files with 32 bits color depth or 2) .PNG files (that implicitly support transparency through an alpha channel).

Depending on how the Windows Shell is configured or used, each shell item can be represented physically by an icon or a thumbnail (historically, the shell only supported icons). This is sometimes confusing because the terminology in the Shell UI always uses the term “Icon”. In the following screenshot, we have opened an extension that contains photos as shell items and we can see that, even in details view, it’s possible to display a dynamically computed thumbnail of the image itself, of 16x16 pixels size. It only works if we use a dynamic image file (which is easier to create than a dynamic icon file):

Item icon and thumbnail support - Picture 14

ShellBoost proposes a unified experience to the developer with the ShellItem’s class Thumbnail property, of type ShellThumbnail:

public virtual ShellThumbnail Thumbnail { get; protected set; }

The ShellThumbnail class is also provided by ShellBoost and can use icons or images, always stored in physical files, to represent the ShellItem visually, independently from the Windows Shell context. So, you can provide this class with only an icon file path (possibly containing multiple images of different sizes), or only an image file path, or both. If an image is required by the Shell and you only have provided an icon, ShellBoost will convert the icon to an image. If an icon is required by the Shell and you only have provided an image, ShellBoost will convert the image to an icon, etc.

For example, here is how is defined the ShellThumbnail of a folder:

public static readonly ShellThumbnail Folder = new ShellThumbnail { IconLocation = "shell32.dll", IconIndex = 4 };
...
public ShellFolder(ShellFolder parent, ShellItemId id)
    : base(parent, id)
{
    ...
    Thumbnail = ShellThumbnail.Folder;
    ...
}
 

This uses the standard Windows shell32.dll file (note the full path does not need to be specified for Windows well-known dlls), and the icon index 4, which is this icon (in multiple sizes) in Windows 10 (only 32 bits color depth are shown and used):

Item icon and thumbnail support - Picture 18

ShellBoost also provides two ShellThumbnail derived classes:

IconShellThumbnail: a class that can use a GDI+ / Winforms System.Drawing.Icon instance to represent a Shell Item. Note this class writes the icon to a physical file path as a cache.

AssemblyResourceShellThumbnail: a class that can get the thumbnail from a .NET assembly resource. Note this class writes the icon to a physical file path as a cache. Usage is demonstrated in the Registry Folder Sample.

The IconShellThumbnail class is useful if you add Icons to a .resX file in your .NET project. For example, if in your .NET project, you have a Resource1.resx file that contains two Icon resources:

Item icon and thumbnail support - Picture 21

Item icon and thumbnail support - Picture 22

You could declare an instance of the IconShellThumbnail like this to declare a ShellThumbnail corresponding to Icon1:

// write the file only once per session
// here typeof(MyFolder).FullName is just used as a unique and permanent string
// Icon1 is a property of System.Drawing.Icon type that’s automatically generated by the Visual Studio’s RESX generator.
private static readonly IconShellThumbnail MyIcon = new IconShellThumbnail(Resource1.Icon1, typeof(MyFolder).FullName, true);

Icons as Win32 resources

The previous chapter explained how to use icons from .ICO file or .NET resources, using the ShellThumbnail classes. However, when working with the Windows Shell, it’s often easier (or mandatory as for overlay icons support, see the dedicated chapter for that) to use icons stored as Win32 resources of a binary file (.DLL or .EXE). Win32 resources are completely different than .NET embedded resources.

ShellBoost comes with a utility class named IconUtilities which has a method that can create a Win32 resource-only DLL from scratch, using either bitmaps or icons, stored as files or streams. Note this class only writes 32-bit ARGB icons (using the underlying PNG format for icons).

For example, if you look at the Local Folder sample project in Visual Studio, you will see this:

Icons as Win32 resources - Picture 16

In this project, the 3 files Attribute.ico, ErrorOverlay.ico and WarningOverlay.ico as declared as “Embedded Resource”, which is a standard way of including a resource in a .NET binary (Winforms, WPF or any other). Now, this is how you can create a Win32 dll from these 3 embedded resources:

IconsDllPath = Path.GetFullPath("icons.dll");
if (!File.Exists(IconsDllPath))
{
    // use ShellBoost utility to extract .NET embedded resources and insert them into a Win32 resource-only .DLL file
    IconUtilities.SaveAsDll(Assembly.GetExecutingAssembly(), typeof(Program).Namespace + ".Resources.Attribute.ico", IconsDllPath, 100, 1033, false);
    IconUtilities.SaveAsDll(Assembly.GetExecutingAssembly(), typeof(Program).Namespace + ".Resources.ErrorOverlay.ico", IconsDllPath, 101, 1033, false);
    IconUtilities.SaveAsDll(Assembly.GetExecutingAssembly(), typeof(Program).Namespace + ".Resources.WarningOverlay.ico", IconsDllPath, 102, 1033, false);
}

This code will create a file named icons.dll that will contain the 3 files as Win32 resources. If you open icons.dll with Visual Studio (as a binary file), you should see this:

Icons as Win32 resources - Picture 19

100 contains Attribute.ico, 101 contains ErrorOverlay.ico, 102 contains WarningOverlay.ico. “English (United States)” is the resource language, corresponding to the 1033 (the locale id for “en-US”) parameter of SaveAsDll. Note all resources contain the full icon, with all its sizes.

Now, you can use this DLL just like we used the shell32.dll earlier (to get the Folder standard icon from the Windows Shell). There is however a difference:

// here, 4 is positive, so it’s an index, the 4th icon in the file.
public static readonly ShellThumbnail Folder = new ShellThumbnail { IconLocation = "shell32.dll", IconIndex = 4 };
 
// here -100 is negative, so it’s an id, not an index
// we use what we pass as the id of SaveAsDll, and that’s also what Visual Studio or other tools show when looking at this dll
public static readonly ShellThumbnail MyAttributeIcon = new ShellThumbnail { IconLocation = @"c:\mypath\icons.dll", IconIndex = -100 };
 

Most of the time, if you are going to use Win32 resources DLL, you want to create them at program startup, like what’s done in the Local Folder sample.

Overlay icons support

A shell item icon or thumbnail may have an overlay icon over it. For example:

http://thewindowsclub.thewindowsclubco.netdna-cdn.com/wp-content/uploads/2010/05/folder-lock.png

ShellBoost supports overlays icons for any shell item. This is demonstrated in the Local Folder sample.

You don’t have to register anything special for that, but the ShellItem instance must override the TryGetPropertyValue and respond to ShellBoost when it requires the OverlayIconLocation property (specific to ShellBoost, this is not a Windows property) of the PropertyStore class in the ShellBoost.Core namespace. The value of this property should follow the Windows Shell Icon location syntax:

<Win32 resources DLL path>,<icon index> // icon index is positive

Or

<Win32 resources DLL path>,-<icon resource id> // icon resource id is positive, but we must prepend a -

Here is some sample code that demonstrates this:

public override bool TryGetPropertyValue(PropertyKey key, out object value)
{
    // OverlayIconLocation is not a Windows property, it's a ShellBoost special property
    if (key == PropertyStore.OverlayIconLocation)
    {
        // note the icon index syntax: the index must be negative when passed to the Windows Shell
        switch (Attribute.Value) // make decision on some custom logic
        {
            case "Error":
                value = IconsDllPath + ",-101"; 
                return true;
 
            case "Warning":
                value = IconsDllPath + ",-102";
                return true;
        }
    }
    return base.TryGetPropertyValue(key, out value);
}

And here is the result of a custom Shell Item icon combined with the “warning” overlay:

Overlay icons support - Picture 43