Introduction
Shell Icon Overlay Handlers can be really useful. They let you display an icon overlay over shell objects to provide extra information. Programs like Dropbox use these overlays to show whether icons are synchronized or not. In this article, I'll show you how to use SharpShell to create Shell Icon Overlay Handlers in no time at all!
Below is a screenshot of the sample we'll create - it shows a padlock over files that are read-only.
Above: Some text files in a folder. With this shell icon extension installed, read-only files have a padlock overlay.
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
Getting Started
Shell Extensions are normally written in C or C++. Until the .NET Framework 4 was released, it was not possible to reliably create a Shell Extension using .NET. Now you can. With the SharpShell
library, all of the COM plumbing is handled for you, and you simply have to create a class for the extension, decorate it with some attributes and override some functions.
To show how easy this is, let's see the full code for the read-only file icon overlay handlers.
Our Goal
Here's the full code for the read-only overlay handler. It's very lean indeed - now that we've seen it in full, I'll describe how to create your own extension step-by-step.
[ComVisible(true)]
public class ReadOnlyFileIconOverlayHandler : SharpIconOverlayHandler
{
protected override int GetPriority()
{
return 90;
}
protected override bool CanShowOverlay(string path, FILE_ATTRIBUTE attributes)
{
try
{
var fileAttributes = new FileInfo(path);
return fileAttributes.IsReadOnly;
}
catch (Exception)
{
return false;
}
}
protected override System.Drawing.Icon GetOverlayIcon()
{
return Properties.Resources.ReadOnly;
}
}
The bulk of this is comments - so you can see, creating overlay handlers with SharpShell is pretty easy!
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 'ReadOnlyFileIconOverlayHandler
'.
Tip: If you add a reference to SharpShell via Nuget, the references below will be added automatically.
Now add the following references:
System.Windows.Forms
System.Drawing
Rename the 'Class1.cs' file to 'ReadOnlyFileIconOverlayHandler.cs'.
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 SharpIconOverlayHandler
Now things get interesting. Derive your ReadOnlyFileIconOverlayHandler
class from SharpIconOverlayHandler
:
public class ReadOnlyFileIconOverlayHandler : SharpIconOverlayHandler
Now we must implement the abstract members of the class. Right click on the SharpIconOverlayHandler
part of the line and choose 'Implement Abstract Class'. This will create empty implementations of the functions we need to provide.
public class ReadOnlyFileIconOverlayHandler : SharpIconOverlayHandler
{
protected override int GetPriority()
{
throw new NotImplementedException();
}
protected override bool CanShowOverlay(string path, FILE_ATTRIBUTE attributes)
{
throw new NotImplementedException();
}
protected override System.Drawing.Icon GetOverlayIcon()
{
throw new NotImplementedException();
}
}
Here's a description of the functions and how they should be used:
GetPriority
This function must return the priority of the handler. The priority is used when there are two icon overlays for a single file - the shell will use the icon with the highest priority. Just to be confusing, the highest priority is 0 - the lowest priority is 100.
CanShowOverlay
Every time a shell item will be displayed, this function will be called. The path to the shell item is provided in the path parameter. The FILE_ATTRIBUTE
flags are also provided (these are attributes like FILE_ATTRIBUTE_DIRECTORY
). Return true
if you want the icon overlay to be shown for the specified file.
GetOverlayIcon
This function must return a standard .NET System.Drawing.Icon
object that is the overlay icon to use.
Step 3: Implement the Functions
Our implementation of these functions is going to be as below. First, GetPriority
:
protected override int GetPriority()
{
return 90;
}
This overlay is useful, but not as important as say, TortoiseSVN's state icons, so let's make the priority low.
Now, CanShowOverlay
:
protected override bool CanShowOverlay(string path, FILE_ATTRIBUTE attributes)
{
try
{
var fileAttributes = new FileInfo(path);
return fileAttributes.IsReadOnly;
}
catch (Exception)
{
return false;
}
}
We're going to return true
(to show the overlay) only if we can get the file attributes without throwing an exception, and if those attributes indicate readonly. (Why don't I use FILE_ATTRIBUTE_READONLY
? Well, apparently it doesn't work properly for directories).
The last function, GetOverlayIcon
:
protected override System.Drawing.Icon GetOverlayIcon()
{
return Properties.Resources.ReadOnly;
}
In the project, I added an icon named 'ReadOnly
' to the resources - this just returns it.
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 ReadOnlyFileIconOverlayHandler : SharpIconOverlayHandler
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:
Debugging the Shell Extension
The Shell Extension is going to be hosted in Windows Explorer - due to the roundabout way that .NET COM Servers are loaded, it's damn near impossible to get a debugger into the process and step through the managed code. However, there is a way to debug your extension quickly. SharpShell comes with some tools that make working with SharpShell COM servers a bit easier, and one of them is the Server Manager. We can use this tool to debug our extension. Open up the Server Manager, and load the extension. Choose 'Install' and then 'Register', now open the Test Shell and choose 'Shell Open Dialog' - now breakpoints in your extension should be hit as you move around the file system.
Above: The Server Manager
Above: The Test Shell
Installing and Registering the Shell Extension
There are a number of ways to install and register SharpShell Shell Extensions. In this section, I'll detail them all.
The regasm Tool
You can use the tool 'regasm' to install and register a shell extension. When using regasm, the shell extension will be installed into the registry (i.e., the Class ID of the COM Server will be put in the COM Server Classes section and associated with the path to the actual server file), it will also register the associations.
The Server Manager Tool
The Server Manager Tool is my preferred approach for installing/uninstalling and registering/unregistering, at least during development, because it lets you install and register as separate steps. It will also let you specify whether you're installing/uninstalling, etc. in 32 bit or 64 bit mode.
Manual Registry Manipulation
Generally a bad approach, but if you absolutely have to, then the MSDN documentation for Shell Extensions describes the changes that must be made to the registry to manually register a COM server, or a Managed COM Server. The documentation is listed in the 'Useful Resources' section.
Cheat Sheet
Here are some useful tips for working with SharpShell and Icon Overlay Handlers.
- Does it seem like your overlay isn't working? Open regedit and check the path:
HKLM\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellIconOverlayHandlers
Windows supports only a limited number of handlers - in alphabetical order. There may be too many installed. - If you need to log events, Run the Server Manager as an Administrator and choose 'Diagnostics > Enable SharpShell Log'. You can now use the functions:
Log
LogError
LogWarning
in your server class, and these messages will be written to the Windows Event Log (under 'Application').
History
- 14th September, 2013: Initial version