Click here to Skip to main content
Click here to Skip to main content
Go to top

File Rating - a practical example of shell extension

, 27 Dec 2004
Rate this:
Please Sign up or sign in to vote.
A shell extension that provides a new Rating column for folders, that allows to sort files by user interest

Introduction

This article presents a practical example of a Shell Extension that I've recently implemented. I was showing travel photos to friends, and I wanted to show only the best photos in my folders. One possible solution was to use one of the great photo managers around but I wanted to work directly with the standard Explorer interface.

The idea is really simple, add a new Rating column to the Folder View of Explorer under Windows XP. This new column can be used to sort the files (photos, MP3s ...) by the user defined rating and it works with the Photo Preview of Explorer, so I can show first the best photos. The side effect of this approach is that it is possible to sort the results of a Search by the Rating thus obtaining the best photos in a folder tree.

This is an example of the extended Explorer view:

Sample image

and these are the new entries in the context menu:

Sample image

Table Of Contents

  1. Shell Extensions - Overview, Debugging, Registration
  2. Implementation
  3. Improvements
  4. Conclusions
  5. References

Shell Extensions

The Windows Shell has a powerful extension mechanism that gives the possibility to provide new functionalities and interaction capabilities to the Shell. The implementation of these extensions in C++ and COM was quite difficult, but a lot has changed with the introduction of .NET. (In the References section, I've reported some links.)

This is a schema that explains the possible Shell Extensions that can be created and what is used by this article.

Debugging

The debugging of Shell Extension with .NET is the same as that of COM (see this). It's just necessary to specify the Explorer.exe as the executable for the debugging session and set to 1 the DesktopProcess DWORD value of the key.

HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer

This value tells the Explorer to create a separate process for each window and one for the Taskbar, easing the debugging of the extension.

Registration

The registration process has an extension type specific part and the general part. The general part is mostly performed by the regasm.exe utility (invoked by VS.NET) that addresses all the COM-.NET connection. If the extension is intended to be installed on non-administrator accounts, it's important to register it under the Approved set of extensions:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved

It's sufficient to add a new string value to this key with the name as the curly braced GUID of the class and an optional description. To inspect the installed extension, there is the Autoruns utility by SysInternals.

The extension specific registration can be performed directly by managed code using two special attributes ComRegisterFunctionAttribute and ComUnregisterFunctionAttribute. The following snippet of code presents how to implement that for registering this extension.

#region Registration
[System.Runtime.InteropServices.ComRegisterFunctionAttribute()]
static void RegisterServer(String str1)
{
    try
    {
        string keyname = "File Rating";
        string guid = "{"+typeof(RatingColumnHandler).GUID.ToString()+"}";
        RegistryKey rk,rk2;
        rk = Registry.ClassesRoot.OpenSubKey(@"*\shellex\ContextMenuHandlers", true);

        ...
    }
    catch(Exception e)
    {
    }
}

[System.Runtime.InteropServices.ComUnregisterFunctionAttribute()]
static void UnregisterServer(String str1)
{
    try
    {
        string keyname = "File Rating";
        string guid = "{"+typeof(RatingColumnHandler).GUID.ToString()+"}";
        RegistryKey rk;
        rk = Registry.ClassesRoot.OpenSubKey(@"*\shellex\ContextMenuHandlers", true);
        rk.DeleteSubKey(keyname, false);
        ...
    }
    catch(Exception e)
    {
    }
}
#endregion

Implementation

The File Rating extension uses a Column Handler to add a new column to the Detailed view of Explorer, the column is registered for in the folders ("Folder/shellex/ColumnHandlers" in the registry's Classes root) and implemented through the interface IColumnProvider. The values of the column can be used for sorting the files, also in the Preview mode of the Explorer.

I've decided to store the rating information of each folder into a .rating file where, in each line, there is the rating, a tab, and then the file name. This is the simplest solution, but there are some issues that I'll discuss in the future work. This file is cached by the Column Handler, and each time, it can be checked against changes using a timestamp.

The user can change the ratings by editing directly the .rating file or better by using a new entry in the Context Menu associated with every file ("*/shellex/ContextMenuHandlers" in the registry's Classes root). Two interfaces, IShellExtInit and IContextMenu are required for the correct implementation of this extension.

IShellExtInit

The method Initialize of this interface is invoked when the extension is going to be invoked on a new folder, and it gives the occasion for obtaining the folder and the files involved in the operation. This operation is carried on by using some Clipboard and Drag&Drop relative functions, and it could be nicely wrapped in a helper class. The list of the files is saved during the initialization phase and used later during the menu construction and invocation (for changing the menu depending on the selection).

IContextMenu

This interface is used to obtain the effective menu for the selection of files involved in the operation (QueryContextMenu) and to process the option selected by the user (InvokeCommand). Optionally, it can provide to the Shell, help information (GetCommandString).

The QueryContextMenu answers to the question of the layout of the menu, and it requires some Win32 menu construction. Each entry is associated to an identifier that is passed to the InvokeCommand when the user selects the menu entry. In this case, the menu is not dependent on the selection and it uses a submenu to group the options:

int IContextMenu.QueryContextMenu(HMenu hMenu, int iMenu, 
                 int idCmdFirst, int idCmdLast, CMF uFlags)
{
    int id = 1;
    if ( (uFlags & (CMF.CMF_VERBSONLY|CMF.CMF_DEFAULTONLY|CMF.CMF_NOVERBS)) == 0 || 
        (uFlags & CMF.CMF_EXPLORE) != 0)
    {
        HMenu submenu = ShellLib.Helpers.CreatePopupMenu();
        Helpers.AppendMenu(submenu, MFMENU.MF_STRING|MFMENU.MF_ENABLED, 
                           new IntPtr(idCmdFirst + id++), "Rating ++");
        Helpers.AppendMenu(submenu, MFMENU.MF_STRING|MFMENU.MF_ENABLED, 
                           new IntPtr(idCmdFirst + id++), "Rating --");
        Helpers.AppendMenu(submenu, MFMENU.MF_STRING|MFMENU.MF_ENABLED, 
                           new IntPtr(idCmdFirst + id++), "Zero Rating");
        Helpers.AppendMenu(submenu, MFMENU.MF_STRING|MFMENU.MF_ENABLED, 
                           new IntPtr(idCmdFirst + id++), "About");
        Helpers.InsertMenu(hMenu, 5, 
                           MFMENU.MF_BYPOSITION|MFMENU.MF_POPUP|MFMENU.MF_ENABLED, 
                           submenu.handle, "File Rating");
    }
    return id;
}
<!--One of the problem that I've found using existing code about Shell Extensions, is relative to the correct usage of P/Invoke. In some cases the Win32 HANDLEs like HMENU and HBITMAP.-->

Improvements

There are some issues about this extension, but they don't really prevent its usage.

  1. In the case of read only folders, the .rating file solution is not applicable, and a centralized solution is better, but it would increase the complexity of this extension.
  2. When a file is renamed or moved, the rating information is lost; this could be addressed by using a FileWatcher on the folder, but it has the side effect.
  3. The solution of an additional hidden file in a folder is not nice, because there are too many. An alternative solution that also solves problem #2 is to use the NTFS extended properties. This is a feature of NTFS 5.0 that gives the opportunity to associate properties to file like Title, Category, and in this case, the Rating. In general, the file rating information could be stored inside the metadata information of a Metadata based file system.
  4. When the user changes the Rating by the context menu, the Explorer view is not updated, and it's required to do a refresh command. (Can anyone suggest me how to do this?)
  5. The rating information could be computed in some automatic way, by tracking file usage or other information, like it's performed by the latest Windows Media Player.

Conclusions

This short article presents here a practical example of shell extension that can be used to rate files like photos or audio files. I hope that it will be useful to someone.

References

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Emanuele Ruffaldi
Software Developer (Senior) Scuola Superiore S.Anna
Italy Italy
Assistant Professor in Applied Mechanics working in Virtual Reality, Robotics and having fun with Programming

Comments and Discussions

 
QuestionDo we need a separate dll? PinmemberGoran _3-Jul-08 6:02 
QuestionFor Folders to? Pinmembertermal18-Jun-08 1:11 
QuestionCan't set breakpoint? Pinmembertermal13-Jun-08 4:57 
Generalvista includes native star rating handlers in explorer Pinmemberumeca7422-Apr-08 23:24 
GeneralDo not write in-process shell extensions in managed code PinmemberSteveKing20-Dec-06 2:16 
GeneralRe: Do not write in-process shell extensions in managed code PinmemberEmanuele Ruffaldi20-Dec-06 2:37 
GeneralRe: Do not write in-process shell extensions in managed code PinmemberAndyCLon3-Apr-08 1:35 
GeneralRe: Do not write in-process shell extensions in managed code PinmemberGoran _3-Jul-08 5:57 
QuestionHow do i provide two diffrent context menu basen on which extentions the files has. Pinmemberthomaxz.tc14-Dec-06 9:57 
QuestionRe: How do i provide two diffrent context menu basen on which extentions the files has. Pinmemberthomaxz.tc14-Dec-06 21:21 
GeneralTwo questions Pinmemberafaz22-Aug-06 1:11 
Questionproblem with nvu ? PinmemberIvi221-Aug-06 0:51 
GeneralUnicode + Centralized database PinmemberOCedHrt17-Mar-06 13:35 
QuestionIcon and Status text Pinmemberwakake26-Nov-05 10:37 
AnswerRe: Icon and Status text Pinmemberwakake27-Nov-05 3:54 
GeneralChaning the background colour of a row PinmemberTimothyP23-Aug-05 23:23 
GeneralNew version PinmemberEmanuele Ruffaldi19-Jul-05 23:46 
GeneralSolution for improvement 4 Pinmemberpanto27-Jun-05 22:13 
Generalsame bug like in my extensions Pinmemberstax07111-May-05 10:53 
GeneralSimpler IShellExtInit Implementation PinmemberGenericMoniker9-Apr-05 2:35 
GeneralRe: Simpler IShellExtInit Implementation Pinmemberneo260077715-May-05 7:18 
GeneralRe: Simpler IShellExtInit Implementation PinmemberGenericMoniker16-May-05 4:17 
GeneralInstalling on non dev machine PinmemberTorsten Dicke20-Mar-05 9:30 
GeneralRe: Installing on non dev machine Pinmemberfaken ame25-Oct-08 21:05 
GeneralFolder information - pidlFolder == 0 Pinmember_Aaron_15-Mar-05 9:16 
AnswerRe: Folder information - pidlFolder == 0 Pinmemberafaz22-Aug-06 12:04 
GeneralRe: Folder information - pidlFolder == 0 [modified] PinmemberCristian Amarie1-May-08 19:45 
GeneralShellLib.cs - GetCommandString PinmemberTormentoR-18-Feb-05 12:08 
GeneralRe: ShellLib.cs - GetCommandString PinmemberEli Brody11-Nov-05 8:22 
GeneralNice PinmemberRussKie28-Dec-04 11:09 
GeneralInteresting but PinstaffPaul Watson28-Dec-04 0:28 
GeneralRe: Interesting but PinmemberEmanuele Ruffaldi28-Dec-04 1:46 
GeneralBroken Image link. PinmemberMr.Prakash27-Dec-04 22:56 
GeneralRe: Broken Image link. PinmemberEmanuele Ruffaldi27-Dec-04 23:20 

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
Web01 | 2.8.140916.1 | Last Updated 28 Dec 2004
Article Copyright 2004 by Emanuele Ruffaldi
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid