Manipulating the Windows Context Menu with .NET

Introduction

I am by nature a very lazy person. Couple my laziness with curiosity and enthusiasm and you end up with wacky solutions to problems you never knew existed. Have you ever wondered how to programmatically add items to the Windows context menu? Let’s say, for example: You would like to add an item under the ‘Send To’ menu, or you would like to add a menu such as ‘Copy to Folder’ to the Windows menu. It is possible and it is quite easy; you just need a bit of Registry manipulation.

Today, you will learn how to add a ‘Copy to Folder’ option and another menu option onto the Windows context menu.

Practical

Create a new C# or VB.NET Windows Forms project. Once the form has finished loading, add two buttons to the form. Your simple design should look like Figure 1.

Our Design
Figure 1: Our Design

To add the ‘Copy to Folder‘ option to a system menu, you need to manipulate the Registry. If you are uncertain of what I mean by ‘Copy to Folder,’ take a look at Figure 2.

Copy to Folder
Figure 2: Copy to Folder

The ‘Copy to Folder’ option enables you to copy files directly to a folder without navigating to it through Windows Explorer. You simply select the Folder you’d want to copy to and voilà! Let’s add this menu option now, starting with the namespaces, as usual.

C#

using Microsoft.Win32;

VB.NET

Imports Microsoft.Win32

The Microsoft.Win32 Namespace contains all the classes and methods for any Registry manipulation. Many professional programmers do not like manipulating the Registry, especially with system settings. I agree with them, but not completely. If you know what you are doing, why not use the Registry? Why reinvent the wheel, and why overcomplicate certain things? Enough ranting from me.

Add the following member variables:

C#

      private RegistryKey rkReg = Registry.ClassesRoot;

      private string strKey = @"AllFilesystemObjects\shellex\
         ContextMenuHandlers\CopyTo";
      private string strClSID = "{C2FBB630-2971-11D1-A18C-
         00C04FD75D13}";

VB.NET

   Private rkReg As RegistryKey = Registry.ClassesRoot

   Private strKey As String = "AllFilesystemObjects\shellex\ _
      ContextMenuHandlers\CopyTo"

   Private strClSID As String = "{C2FBB630-2971-11D1-A18C- _
      00C04FD75D13}"

A main Registry object gets created; it represents the Registry root: HKEY_CLASSES_ROOT. The key object represents the key we need to manipulate to get the ‘Copy To Folder’ option in our menus. The CLSID object represents the ‘Copy To Folder’ object. As mentioned in an earlier article, the CLSID is the object’s Class ID. This is how Windows sees and identifies the object. The object in this case is the desired window. For more information regarding the CLSID object in Windows Explorer, please refer to these articles:

Add the CopyTo sub procedure and the call to it:

C#

      private void CopyTo()
      {
         RegistryKey rkKey = rkReg.OpenSubKey(strKey);

         if (rkKey == null)
         {

            try
            {

               rkKey = rkReg.CreateSubKey(strKey);
               rkKey.SetValue(string.Empty, strClSID);

            }
            catch (UnauthorizedAccessException ex)
            {

               MessageBox.Show("Error", "Error",
                  MessageBoxButtons.OK, MessageBoxIcon.Error);

            }

         }

         else
         {

            MessageBox.Show("Already installed.", "Error",
               MessageBoxButtons.OK, MessageBoxIcon.Error);

         }
      }
      private void Button1_Click_1(object sender, EventArgs e)
      {

         CopyTo();

      }

VB.NET

   Private Sub CopyTo()

      Dim rkKey As RegistryKey = rkReg.OpenSubKey(strKey)

      If rkKey Is Nothing Then

         Try

            rkKey = rkReg.CreateSubKey(strKey)
            rkKey.SetValue(String.Empty, strClSID)

         Catch ex As UnauthorizedAccessException

            MessageBox.Show("Error", "Error", _
               MessageBoxButtons.OK,  MessageBoxIcon.Error)

         End Try

      Else

         MessageBox.Show("Already installed.", "Error", _
            MessageBoxButtons.OK, MessageBoxIcon.Error)

      End If

   End Sub

   Sub Button1_Click(sender As Object, e As EventArgs) _
         Handles Button1.Click

      CopyTo()

   End Sub

