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

Simple shell context menu

By , 14 Aug 2006
 

Introduction

Shell context menus are displayed when you right click on shell objects such as files and folders. A full-blown context menu is a COM object that implements the IContextMenu and IShellExtInt interfaces. This article demonstrates how to create a simple shell context menu (also called a shortcut menu) that does not require COM and only requires a few registry entries.

Registry entries

You can hookup a context menu to any file type by adding entries under the HKEY_CLASSES_ROOT\<file type>\shell registry location. For example, the following registry script adds the Register and Unregister context menus to DLL files.

REGEDIT4

[HKEY_CLASSES_ROOT\dllfile\shell]
[HKEY_CLASSES_ROOT\dllfile\shell\Register]
[HKEY_CLASSES_ROOT\dllfile\shell\Register\command]
@="regsvr32 \"%L\""

[HKEY_CLASSES_ROOT\dllfile\shell\Unregister]
[HKEY_CLASSES_ROOT\dllfile\shell\Unregister\command]
@="regsvr32 /u \"%L\""

A view of the registry is shown below. The HKEY_CLASSES_ROOT\dllfile\shell key contains the list of context menus for DLL files. The Register and Unregister keys are two of the menus for DLL files (these also specify the menu text since a default value is not specified). The default value of the command key specifies the command line that is executed when the context menu is invoked. The %L argument is a placeholder to the full path of the selected item. You can read more about the registry settings at the MSDN article: Extending Shortcut Menus.

Registering and un-registering

The sample application contains the FileShellExtension class that registers and un-registers a simple shell context menu. The Register method creates the necessary registry entries, and the Unregister method removes the registry entries.

static class FileShellExtension
{
    public static void Register(string fileType,
           string shellKeyName, string menuText, string menuCommand)
    {
        // create path to registry location
        string regPath = string.Format(@"{0}\shell\{1}", 
                                       fileType, shellKeyName);

        // add context menu to the registry
        using (RegistryKey key = 
               Registry.ClassesRoot.CreateSubKey(regPath))
        {
            key.SetValue(null, menuText);
        }

        // add command that is invoked to the registry
        using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(
            string.Format(@"{0}\command", regPath)))
        {
            key.SetValue(null, menuCommand);
        }
    }

    public static void Unregister(string fileType, string shellKeyName)
    {
        Debug.Assert(!string.IsNullOrEmpty(fileType) &&
            !string.IsNullOrEmpty(shellKeyName));

        // path to the registry location
        string regPath = string.Format(@"{0}\shell\{1}", 
                                       fileType, shellKeyName);

        // remove context menu from the registry
        Registry.ClassesRoot.DeleteSubKeyTree(regPath);
    }
}

The sample application self-registers when executed without any command line arguments, or with the -register command; it unregisters when the -unregister command is specified. The usage of the FileShellExtension class is shown below.

// sample usage to register
// get full path to self, %L is a placeholder for the selected file
string menuCommand = string.Format("\"{0}\" \"%L\"", 
                                   Application.ExecutablePath);
FileShellExtension.Register("jpegfile", "Simple Context Menu", 
                            "Copy to Grayscale", menuCommand);

// sample usage to unregister
FileShellExtension.Unregister("jpegfile", "Simple Context Menu");

Creating a grayscale image

The CopyGrayscaleImage method is called when the context menu is clicked. The ColorMatrix class is used to generate a grayscale copy of the selected image.

static void CopyGrayscaleImage(string filePath)
{
    // full path to the grayscale copy
    string grayFilePath = Path.Combine(
        Path.GetDirectoryName(filePath),
        string.Format("{0} (grayscale){1}",
        Path.GetFileNameWithoutExtension(filePath),
        Path.GetExtension(filePath)));

    // using calls Dispose on the objects, important
    // so the file is not locked when the app terminates
    using (Image image = new Bitmap(filePath))
    using (Bitmap grayImage = new Bitmap(image.Width, image.Height))
    using (Graphics g = Graphics.FromImage(grayImage))
    {
        // setup grayscale matrix
        ImageAttributes attr = new ImageAttributes();
        attr.SetColorMatrix(new ColorMatrix(new float[][]{
            new float[]{0.3086F,0.3086F,0.3086F,0,0},
            new float[]{0.6094F,0.6094F,0.6094F,0,0},
            new float[]{0.082F,0.082F,0.082F,0,0},
            new float[]{0,0,0,1,0,0},
            new float[]{0,0,0,0,1,0},
            new float[]{0,0,0,0,0,1}}));

        // create the grayscale image
        g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
            0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attr);

        // save to the file system
        grayImage.Save(grayFilePath, ImageFormat.Jpeg);
    }
}

The original and generated grayscale images are shown below:

Running the sample

The sample was built with Visual Studio 2005, and requires the .NET Framework 2.0; however, the ideas can easily be incorporated into any .NET version and language. You can do the following to run the sample:

  • Build and run the application. This registers the context menu by adding the HKEY_CLASSES_ROOT\jpegfile\shell\Simple Context Menu key to the registry.
  • Right click on a JPEG file, you should see a new Copy to Grayscale context menu.
  • Click the context menu to create a grayscale copy of the image.
  • Unregister the context menu by running SimpleContextMenu.exe –unregister.

Context menus for all files, folders, and drives

