public static extern bool InsertMenuItem( IntPtr hMenu, uint uItem, [MarshalAs(UnmanagedType.Bool)] bool fByPosition, ref MENUITEMINFO mii);
/// <summary> /// Add commands to a shortcut menu. /// </summary> /// <param name="hMenu">A handle to the shortcut menu.</param> /// <param name="iMenu">The zero-based position at which to insert the first new menu item.</param> /// <param name="idCmdFirst">The minimum value that the handler can specify for a menu item ID.</param> /// <param name="idCmdLast">The maximum value that the handler can specify for a menu item ID.</param> /// <param name="uFlags">Optional flags that specify how the shortcut menu can be changed.</param> /// <returns> /// If successful, returns an HRESULT value that has its severity value set /// to SEVERITY_SUCCESS and its code value set to the offset of the largest /// command identifier that was assigned, plus one. /// </returns> public int QueryContextMenu(IntPtr hMenu, uint iMenu, uint idCmdFirst, uint idCmdLast, uint uFlags) { // If uFlags include CMF_DEFAULTONLY then we should not do anything. if (((uint)CMF.CMF_DEFAULTONLY & uFlags) != 0) { return(NativeHelpers.MakeHResult(WinError.SEVERITY_SUCCESS, 0, 0)); } // Check if the user wants to see the extended context menu (i.e. pressing Shift while opening the context menu). this.isExtendedContextMenu = ((uint)CMF.CMF_EXTENDEDVERBS & uFlags) != 0; this.activeCommands.Clear(); var maxItems = (idCmdLast - idCmdFirst) + 1 - 2 /* Subtract 2 for the separators */; if (maxItems > 0) { var menuIndex = iMenu; // Add a separator. var beginSeparator = new MENUITEMINFO(); beginSeparator.cbSize = (uint)Marshal.SizeOf(beginSeparator); beginSeparator.fMask = MIIM.MIIM_TYPE; beginSeparator.fType = MFT.MFT_SEPARATOR; if (!NativeMethods.InsertMenuItem(hMenu, menuIndex++, true, ref beginSeparator)) { return(Marshal.GetHRForLastWin32Error()); } // Add the commands. var context = new CommandContext(this.selectedShellItems, this.isExtendedContextMenu); var commandOffset = default(uint); foreach (var command in CommandFactory.GetAvailableCommands()) { try { var commandState = command.GetState(context); if (commandState != null && commandState.IsVisible) { var verb = Guid.NewGuid().ToString(); // Create a unique verb to be able to retrieve the right command later on based on that verb. var activeCommand = new ActiveCommand(command, verb, commandOffset++); this.activeCommands.Add(activeCommand); var mii = new MENUITEMINFO(); mii.cbSize = (uint)Marshal.SizeOf(mii); mii.fMask = MIIM.MIIM_BITMAP | MIIM.MIIM_STRING | MIIM.MIIM_FTYPE | MIIM.MIIM_ID | MIIM.MIIM_STATE; mii.wID = idCmdFirst + activeCommand.Offset; mii.fType = MFT.MFT_STRING; mii.dwTypeData = commandState.MenuText; if (!commandState.IsEnabled) { mii.fState = MFS.MFS_DISABLED; } else if (commandState.IsChecked) { mii.fState = MFS.MFS_CHECKED; } else { mii.fState = MFS.MFS_ENABLED; } if (!NativeMethods.InsertMenuItem(hMenu, menuIndex++, true, ref mii)) { return(Marshal.GetHRForLastWin32Error()); } if (this.activeCommands.Count >= maxItems) { break; } } } catch (Exception exc) { Logger.LogError($"Error querying command \"{command.Name}\": {exc.ToString()}"); } } // Add a separator. var endSeparator = new MENUITEMINFO(); endSeparator.cbSize = (uint)Marshal.SizeOf(endSeparator); endSeparator.fMask = MIIM.MIIM_TYPE; endSeparator.fType = MFT.MFT_SEPARATOR; if (!NativeMethods.InsertMenuItem(hMenu, menuIndex++, true, ref endSeparator)) { return(Marshal.GetHRForLastWin32Error()); } } // Return an HRESULT value with the severity set to SEVERITY_SUCCESS. // Set the code value to the offset of the largest command identifier // that was assigned, plus one (1). return(NativeHelpers.MakeHResult(WinError.SEVERITY_SUCCESS, 0, (uint)this.activeCommands.Count)); }