The preceding sub procedure simply creates the Registry key you initialized earlier and does some error trapping. If the setting and the key already exist, a MessageBox will inform you.

Adding an extra menu option to the Send To menu is not so easy. You need to manipulate the shell object and create the shortcut with its help and with the help of the Windows Scripting Host. Once the menu option has been created, it is permanent—unless you decide to delete it manually. The Shortcuts under the ‘Send To’ menu object are created and exist in the following location:

C:\Users\<yourusername>\AppData\Roaming\Microsoft\Windows\SendTo

Follow these steps to add a Reference to the Windows Script Host Object Model that’s shown in Figure 3:

  1. Click Project.
  2. Click Add Reference.
  3. Select the COM tab.
  4. Check Windows Script Host Object Model.
  5. Click OK.

Adding a Reference
Figure 3: Adding a Reference

Add the Windows Script Host Object Model Namespace in your code as well.

C#

using IWshRuntimeLibrary;

VB.NET

Imports IWshRuntimeLibrary

Add the sub and its call.

C#

      private void SendToShortcut()
      {

         object shDesktop = (object)"Desktop";
         WshShell shell = new WshShell();

         string shortcutAddress = Environment.GetFolderPath
            (Environment.SpecialFolder.ApplicationData) +
            @"\Roaming\Microsoft\Windows\SendTo\" +
            System.Diagnostics.Process.GetCurrentProcess()
            .ProcessName;

         IWshShortcut shortcut = (IWshShortcut)shell
            .CreateShortcut(shortcutAddress);

         shortcut.Description = "Shortcut to Your app";

         shortcut.TargetPath = Environment.GetFolderPath
            (Environment.SpecialFolder.ApplicationData) +
            @"\Roaming\Microsoft\Windows\SendTo\" +
            System.Diagnostics.Process.GetCurrentProcess()
            .ProcessName;

         shortcut.Save();

      }
      private void Button2_Click(object sender, EventArgs e)
      {
         SendToShortcut();
      }

VB.NET

   Private Sub SendToShortcut()

      Dim shDesktop As Object = CObj("Desktop")

      Dim shell As WshShell = New WshShell()

      Dim shortcutAddress As String = Environment.GetFolderPath _
         (Environment.SpecialFolder.ApplicationData) & _
            "\Roaming\Microsoft\Windows\SendTo\" + System _
            .Diagnostics.Process.GetCurrentProcess().ProcessName
      Dim shortcut As IWshShortcut = CType(shell.CreateShortcut _
         (shortcutAddress), IWshShortcut)

      shortcut.Description = "Shortcut to Your app"
      shortcut.TargetPath = Environment.GetFolderPath(Environment _
         .SpecialFolder.ApplicationData) & "\Roaming\ _
         Microsoft\Windows\SendTo\" + System.Diagnostics.Process _
         .GetCurrentProcess().ProcessName
      shortcut.Save()

   End Sub
   Private Sub Button2_Click(sender As Object, e As EventArgs) _
         Handles Button2.Click

      SendToShortcut()

   End Sub

With the help of the Windows Scripting Host, a Shortcut gets created in the correct location for ‘Send To.’

You can download the source code for the project from GitHub.

Conclusion

Being lazy has its advantages! The Windows menu is quite easy to manipulate; feel free to explore it further.

Hannes DuPreez
Hannes DuPreez
Ockert J. du Preez is a passionate coder and always willing to learn. He has written hundreds of developer articles over the years detailing his programming quests and adventures. He has written the following books: Visual Studio 2019 In-Depth (BpB Publications) JavaScript for Gurus (BpB Publications) He was the Technical Editor for Professional C++, 5th Edition (Wiley) He was a Microsoft Most Valuable Professional for .NET (2008–2017).

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read