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

.NET Shell Extensions - Shell Drop Handlers

, 19 Jan 2013
Rate this:
Please Sign up or sign in to vote.
Rapidly create Shell Drop Handler Extensions using .NET
Introduction   

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:

  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    

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 'XsdDropHandler'. Rename the 'Class1.cs' file to 'XsdDropHandler.cs'.   

Now add the following references:  

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

These references contain various useful bits and pieces that other parts of the SharpShell library will need, such as icons and context menus. 

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 Core Library' zip file at the top of the article and add a reference to the 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 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:   

public class XsdDropHandler : SharpDropHandler
{
} 
For a drop handler, there are two abstract functions in the base class that we must implement in the derived class. 

DragEnter 

protected abstract void 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: 

  1. Check the set of files that are being dragged (these are in the 'DragItems' member).
  2. 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 

protected abstract void 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:

/// <summary>
/// Checks what operations are available for dragging onto the target with the drag files.
/// </summary>
/// <param name="dragEventArgs">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
protected override void DragEnter(DragEventArgs dragEventArgs)
{
    //  Check the drag files - if they're all XML, we can validate them against the XSD.
    dragEventArgs.Effect =
        DragItems.All(di => string.Compare(Path.GetExtension(di), ".xml", StringComparison.InvariantCultureIgnoreCase) == 0)
            ? DragDropEffects.Link : DragDropEffects.None;
}

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'. 

/// <summary>
/// Performs the drop.
/// </summary>
/// <param name="dragEventArgs">The <see cref="System.Windows.Forms.DragEventArgs"/> instance containing the event data.</param>
protected override void Drop(DragEventArgs dragEventArgs)
{
    //  Create the validator output form.
    var validatorOutputForm = new ValidationOutputForm {XsdFilePath = SelectedItemPath, XmlFilePaths = DragItems};
    validatorOutputForm.ShowDialog();
}

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)]
public class 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:

[COMServerAssociation(AssociationType.ClassOfExtension, ".xsd")]
public class XsdDropHandler : SharpDropHandler 

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. 

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.   

License

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

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

 
QuestionUnsafe... PinmemberStephen Hewitt20-Jan-13 2:01 
AnswerRe: Unsafe... PinmvpDave Kerr24-Jan-13 11:52 
GeneralRe: Unsafe... PinmemberSteveKing24-Feb-13 23:05 

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 | Mobile
Web02 | 2.8.140721.1 | Last Updated 19 Jan 2013
Article Copyright 2013 by Dave Kerr
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid