如何向 shell 文件扩展名添加更多上下文菜单和命令?

How can i add more context menus and commands to the shell file extensions?

我试图做的是将这部分添加到 Program.cs

const string MenuText1 = "List all images";

然后

FileShellExtension.Register(Program.FileType,
                    Program.KeyName, Program.MenuText1,
                    menuCommand);

现在的问题是我在上下文菜单中只看到第二个菜单 MenuText1 而不是 MenuText,我想同时看到它们和 MenuText1 当我点击它时它执行与菜单文本。我想添加更多 MenuTexts 和更多命令,以便每个新的 MenuText1..2..3..4..5 都有自己的命令。

这是 FileShellExtension class 代码

using System;
using System.Diagnostics;
using Microsoft.Win32;

namespace SimpleContextMenu
{
    /// <summary>
    /// Register and unregister simple shell context menus.
    /// </summary>
    static class FileShellExtension
    {
        /// <summary>
        /// Register a simple shell context menu.
        /// </summary>
        /// <param name="fileType">The file type to register.</param>
        /// <param name="shellKeyName">Name that appears in the registry.</param>
        /// <param name="menuText">Text that appears in the context menu.</param>
        /// <param name="menuCommand">Command line that is executed.</param>
        public static void Register(
            string fileType, string shellKeyName, 
            string menuText, string menuCommand)
        {
            Debug.Assert(!string.IsNullOrEmpty(fileType) &&
                !string.IsNullOrEmpty(shellKeyName) &&
                !string.IsNullOrEmpty(menuText) && 
                !string.IsNullOrEmpty(menuCommand));

            // create full 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);
            }
        }

        /// <summary>
        /// Unregister a simple shell context menu.
        /// </summary>
        /// <param name="fileType">The file type to unregister.</param>
        /// <param name="shellKeyName">Name that was registered in the registry.</param>
        public static void Unregister(string fileType, string shellKeyName)
        {
            Debug.Assert(!string.IsNullOrEmpty(fileType) &&
                !string.IsNullOrEmpty(shellKeyName));

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

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

}

这是 Program.cs

using System;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

[assembly: CLSCompliant(true)]
namespace SimpleContextMenu
{
    static class Program
    {
        // file type to register
        const string FileType = "jpegfile";

        // context menu name in the registry
        const string KeyName = "Simple Context Menu";

        // context menu text
        const string MenuText = "Copy to Grayscale";
        const string MenuText1 = "List all images";

        [STAThread]
        static void Main(string[] args)
        {
            // process register or unregister commands
            if (!ProcessCommand(args))
            {
                // invoked from shell, process the selected file
                CopyGrayscaleImage(args[0]);
            }
        }

        /// <summary>
        /// Process command line actions (register or unregister).
        /// </summary>
        /// <param name="args">Command line arguments.</param>
        /// <returns>True if processed an action in the command line.</returns>
        static bool ProcessCommand(string[] args)
        {
            // register
            if (args.Length == 0 || string.Compare(args[0], "-register", true) == 0)
            {
                // full path to self, %L is placeholder for selected file
                string menuCommand = string.Format(
                    "\"{0}\" \"%L\"", Application.ExecutablePath);

                // register the context menu
                FileShellExtension.Register(Program.FileType,
                    Program.KeyName, Program.MenuText,
                    menuCommand);

                FileShellExtension.Register(Program.FileType,
                    Program.KeyName, Program.MenuText1,
                    menuCommand);

                MessageBox.Show(string.Format(
                    "The {0} shell extension was registered.",
                    Program.KeyName), Program.KeyName);

                return true;
            }

            // unregister       
            if (string.Compare(args[0], "-unregister", true) == 0)
            {
                // unregister the context menu
                FileShellExtension.Unregister(Program.FileType, Program.KeyName);

                MessageBox.Show(string.Format(
                    "The {0} shell extension was unregistered.",
                    Program.KeyName), Program.KeyName);

                return true;
            }

            // command line did not contain an action
            return false;
        }

        /// <summary>
        /// Make a grayscale copy of the image.
        /// </summary>
        /// <param name="filePath">Full path to the image to copy.</param>
        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;
            }
        }
    }
}

那么,为什么第二项List all images在注册后覆盖了第一项Copy to Grayscale

让我们打开注册表编辑器来检查注册表设置。

您可以看到 FileShellExtension.Register 方法的第二个参数(在本例中为 Program.KeyName)映射到 注册表项 jpegfile/shell.

所以如果你想注册2个菜单项,你需要提供2个不同的字符串作为shell键名。喜欢 "Simple Context Menu" 和 "Another Context Menu".