Добавляем пункт в системное меню

image
Иногда требуется создать свой пункт в системном меню (в меню Windows Explorer). Я как начинающий .NET-разработчик с такой проблемой недавно столкнулся. Её решение на языке C# привожу ниже. Надеюсь, кому-нибудь пригодится. Для примера в данном посте я расскажу, как добавить новый пункт в контекстное меню папки.

Пишем код


Для решения задачи будем работать с реестром. Именно в нем нужно зарегистрировать наш пункт меню. Для регистрации создадим следующие переменные:
  1. //Переменные для регистрации
  2. private const string MenuName = "Folder\\shell\\NewMenuOption";
  3. private const string Command = "Folder\\shell\\NewMenuOption\\command";
* This source code was highlighted with Source Code Highlighter.

Как вы смогли заметить, на форме находятся две кнопки, одна addBtn регистрирует пункт в реестре, другая удаляет его. Код для добавления будет выглядеть так:
  1. //Прописываем пункт в реестре
  2. private void addBtn_Click(object sender, EventArgs e)
  3. {
  4.   RegistryKey regmenu = null; RegistryKey regcmd = null;
  5.   try
  6.   {
  7.     regmenu = Registry.ClassesRoot.CreateSubKey(MenuName);
  8.     if (regmenu != null)
  9.       regmenu.SetValue("", nameBox.Text);
  10.     regcmd = Registry.ClassesRoot.CreateSubKey(Command);
  11.     if (regcmd != null)
  12.       regcmd.SetValue("", pathBox.Text);
  13.   }
  14.     catch (Exception ex)
  15.   {
  16.     MessageBox.Show(this, ex.ToString());
  17.   }
  18.   finally
  19.   {
  20.     if (regmenu != null)
  21.       regmenu.Close();
  22.     if (regcmd != null)
  23.       regcmd.Close();
  24.   }
  25. }
* This source code was highlighted with Source Code Highlighter.

Думаю, здесь всё и так понятно. Данные для регистрации пункта (его имя и путь к приложению, которое будет выполняться по клику на него) берем из двух TextBox-ов, которое находятся на форме — nameBox (имя пункта меню) и pathBox (путь к исполняемому файлу).
Аналогично пишем код для удаления:
  1. //Удаляем пункт меню из реестра
  2. private void removeBtn_Click(object sender, EventArgs e)
  3. {
  4.   try
  5.   {
  6.     RegistryKey reg = Registry.ClassesRoot.OpenSubKey(Command);
  7.     if (reg != null)
  8.       {
  9.         reg.Close();
  10.         Registry.ClassesRoot.DeleteSubKey(Command);
  11.       }
  12.     reg = Registry.ClassesRoot.OpenSubKey(MenuName);
  13.     if (reg != null)
  14.     {
  15.       reg.Close();
  16.       Registry.ClassesRoot.DeleteSubKey(MenuName);
  17.     }
  18.   }
  19.   catch (Exception ex)
  20.   {
  21.     MessageBox.Show(this, ex.ToString());
  22.   }
  23. }
* This source code was highlighted with Source Code Highlighter.

Не забудьте, что для работы с реестром нам нужно подключить пространство имен Microsoft.Win32.
Для выбора исполняемого файла, который будет запускаться по нашему пункту у нас на форме присутствует кнопка appPathBtn:
  1. //Диалог выбора исполняемого файла
  2. private void appPathBtn_Click(object sender, EventArgs e)
  3. {
  4.   if (sender == appPathBtn)
  5.   {
  6.     openFileDialogExe.Filter = "exe files (*.exe)|*.exe|All files (*.*)|*.*";
  7.     if (openFileDialogExe.ShowDialog(this) == DialogResult.OK)
  8.       pathBox.Text = openFileDialogExe.FileName;
  9.   }
  10. }
* This source code was highlighted with Source Code Highlighter.

Для выбора диалога используем openFileDialog:
image

Так же можно дополнительно сделать проверку на правильность введенных данных (например, на существование указанного исполняемого файла и т.д.):
private void pathBox_TextChanged(object sender, EventArgs e)
{
  if (((TextBox)sender).Text.Length > 0)
  {
    if (sender.Equals(pathBox))
    {
      if (pathBox.Text.IndexOf('\\') >= 0)
        addBtn.Enabled = nameBox.Text.Length > 0 && File.Exists(pathBox.Text);
      else
        addBtn.Enabled = nameBox.Text.Length > 0;
    }
  }
  else
  {
    addBtn.Enabled = false;
  }
  removeBtn.Enabled = nameBox.Text.Length > 0 || pathBox.Text.Length > 0;
}


