Introduction
Shell Icon Handlers are DLLs that are registered in the system to customize 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:
- .NET Shell Extensions - Shell Context Menus
- .NET Shell Extensions - Shell Icon Handlers
- .NET Shell Extensions - Shell Info Tip Handlers
- .NET Shell Extensions - Shell Drop Handlers
- .NET Shell Extensions - Shell Preview Handlers
- .NET Shell Extensions - Shell Icon Overlay Handlers
- .NET Shell Extensions - Shell Thumbnail Handlers
- .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:
[ComVisible(true)]
[COMServerAssocation(AssociationType.ClassOfExtension, ".dll")]
public class DllIconHandler : SharpIconHandler
{
protected override Icon GetIcon(bool smallIcon, uint iconSize)
{
Icon icon = null;
try
{
AssemblyName.GetAssemblyName(SelectedItemPath);
}
catch (BadImageFormatException)
{
icon = Properties.Resources.NativeDll;
}
catch (Exception)
{
icon = Properties.Resources.NativeDll;
}
if (icon == null)
icon = Properties.Resources.ManagedDll;
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:
System.Windows.Forms
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
:
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
.
protected override Icon GetIcon(bool smallIcon, uint iconSize)
{
Icon icon = null;
try
{
AssemblyName.GetAssemblyName(SelectedItemPath);
}
catch (BadImageFormatException)
{
icon = Properties.Resources.NativeDll;
}
catch (Exception)
{
icon = Properties.Resources.NativeDll;
}
if (icon == null)
icon = Properties.Resources.ManagedDll;
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, it's 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 protect 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 recognize 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:
- Only shell items that match the COM Server Associations specified on the server will be tested
- 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.
History
- 19th January, 2015: Initial version