Click here to Skip to main content
Click here to Skip to main content

.NET Shell Extensions - Shell Icon Handlers

, 22 Feb 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
Rapidly create Shell Icon Handler Extensions using .NET

Introduction        

Shell Icon Handlers are DLLs that are registered in the system to customise the appearance of icons. In this article I will show you how to create an Icon Handler extension using .NET and a library called SharpShell. 

 

Above: An example Icon Handler Extension in action. This extension changes the icons for dll files to indicate whether they are Assemblies or Native DLLs. 

The Series  

This article is part of the series '.NET Shell Extensions', which includes:

  1. .NET Shell Extensions - Shell Context Menus  
  2. .NET Shell Extensions - Shell Icon Handlers  
  3. .NET Shell Extensions - Shell Info Tip Handlers     
  4. .NET Shell Extensions - Shell Drop Handlers   
  5. .NET Shell Extensions - Shell Preview Handlers   
  6. .NET Shell Extensions - Shell Icon Overlay Handlers
  7. .NET Shell Extensions - Shell Thumbnail Handlers
  8. .NET Shell Extensions - Shell Property Sheets    

Our Goal   

To show how SharpShell and Shell Icon Handlers work we're going to create a DLL that changes the icons of  *.dll files - showing them in one colour for standard DLLs and another colour for Assemblies. Just to show how easily this can be done with SharpShell, here's the final class: 

/// <summary>
/// The DllIconHandler is a Shell Icon Handler exception that
/// shows different icons for native and managed dlls.
/// </summary>
[ComVisible(true)]
[COMServerAssocation(AssociationType.ClassOfExtension, ".dll")]
public class DllIconHandler : SharpIconHandler
{
    /// <summary>
    /// Gets the icon.
    /// </summary>
    /// <param name="smallIcon">if set to <c>true</c> provide a small icon.</param>
    /// <param name="iconSize">Size of the icon.</param>
    /// <returns>
    /// The icon for the file.
    /// </returns>
    protected override Icon GetIcon(bool smallIcon, uint iconSize)
    {
        //  The icon we'll return.
        Icon icon = null;
 
        //  Check the assembly name. If it's a native dll, this'll throw an exception.
        try
        {
            //  FilePath is provided by 'SharpIconHandlder' and contains the path of the file.
            AssemblyName.GetAssemblyName(FilePath);
        }
        catch (BadImageFormatException)
        {
            //  The file is not an assembly.
            icon = Properties.Resources.NativeDll;
        }
        catch (Exception)
        {
            //  Some other eception occured, so assume we're native.
            icon = Properties.Resources.NativeDll;
        }
 
        //  If we haven't determined that the dll is native, use the managed icon.
        if (icon == null)
            icon = Properties.Resources.ManagedDll;
        
        //  Return the icon with the correct size. Use the SharpIconHandler 'GetIconSpecificSize'
        //  function to extract the icon of the required size.
        return GetIconSpecificSize(icon, new Size((int)iconSize, (int)iconSize));
    }
}

Can't get much easier than that. Now we'll look at how to create an Icon Handler Extension in detail. 

Step 1: Creating the Project 

First, create a new C# Class Library project. 

Tip: You can use Visual Basic rather than C# - in this article the source code is C# but the method for creating a Visual Basic Shell Extension is just the same. 

In this example we'll call the project 'DllIconHandler'. Rename the 'Class1.cs' file to 'DllIconHandler.cs'.   

Now add the following references: 

  1. System.Windows.Forms
  2. System.Drawing

System.Windows.Forms is needed because the SharpShell library depends on it (for things like context menus). System.Drawing is needed as we're going to want to use Icons.  

Tip: If you use Nuget to install SharpShell (see 'Step 2') you don't need to add these references - they'll be added automatically. 

Step 2: Referencing SharpShell    

We now need to add a reference to the core SharpShell library. You can do that in a few different ways:

Add Reference 

Download the 'SharpShell Library' zip file at the top of the article and add a reference to the downloaded SharpShell.dll file.  