* This source code was highlighted with Source Code Highlighter.

private void nameBox_TextChanged(object sender, EventArgs e)
{
  if (((TextBox)sender).Text.Length > 0)
  {
    if (sender.Equals(pathBox))
    {
      if (pathBox.Text.IndexOf('\\') >= 0)
        addBtn.Enabled = nameBox.Text.Length > 0 && File.Exists(pathBox.Text);
      else
        addBtn.Enabled = nameBox.Text.Length > 0;
    }
  }
  else
  {
    addBtn.Enabled = false;
  }
  removeBtn.Enabled = nameBox.Text.Length > 0 || pathBox.Text.Length > 0;
}


* This source code was highlighted with Source Code Highlighter.

И, наконец, последнее, что сделаем, напишем код, который при загрузке формы будет проверять разрешено ли нам прописывать в реестре нужные нам ключи. Поключаем необходимые пространства имен:
using System.Security;
using System.Security.Permissions;


* This source code was highlighted with Source Code Highlighter.

Опишем вспомогательную функцию:
//Проверяем доступ
private void CheckSecurity()
{
  RegistryPermission regPerm;
  regPerm = new RegistryPermission(RegistryPermissionAccess.Write, "HKEY_CLASSES_ROOT\\" + MenuName);
  regPerm.AddPathList(RegistryPermissionAccess.Write, "
HKEY_CLASSES_ROOT\\" + Command);
  regPerm.Demand();
}


* This source code was highlighted with Source Code Highlighter.

Заканчиваем написанием обработчика события Form_Load:
  1. private void mainForm_Load(object sender, EventArgs e)
  2. {
  3.   RegistryKey regmenu = null;
  4.   RegistryKey regcmd = null;
  5.   try
  6.   {
  7.     this.CheckSecurity();
  8.     addBtn.Enabled = false;
  9.     regmenu = Registry.ClassesRoot.OpenSubKey(MenuName, false);
  10.     if (regmenu != null)
  11.       nameBox.Text = (String)regmenu.GetValue("");
  12.     regcmd = Registry.ClassesRoot.OpenSubKey(Command, false);
  13.     if (regcmd != null)
  14.       pathBox.Text = (String)regcmd.GetValue("");
  15.     removeBtn.Enabled = nameBox.Text.Length > 0 || pathBox.Text.Length > 0;
  16.   }
  17.   catch (ArgumentException ex)
  18.   {
  19.     // RegistryPermissionAccess.AllAccess НЕ может быть использован как параметр для GetPathList.
  20.     MessageBox.Show(this, "An ArgumentException occured as a result of using AllAccess. "
  21.       + "AllAccess cannot be used as a parameter in GetPathList because it represents more than one "
  22.       + "type of registry variable access : \n" + ex);
  23.   }
  24.   catch (SecurityException ex)
  25.   {
  26.     // RegistryPermissionAccess.AllAccess НЕ может быть использован как параметр для GetPathList.
  27.     MessageBox.Show(this, "An ArgumentException occured as a result of using AllAccess. " + ex);
  28.     addBtn.Enabled = false;
  29.     removeBtn.Enabled = false;
  30.   }
  31.   catch (Exception ex)
  32.   {
  33.     MessageBox.Show(this, ex.ToString());
  34.   }
  35.   finally
  36.   {
  37.     if (regmenu != null)
  38.       regmenu.Close();
  39.     if (regcmd != null)
  40.       regcmd.Close();
  41.   }
  42. }
* This source code was highlighted with Source Code Highlighter.


Результат нашего труда привожу ниже.
image

Прописываем нужные данные и жмем кнопку «Добавить». Открываем любое окно Windows Explorer и видим:
image

Если кликнуть на пункт, откроется приложение MpTrim. По аналогии можно прописать свой пункт меню как для всех файлов и папок, так и для отдельных типов, допустим графических.

Надеюсь, данный мой пост кому-нибудь поможет ;)


Скачать исходный код проекта


Пост в моем блоге

 

 



Опубликовал admin
9 Июн, Вторник 2009г.



Программирование для чайников.