0

In the Program.cs i added a class:

public static class Menus
        {
            public static string MenuShare1 = "FaceBook";
            public static string MenyShare2 = "Tapuz";
        }

Then i added also a context menu string variable:

const string MenuText2 = "Share >";

What i want to do is when i make right click with the mouse in the directory i'm in today now it's showing me "Copy to Grayscale" and "Resize all images" i want it to show also the context menu "Share >" and when i click or move the mouse over on the "Share >" it will open sub context menus from the class Menus one under the other:

FaceBook Tapuz

And if i will click on FaceBook or Tapuz then it will do something.

In 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
    {

        public static class Menus
        {
            public static string MenuShare1 = "FaceBook";
            public static string MenyShare2 = "Tapuz";
        }

        // file type to register
        const string FileType = "bitmapfile";//"jpegfile";

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

        // context menu text
        const string MenuText = "Copy to Grayscale";
        const string MenuText1 = "Resize all images";
        const string MenuText2 = "Share >";

        [STAThread]
        static void Main(string[] args)
        {
            // process register or unregister commands
            if (!ProcessCommand(args))
            {
                string action = args[0];
                //MessageBox.Show(action);
                string fileName = args[1];

                if (action == "Copy")
                {
                    // invoked from shell, process the selected file
                    CopyGrayscaleImage(fileName);
                }
                else if (action == "Resize")
                {
                    string FilePath = Path.Combine(
                    Path.GetDirectoryName(fileName),
                    string.Format("{0} (resized){1}",
                    Path.GetFileNameWithoutExtension(fileName),
                    Path.GetExtension(fileName)));
                    //MessageBox.Show(FilePath);
                    Bitmap bmp1 = new Bitmap(ResizeImages(fileName,100,100));
                    bmp1.Save(FilePath);
                    bmp1.Dispose();
                }
            }
        }

        /// <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}\" Copy \"%L\"", Application.ExecutablePath);

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

                string menuCommand1 = string.Format("\"{0}\" Resize \"%L\"", Application.ExecutablePath);

                FileShellExtension.Register(Program.FileType,
                    Program.KeyName1, Program.MenuText1,
                    menuCommand1);
                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;
            }
        }

        private static Bitmap ResizeImages(String filename, int maxWidth, int maxHeight)
        {
            using (Image originalImage = Image.FromFile(filename))
            {
                //Caluate new Size
                int newWidth = originalImage.Width;
                int newHeight = originalImage.Height;
                double aspectRatio = (double)originalImage.Width / (double)originalImage.Height;
                if (aspectRatio <= 1 && originalImage.Width > maxWidth)
                {
                    newWidth = maxWidth;
                    newHeight = (int)Math.Round(newWidth / aspectRatio);
                }
                else if (aspectRatio > 1 && originalImage.Height > maxHeight)
                {
                    newHeight = maxHeight;
                    newWidth = (int)Math.Round(newHeight * aspectRatio);
                }
                if (newWidth >= 0 && newHeight >= 0)
                {
                    Bitmap newImage = new Bitmap(newWidth, newHeight);
                    using (Graphics g = Graphics.FromImage(newImage))
                    {
                        //--Quality Settings Adjust to fit your application
                        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
                        g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                        g.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                        g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
                        g.DrawImage(originalImage, 0, 0, newImage.Width, newImage.Height);
                        return newImage;
                    }
                }
                return null;
            }
        }
    }
}

And FileShellExtension.cs

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);
        }
    }

}

UPDATE

This is what i tried now. In Program.cs in the Main method i added:

else if (action == "Share")
                {
                    // create full path to registry location under the key you created
                    string regSubPath = string.Format(@"{0}\shell\{1}\Share", FileType, KeyName2);

                    // add context menu to the registry
                    using (Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.ClassesRoot.CreateSubKey(regSubPath))
                    {
                        key.SetValue(null, "Tapuz");
                    }
                }

But it's not showing a sub menu when i click on "Share Media" And it was better to do as it is in the file explorer when you move the mouse over the context menu after a second a sub menu is open without clicking on it.

Like for example: Send to There is a menu Send to with a small black arrow to the right when you move the mouse over it on it it's opening a sub context menu.

Rubi Reubi
  • 103
  • 8
  • While you do provide a lot of information and code (Good), it's unclear what difficulty you have in implementing this. Are you seeing an error? Did you research and didn't find how to add a share menuItem? – Roy Falk Feb 01 '16 at 19:24
  • My problem is how to add the sub menus. What i did now is added the "Share >" as a context menu i added a new string menuCommand2 and registering it like i did with the others so now when i make right mouse click in the directory i see also the "Share >" menu. Then in the Main method i added a new check: else if (action == "Share") and inside i'm calling a new method i did: static void Commands(string menuCommand,FileShellExtension fse) { } but i'm not sure how to continue. It's not simple context menu like in winforms designer. – Rubi Reubi Feb 01 '16 at 20:03
  • 1
    This is a possible duplicate of http://stackoverflow.com/q/16146801/5276890. – Roy Falk Feb 01 '16 at 20:40
  • I will check the link and will try to solve it. But from what i saw in the link they are talking about ContextMenu of winforms my project my solution is not winforms. It's shell file and registertion. – Rubi Reubi Feb 02 '16 at 07:29

1 Answers1

1

Looking at this question and the official documentation (and also your code), I think you just need to create the menu items in the registry in the path under the 'Share' menuitem.

In other words, if you were to open regedit and browse to the relevant branch (HKEY_CLASSES_ROOT.fileType\Shell\Share) and add Tapuz, it would add the submenu to the windows explorer. The command to do this is (probably):

using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(regPath))
{
    key.SetValue(null, "Tapuz");
}

I assume the condition you talked about (if action == share) is for setting the callback. In other words, what would run if you were to click on share. Since share is the title of a submenu, I would say this isn't needed.

======================================================================== Just to clarify.

  1. open regedit and browse to the relevant location. See if you can see share, tapuz, fb, copy to gs and resize as keys.
  2. If you see some of them, add what's missing and see if now explorer behaves better.
  3. Once that's done, delete the keys and try to do it from the code with FileShellExtension.cs : register.
  4. If that works, you can then move to SimpleContextMenu and the function callbacks.

In any case, always check the program output against what's in the registry, as that's where it's supposed to be reflected and compare to something known, like open with...

Community
  • 1
  • 1
Roy Falk
  • 1,685
  • 3
  • 19
  • 45
  • Roy it's fine. I tried your solution in the Main method. Not sure if it suppose to be in the Main method i added a new if else ( action ==.... and inside added your solution. Please look at my question i edited it with an UPDATE of what i did. Thank you. – Rubi Reubi Feb 02 '16 at 22:56
  • Sorry for the delay. See my edit in response to yours. – Roy Falk Feb 04 '16 at 16:48
  • Roy sorry for the mess i edited my question again showing Program.cs with what i did. You can see it here: http://pastebin.com/qaZPgFm7 sorry again. I marked not to use the if else (action == share) and added the code in your solution after where i make Register for the share. But when i click on Share Media it does nothing. – Rubi Reubi Feb 04 '16 at 21:01