Tip: The download on this article is correct at the time of writing - if you need the latest version, use Nuget (as described below) or get the library from sharpshell.codeplex.com.  

Use Nuget

If you have Nuget installed, just do a quick search for SharpShell and install it directly - or get the package details at https://www.nuget.org/packages/SharpShell

Use CodePlex 

Rather than getting the library from this page, which may not be the latest version, you can always get the very latest version of the library from CodePlex - on the SharpShell home page which is sharpshell.codeplex.com. Nuget will always have the latest stable version - CodePlex may have betas available, and the CodeProject articles will have the version that was available at the time of writing. 

Step 3: Deriving from SharpIconHandler 

Now we're actually going to create the functionality for the DLL Icon Handler. Derive your DllIconHandler class from SharpIconHandler:
/// <summary>
/// The DllIconHandler is a Shell Icon Handler exception that
/// shows different icons for native and managed dlls.
/// </summary>
public class DllIconHandler : SharpIconHandler
{
}  

Now we must implement the abstract members of the class. Right click on the SharpIconHandler part of the line and choose 'Implement Abstract Class'. 

This'll create the implementation of the  function we use to get the icon - needed - GetIcon

/// <summary>
/// Gets the icon.
/// </summary>
/// <param name="smallIcon">if set to <c>true</c> provide a small icon.</param>
/// <param name="iconSize">Size of the icon.</param>
/// <returns>
/// The icon for the file.
/// </returns>
protected override Icon GetIcon(bool smallIcon, uint iconSize)
{
    //  The icon we'll return.
    Icon icon = null;
 
    //  Check the assembly name. If it's a native dll, this'll throw an exception.
    try
    {
        //  SelectedItemPath is provided by 'SharpIconHandlder' and contains the path of the file.
        AssemblyName.GetAssemblyName(SelectedItemPath);
    }
    catch (BadImageFormatException)
    {
        //  The file is not an assembly.
        icon = Properties.Resources.NativeDll;
    }
    catch (Exception)
    {
        //  Some other eception occured, so assume we're native.
        icon = Properties.Resources.NativeDll;
    }
 
    //  If we haven't determined that the dll is native, use the managed icon.
    if (icon == null)
        icon = Properties.Resources.ManagedDll;
    
    //  Return the icon with the correct size. Use the SharpIconHandler 'GetIconSpecificSize'
    //  function to extract the icon of the required size.
    return GetIconSpecificSize(icon, new Size((int)iconSize, (int)iconSize));
} 

GetIcon is called to get an Icon object for the selected file. The selected file (or folder, drive etc) path is stored in the SelectedItemPath property.

smallIcon is set to true if the shell is explicitly asking for a small icon. Generally we can ignore this, because the desired icon size is also provided, as iconSize.

A helper function GetIconSpecificSize is in the base class, this will return the correct sized icon from the Icon object - if this function is not used, then the system will get the first icon and resize it itself, normally this is not what you want. 

Step 4: Handling the COM Registration     

There are just a few things left to do. First, we must add the COMVisible attribute to our class. 

[ComVisible(true)]
public class DllIconHandler : SharpIconHandler
This is because even though SharpShell is hiding away most of the COM plumbing, its this class itself which is actually the COM Server - so it must be COM visible.

Next, we must give the assembly a strong name. There are ways around this requirement, but generally this is the best approach to take. To do this, right click on the project and choose 'Properties'. Then go to 'Signing'. Choose 'Sign the Assembly', specify 'New' for the key and choose a key name. You can password project the key if you want to, but it is not required:  

The final step - we now need to associate our extension with some file types. We can do that with the COMServerAssociation attribute:

[ComVisible(true)]
[COMServerAssocation(AssociationType.ClassOfExtension, ".dll")]
public class DllIconHandler : SharpIconHandler 

So what have we done here? We've told SharpShell that when registering the server, we want it to be associated with the class of *.dll files. This means that we won't just have it available for anything that ends in *.dll, but anything that is the same class. In basic terms that's most things that share the same icon as the *.dll files.  