You can also hookup context menus to all files, folders, and drives by adding entries to the file type's *, Directory, and Drive registry keys. For example, XP PowerToys adds the Open Command Window Here menu to all folders with the following registry script:

REGEDIT4

[HKEY_CLASSES_ROOT\Directory\shell\cmd]
@="Open Command Window Here"

[HKEY_CLASSES_ROOT\Directory\shell\cmd\command]
@="cmd.exe /k \"cd %L\""

Simple context menus do have limitations, such as only accepting one file on the command line, but they are still pretty useful. I'll cover creating a full-blown .NET COM-based context menu in a future article.

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

About the Author

Ralph Arvesen
Web Developer
United States United States
Member
Ralph Arvesen is a software engineer for Vertigo Software and has worked on desktop, web and Pocket PC applications using .NET and C++. Before Vertigo, he designed hardware and firmware for optical inspection systems and has been developing software for the Microsoft platform since Windows 2.0. He co-authored several books and worked as technical editor on others. Ralph lives in the Texas Hill Country west of Austin; his personal site is located at www.lostsprings.com.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberLord Codemonger3 May '13 - 8:59 
what I was looking for
QuestionHow to save excel file path?memberKhuc Manh Thao28 Feb '12 - 15:52 
According to your instructions:
 
<pre>static void CopyGrayscaleImage(string filePath)
          {
               try
               {
                    // full path to the grayscale copy
                    string grayFilePath = Path.Combine(
                         Path.GetDirectoryName(filePath),
                         string.Format("{0} (grayscale){1}",
                         Path.GetFileNameWithoutExtension(filePath),
                         Path.GetExtension(filePath)));
 
                    // using calls Dispose on the objects, important
                    // so the file is not locked when the app terminates
                    using (Image image = new Bitmap(filePath))
                    using (Bitmap grayImage = new Bitmap(image.Width, image.Height))
                    using (Graphics g = Graphics.FromImage(grayImage))
                    {
                         // setup grayscale matrix
                         ImageAttributes attr = new ImageAttributes();
                         attr.SetColorMatrix(new ColorMatrix(new float[][]{  
                              new float[]{0.3086F,0.3086F,0.3086F,0,0},
                              new float[]{0.6094F,0.6094F,0.6094F,0,0},
                              new float[]{0.082F,0.082F,0.082F,0,0},
                              new float[]{0,0,0,1,0,0},
                              new float[]{0,0,0,0,1,0},
                              new float[]{0,0,0,0,0,1}}));
 
                         // create the grayscale image
                         g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height),
                              0, 0, image.Width, image.Height, GraphicsUnit.Pixel, attr);
 
                         // save to the file system
                         grayImage.Save(grayFilePath, ImageFormat.Jpeg);
 
                         // success
                         MessageBox.Show(string.Format("Copied grayscale image {0}", grayFilePath), Program.KeyName);
                    }
               }
               catch (Exception ex)
               {
                    MessageBox.Show(string.Format("An error occurred: {0}", ex.Message), Program.KeyName);
                    return;
               }
          }</pre>
 
So, you will save the parameters of the image file path. However, I do not know how to save the parameter file path of excel. So my request is how to choose my program from Meu context (right click on excel file)
 
kmt
QuestionHow to make work on 64-bit?memberMember 30938448 Dec '11 - 3:45 
this works great on 32-bit OS but I haven't been able to find a way to make it work on 64-bit?
QuestionOn WinXP fine | On Win7 it does not workmemberDiabloPB16 Oct '11 - 22:09 
Hello,
 
on Windows XP its works fine. It registered the "Simple Contect Menu" to the registry. But on Windows 7 it does not work automatically. Spite of admin rights you have to enter it manually Frown | :(
Then it works...
 
I don't know why Sniff | :^)
http://www.pb-software.de.vu

QuestionHow do you do this for a custom file type e.g. *.ttr filesmemberkommand17 Nov '10 - 6:36 
I have registered on the system a custom file type (i.e .ttr) that I need to show context menu for, but this doesn't work, I can however get it to work for many default file types though. What do I need to do for non default file types. Pls help.
GeneralGreat Job!memberoldsellerros17 Nov '09 - 11:32 
Thanks you!Thumbs Up | :thumbsup:
QuestionWhat about custom icon?memberWizard_Memfis2 Sep '09 - 10:48 
Hi!
Thanks for your excellent article!!!
Could you help me with icon? How can I add icon for my menu item? F.e. Zip , ect.
QuestionThe * didn't works well ???memberAdore C++13 Jun '09 - 9:18 
Dear Sir , thanks for your nice code , but u said that if we want to make a shell menu for any file type we use the * for the filetype , indeed it worked fine for many file types except all the image types (jpeg , gif , bmp ,.....) ummm i don't know why ??? do u have any idea about that ??
thanks bye
GeneralDoesn't work in Vista64bitmemberGreg Cadmes22 Jan '09 - 18:39 
Too bad more R&D wasn't done to elaborate on why the context menu item doesn't appear. (Even if the register/unregister was sucessful)
 
Did anyone else get this to work in Vista?
GeneralRegistry shell command for dll not working on vistamemberPaul Shaffer15 Jan '09 - 20:13 
Vista32:
 
Exe and Ocx will show the command in context menu. Dll command won't appear, I've tried everything.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 14 Aug 2006
Article Copyright 2006 by Ralph Arvesen
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid