Add shell context menu only in my application

In my .NET Framework 4 application, I show files, folders, and other materials that are not part of the file system. For files and folders, I was able to display the Windows Shell context menu for this item, thanks to this code in MSDN . (It still doesn't display the carbonite shell extension, but I'm distracted.)

My struggle is to add my own submenu to the Shell context menu. All my research refers to the so-called Shell Extensions, which, if I understand correctly, are a system-wide change. I just want to add Shell to the context menu when it is available from my application.

Grasping on the straws, admittedly, I tried to add the following to the ShowContextMenu class ShowContextMenu above, right after it calls QueryContextMenu :

 var mii = new MENUITEMINFO(); mii.cbSize = Marshal.SizeOf(mii); mii.fMask = MIIM.SUBMENU | MIIM.STRING | MIIM.FTYPE | MIIM.ID; mii.fType = MFT.BYPOSITION; mii.wID = 0; mii.hSubMenu = subMenu.Handle; mii.dwTypeData = "Test"; var success = InsertMenuItem(pMenu, 0, true, ref mii); 

but without "success." ( subMenu is System.Windows.Forms.ContextMenuStrip , which I created earlier.)

My questions:

  • Will I fix that what I'm trying is different from creating a shell extension?

  • Is this still a dangerous activity from managed code, according to this post ?

  • How is this actually done?

+4
source share
1 answer

OK, it seems that you can add custom menu items to the Windows Shell context menu, just in your application (there is no need to do anything that affects the whole Windows system). Below I did it. Keep in mind that this answer should be taken in the context of the above MSDN code. Here's the link again:

ShellContextMenu class on MSDN

In this class, in particular, the ShowContextMenu method is a call to QueryContextMenu , the purpose of which I learned to fill the menu with elements - in this case, the corresponding Windows shell menu items for the file / folder whose context menu will be displayed. After this call, I added the following code to add a submenu and separator:

 var mii = new MENUITEMINFO(); mii.fMask = MIIM.SUBMENU | MIIM.STRING | MIIM.FTYPE | MIIM.ID | MIIM.STATE | MIIM.BITMAP; mii.fState = MFS.ENABLED; mii.fType = MFT.STRING; mii.wID = 0; // Application-defined value that identifies the menu item. mii.hSubMenu = **subMenu**.Handle; mii.dwTypeData = Program.ShortTitle; mii.cch = mii.dwTypeData.Length; var bmp = new System.Drawing.Icon(ac.Properties.NeutralResources.MyAppIcon, 16, 16).ToBitmap(); this.hMyAppSubmenuIcon = bmp.GetHbitmap(); mii.hbmpItem = this.hMyAppSubmenuIcon; mii.cbSize = Marshal.SizeOf(typeof(MENUITEMINFO)); var success = InsertMenuItem(pMenu, 0, true, ref mii); mii = new MENUITEMINFO(); mii.fMask = MIIM.FTYPE; mii.fType = MFT.SEPARATOR; mii.cbSize = Marshal.SizeOf(mii); success = InsertMenuItem(pMenu, 1, true, ref mii); 

subMenu is of type System.Windows.Forms.ContextMenu . Thus, the entire context menu is a hybrid consisting of managed and unmanaged menu items. So far I have not seen a problem with this; it just means that handling the selection of two types of menu items should be done differently, as described below ...

After entering the managed items in the menu, the ShowContextMenu method calls TrackPopupMenu . For Shell menu items, an already-written class takes care of processing its selection. For my own menu items, I had to take additional steps, because TrackPopupMenu is a feature of the Windows API, so it doesnโ€™t work very well with elements of the " Click " controlled submenu. You can connect Click event handlers to your submenu items, but when they are selected from the Shell context menu, their Click event does not fire. I still plugged in their Click even because sometimes I just show my guided menu on my own.

To take action in response to the selected menu item in the Shell context menu, I used the return value TrackPopupMenu , which is the resource identifier of the selected menu item. What is where everything got a little cool. When creating a managed context menu, each menu item has an index. You can use this with the Windows API function GetMenuItemID , which returns the resource identifier of a menu item. I inherited from the managed class ContextMenu and encapsulated a Dictionary , which helped me map this resource identifier to a menu item that will be used later right after calling TrackPopupMenu . For my purposes, this is all I need to call the handler, because in my application I use the command template and I saved the command object in the property of the Tag menu item when creating the menu. (As soon as the dictionary gave me the correct menu item, I was able to execute the corresponding handler by extracting the command object from Tag ).

It has been working for several days now. If anyone sees holes as unmanaged resources that I had to clean up, please indicate.

+1
source

All Articles