You can associate with files, folders, classes, drives and more - full documentation on using the association attribute is available on the CodePlex site at COM Server Associations

And that's it! Building the project creates the DllIconHandler assembly, which can be registered as a COM server to add the icon handler system, providing coloured icons for dll files.  

Debugging the Shell Extension 

If you have seen the article .NET Shell Extensions - Context Menus you may recognise the 'Server Manager' tool. This is a tool in the SharpShell source code that can be used to help debug Shell Extensions.  

Tip: If you want the latest version of the tools, they're available pre-built from the CodePlex site.  

Open the Sever Manager tool and use File > Load Server to load the DllIconHandler.dll file. You can also drag the server into the main window. Selecting the server will show you some details on it. Select the server. 

 

Now press 'Test Server' or use 'Server > Test...'. This will open the Test Shell which will simulate the calls that will be made to the server, just as if the Windows Shell was making the calls - however, as this is a managed application you can quickly attach a debugger to it and see how your server is running. It also lets you test the server without having to install or register it in the system, and this will save you a lot of time (when testing in Explorer for real, you'll be having to restart it lots to unlock the file so you can update it). 

When testing Shell Icon Handler extensions, be aware of the following points: 

  1. Only shell items that match the COM Server Associations specified on the server will be tested.
  2. Only the list view on the right will test the icons - the folders view on the left will use the standard shell icon.   

Installing and Registering the Shell Extension 

You can check the 'Installing and Registering the Shell Extension' section of the .NET Shell Extensions - Shell Context Menus for details on how to install and register these extensions - the process is the same. 

Useful Resources   

How to Create Icon Handlers: The hub of the MSDN resources on shell icon handlers. Note that these resources are all for C and C++. 

SharpShell on CodePlex: The home of the SharpShell project - includes documentation, discussions and the latest source code and releases. 

What's Next?

SharpShell will over time provide a mechanism to create all of the available Shell Extensions using .NET. So far, fully supported are Context Menu Extensions, Icon Handlers and Info Tip Handlers - follow the CodePlex project to stay up to date as new features are added. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Dave Kerr
Software Developer
United Kingdom United Kingdom
Follow my blog at www.dwmkerr.com and find out about my charity at www.childrenshomesnepal.org.
Follow on   Twitter

Comments and Discussions

 
Questionicon-to big a project PinmemberMads Haupt20-Oct-13 3:45 
QuestionDon't PinmemberSteveKing25-Feb-13 0:02 
QuestionWindows icons PinmemberMayzz8-Feb-13 6:12 
AnswerRe: Windows icons PinmvpDave Kerr9-Feb-13 0:19 
GeneralRe: Windows icons PinmemberMayzz9-Feb-13 3:16 
GeneralRe: Windows icons PinmvpDave Kerr9-Feb-13 3:32 
GeneralRe: Windows icons PinmemberMayzz9-Feb-13 5:28 
GeneralRe: Windows icons PinmvpDave Kerr10-Feb-13 1:29 
GeneralRe: Windows icons PinmemberMayzz10-Feb-13 3:17 
GeneralRe: Windows icons PinmvpDave Kerr10-Feb-13 4:05 
QuestionAnd again... PinmemberBrisingr Aerowing16-Jan-13 16:06 
AnswerRe: And again... PinmvpDave Kerr16-Jan-13 21:31 
Thanks!

GeneralMy vote of 5 PinmemberSkyRunner11-Jan-13 11:08 
GeneralRe: My vote of 5 PinmvpDave Kerr11-Jan-13 11:38 
GeneralRe: My vote of 5 PinmemberSkyRunner12-Jan-13 5:22 
GeneralMy vote of 5 PinmemberEdo Tzumer9-Jan-13 23:47 
GeneralRe: My vote of 5 PinmvpDave Kerr10-Jan-13 0:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141220.1 | Last Updated 23 Feb 2013
Article Copyright 2013 by Dave Kerr
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid