Shell Drop Handlers are DLLs that are registered in the system to extend the drag and drop functionality in the Shell. You can use these extensions to allow files to become drop targets for other files, or use the standard drag and drop functionality to invoke your own business logic. In this article I will show you how to create a Drag Handler extension using .NET and a library called SharpShell.

The Drag Handler we'll create will allow the user to drag XML files onto an XSD file, and validate the contents of the XML files against the XSD schema. Here's how it'll look.

Above: Here we drag two XML files over an XSD file - the extension kicks in and shows the visual cue 'Link'.

Above: The user releases the mouse and the extension validates the XML files against the XSD, displaying the results in a dialog.

The Series

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

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 SharpDropHandler

The now that we've set up the project, we can derive the XsdDropHandler class from SharpDropHandler. SharpDropHandler is the base class for Drop Handler Shell Extensions - and it will provide all of the COM plumbing and interop needed - we'll just implement a couple of abstract members to provide the business logic. So here's how your class should look:

publicclass XsdDropHandler : SharpDropHandler
{
}

For a drop handler, there are two abstract functions in the base class that we must implement in the derived class.

DragEnter

protectedabstractvoid DragEnter(DragEventArgs dragEventArgs);

DragEnter is called when the user has selected some shell items and dragged them over the shell item that you register the extension for (so in our case, this will happen when the user drags anything over an XSD file). You must do the following in the DragEnter function:

Check the set of files that are being dragged (these are in the 'DragItems' member).

Depending on what drag operations you'll allow, set the dragEventArgs.Effect member to the effect you are going to allow.

So for example in our drop handler, we'll make sure that every dragged file is an xml file. If they are all xml files, we'll set the drag effect to 'link'.

Drop

protectedabstractvoid Drop(DragEventArgs dragEventArgs);

Drop is called when the user releases the mouse and the actual functionality needs to be invoked. DragEventArgs are provided in case you need to see things like the keys being pressed or the mouse position.

In our example, we'll open up our validation form in this function.

Step 4: Implementing DragEnter

As described, DragEnter is just going to allow the 'link' effect if EVERY drag file is an XML file. Here's the code:

This is straightforward enough not to need too much explanation. We use the Linq statement 'All' to verify a condition on every path (that the extension is xml), if this is true we set the drag effect to link.

Step 5: Implementing Drop

Drop is even more straightforward - we'll pass the paths to the form.

Tip: Remember that for a SharpDropHandler, the dragged files are stored in the property 'DragFiles' and the object we're dragging over is stored in the property 'SelectedItemPath'.

In this function, we pass the xsd path (which is the SelectedItemPath property) and the xml paths (the DragItems property) to our ValidationOutputForm, which we'll build next.

Here you can see how straightforward it is to implement the core business logic for the extension.

Step 6: The Validation Form

I'm not going to go into too much detail here - the code is in the XsdDropHandler sample in the source code. This is essentially a very simple WinForms form that shows a list of validation results, the validation results come from using an XmlReader to read the XML files, validating against the provided schema file.

Step 7: Handling the COM Registration

There are just a few things left to do. First, we must add the ComVisible attribute to our class. This because our class is a COM server and must be visible to other code trying to use it.

[ComVisible(true)]
publicclass XsdDropHandler : SharpDropHandler

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:

Finally, we need to associate our extension with some the types of shell items we want to use it for. We can do that with the COMServerAssociation attribute:

So what have we done here? We've told SharpShell that when registering the server, we want it to be associated with XSD file classes in the system.

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.

We're done! Building the project creates the XsdDropHandler assembly, which can be registered as a COM server to add the extension to the system, allowing you to drag XML files onto an XSD file to validate them against the schema.

Debugging the Shell Extension

If you have seen any of my other articles on .NET Shell Extensions, 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 XsdDropHandler.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 most SharpShell servers can be tested directly inside this application by selecting them and choosing 'Test Shell' - however, at this stage at least, Shell Drop Handlers cannot be tested in this way. There is another mechanism - press 'Test Shell' to open the test shell, then choose 'Shell Open Dialog'.

Once the shell open dialog has opened, you can drag and drop files over the XSD. If you attach a debugger to the Server Manager, you can debug directly into your extension. Remember that you have to Register the server before you can test it.

Comments and Discussions

I'm not convinced writing shell extensions in .net is a good idea or even supported. See this[^] article.

From the article: "One runtime of particular note is the common language runtime (CLR) (CLR), also known as managed code or the .NET Framework. Microsoft recommends against writing managed in-process extensions to Windows Explorer or Windows Internet Explorer and does not consider them a supported scenario."

It seems such code is not supported even if using .net 4's SxS capabilities.

I know many people want to write such extensions using .net, but as far as I can tell it's still not safe to do so.

Indeed Microsoft seem to be unhappy to say that it is supported, and have removed many of the samples that they published of CLR bsaed shell extension handlers. To anyone wanting to know more about whether extensions should or shouldn't be written in .NET there's a page I'm updating here:

So far I'm having no problems with the approach I'm using but it is important to be aware as you have mentioned that Microsoft do not consider this a supported scenario.

The good news is that for more advanced extensions, like Shell Preview Handlers, the system can run them out of process via a surrogate host, which makes .NET extensions perfectly valid (they also back this up in the documentation).