using Microsoft.Win32; using System.ComponentModel; using Vanara.PInvoke; namespace Vanara.Windows.Shell; /// A value that determines if a user can select a single item, multiple items, or a selection from an item. [Flags] public enum VerbMultiSelectModel { /// /// Inferred from the type of verb implementation you have chosen. For COM-based methods (such as DropTarget and ExecuteCommand) /// Player is assumed, and for the other methods Document is assumed. /// Unset = 0, /// Support any number of items. Player = 1, /// Support only a single selection. Single = 2, /// /// Create a top level window for each item. Doing so limits the number of items activated and helps avoid running out of system /// resources if the user opens too many windows. /// Document = 4 } /// Determines the placement of a verb in a menu. public enum VerbPosition { /// The menu position is undefined. Undefined, /// The menu should be displayed at the top. Top, /// The menu should be displayed at the bottom. Bottom } /// Determines menu location. public enum VerbSelectionModel { /// Specifies an item verb. Item, /// Specifies a verb on the background shortcut menu. BackgroundShortcutMenu } /// Encapsulates a shortcut menu verb in the registry. public class CommandVerb : RegBasedSettings, IEquatable { internal CommandVerb(RegistryKey key, string name, bool readOnly = true) : base(key, readOnly) => Name = name; /// Gets or sets an Advanced Query Syntax (AQS) expression that determines whether the verb is displayed or hidden. /// The AQS expression that controls visibility. public string? AppliesTo { get => key.GetValue("AppliesTo", null)?.ToString(); set => UpdateValue("AppliesTo", value); } /// /// Gets or sets the SFGAO value of the bit values of the mask to test to determine whether the verb should be enabled or disabled. /// /// The attribute mask. [DefaultValue((Shell32.SFGAO)0)] public Shell32.SFGAO AttributeMask { get => (Shell32.SFGAO)(int)key.GetValue("AttributeMask", 0)!; set => UpdateValue("AttributeMask", (int)value, RegistryValueKind.DWord); } /// Gets or sets the SFGAO value of the bits that are tested to determine whether the verb should be enabled or disabled. /// The attribute value. [DefaultValue((Shell32.SFGAO)0)] public Shell32.SFGAO AttributeValue { get => (Shell32.SFGAO)(int)key.GetValue("AttributeValue", 0)!; set => UpdateValue("AttributeValue", (int)value, RegistryValueKind.DWord); } /// Gets or sets the command string used to launch the command in a console window or batch (.bat) file. /// The command string. /// /// If any element of the command string contains or might contain spaces, it must be enclosed in quotation marks. Otherwise, if the /// element contains a space, it will not parse correctly. For instance, "My Program.exe" starts the application properly. If you /// use My Program.exe without quotation marks, then the system attempts to launch My with Program.exe as its first command line /// argument. You should always use quotation marks with arguments such as "%1" that are expanded to strings by the Shell, because /// you cannot be certain that the string will not contain a space. /// [DefaultValue(null)] public string? Command { get => key.GetSubKeyDefaultValue("command")?.ToString(); set => UpdateKeyValue("command", value); } /// Gets or sets the optional CLSID of an object that implments IExplorerCommandState. /// The command state handler. [DefaultValue(null)] public Guid? CommandStateHandler { get => key.GetGuidValue("CommandStateHandler"); set => UpdateValue("CommandStateHandler", value); } /// Gets or sets an Advanced Query Syntax (AQS) expression that controls which verb is the default. /// The AQS expression that controls which verb is the default. [DefaultValue(null)] public string? DefaultAppliesTo { get => key.GetValue("DefaultAppliesTo", null)?.ToString(); set => UpdateValue("DefaultAppliesTo", value); } /// /// Gets or sets the optional CLSID value of the inproc extension that handles an excution within Windows Explorer or IE. For /// Windows Explorer, this value should be also assigned to the value and exclusively /// associated with a value of "%SYSTEMROOT%\Explorer.exe". For IE, this value should be exclusively /// associated with a value of "C:\Program Files\Internet Explorer\iexplore.exe" %1. /// /// The explorer command handler CLSID. [DefaultValue(null)] public Guid? DelegateExecute { get { using var sk = key.OpenSubKey("command"); return sk?.GetGuidValue("DelegateExecute"); } set { EnsureWritable(); if (!value.HasValue) { try { key.DeleteSubKeyTree("command"); } catch { } } else { using var sk = key.CreateSubKey("command"); sk?.SetValue("DelegateExecute", value.Value.ToRegString()); } } } /// /// Gets or sets an optional display name associated with them, which is displayed on the shortcut menu instead of the verb string /// itself. For example, the display string for openas is Open With. Like normal menu strings, including an ampersand /// character in the display string allows keyboard selection of the command. /// /// The display name for the verb. [DefaultValue(null)] public string? DisplayName { get => key.GetValue("", null)?.ToString(); set => UpdateValue("", value); } /// Gets or sets the optional CLSID of the object that implements IDropTarget. /// The drop target handler's CLSID. [DefaultValue(null)] public Guid? DropTarget { get { using var sk = key.OpenSubKey("DropTarget"); return sk?.GetGuidValue("CLSID"); } set { EnsureWritable(); if (!value.HasValue) { try { key.DeleteSubKeyTree("DropTarget"); } catch { } } else { using var sk = key.CreateSubKey("DropTarget"); sk?.SetValue("CLSID", value.Value.ToRegString()); } } } /// /// Gets or sets the optional CLSID value of the inproc explorer extension that handles this verb's execution. This value should be /// also assigned to the value and is generally associated with a value of "%SYSTEMROOT%\Explorer.exe". /// /// The explorer command handler CLSID. [DefaultValue(null)] public Guid? ExplorerCommandHandler { get => key.GetGuidValue("ExplorerCommandHandler"); set => UpdateValue("ExplorerCommandHandler", value); } /// /// Gets or sets a value that marks the command as extended and will be displayed only when the user right-clicks an object while /// also pressing the SHIFT key. /// /// /// if command is only displayed only when the user right-clicks an object while also pressing the SHIFT key; /// otherwise, . /// [DefaultValue(false)] public bool Extended { get => key.HasValue("Extended"); set => ToggleValue("Extended", value); } /// /// Gets or sets an Advanced Query Syntax (AQS) expression that controls whether a User Account Control (UAC) shield is displayed. /// /// The AQS expression that controls whether a User Account Control (UAC) shield is displayed. [DefaultValue(null)] public string? HasLUAShield { get => key.GetValue("HasLUAShield", null)?.ToString(); set => UpdateValue("HasLUAShield", value); } /// Gets or sets a value that determines on which menu the command is displayed. /// The implied selection model. [DefaultValue((VerbSelectionModel)0)] public VerbSelectionModel ImpliedSelectionModel { get => (VerbSelectionModel)(int)key.GetValue("ImpliedSelectionModel", 0)!; set => UpdateValue("ImpliedSelectionModel", (int)value, RegistryValueKind.DWord); } /// /// Gets or sets a value that tells the system that the verb is not an actual verb, but exists solely for the purpose of backward compatibility. /// /// if disabled; otherwise, . [DefaultValue(false)] public bool LegacyDisable { get => key.HasValue("LegacyDisable"); set => ToggleValue("LegacyDisable", value); } /// Gets or sets a localizable value that is displayed as a menu's text. /// The menu's text. [DefaultValue(null)] public IndirectString? MUIVerb { get => IndirectString.TryParse(key.GetValue("MUIVerb")?.ToString(), out var loc) ? loc : null; set => UpdateValue("MUIVerb", value?.ToString()); } /// /// Gets or sets a value that determines if a user can select a single item, multiple items, or a selection from an item. /// /// The multi select model for the menu. [DefaultValue((VerbMultiSelectModel)0)] public VerbMultiSelectModel MultiSelectModel { get { string value = key.GetValue("MultiSelectModel", VerbMultiSelectModel.Unset.ToString())!.ToString()!.Replace('|', ',').Replace(" ", ""); return (VerbMultiSelectModel)Enum.Parse(typeof(VerbMultiSelectModel), value, true); } set => UpdateValue("MultiSelectModel", value.ToString().Replace(", ", " | "), RegistryValueKind.String, VerbMultiSelectModel.Unset.ToString()); } /// Gets the text string that is used by the Shell to identify the associated command. /// The verb name. public string Name { get; } /// /// Gets or sets a value that tells the system that this verb can never be displayed as the default verb for this file type. /// /// if menu can never be set as default; otherwise, . [DefaultValue(false)] public bool NeverDefault { get => key.HasValue("NeverDefault"); set => ToggleValue("NeverDefault", value); } /// Gets or sets a value that tells the system that this verb can only be displayed when in an Explorer window. /// if menu is only to be displayed when in an Explorer window; otherwise, . [DefaultValue(false)] public bool OnlyInBrowserWindow { get => key.HasValue("OnlyInBrowserWindow"); set => ToggleValue("OnlyInBrowserWindow", value); } /// /// Gets or sets a value that is used to place a verb at the top or bottom of the menu. If there are multiple verbs that specify /// this attribute then the last one to do so gets priority /// /// The verb menu placement. [DefaultValue((VerbPosition)0)] public VerbPosition Position { get => (VerbPosition)Enum.Parse(typeof(VerbPosition), key.GetValue("Position", VerbPosition.Undefined.ToString())!.ToString()!); set => UpdateValue("Position", value.ToString(), RegistryValueKind.String, VerbPosition.Undefined.ToString()); } /// Gets or sets a value that tells the system that this verb is available for programmatic access only and not displayed. /// if verb is available for programmatic access only and not displayed; otherwise, . [DefaultValue(false)] public bool ProgrammaticAccessOnly { get => key.HasValue("ProgrammaticAccessOnly"); set => ToggleValue("ProgrammaticAccessOnly", value); } /// Gets or sets a value that tells the system to place a separator after this menu item. /// if a separator should be displayed after this menu item; otherwise, . [DefaultValue(false)] public bool SeparatorAfter { get => 1 == key.GetValue("SeparatorAfter", 0) as int?; set => UpdateValue("SeparatorAfter", value ? 1 : 0, RegistryValueKind.DWord); } /// Gets or sets a value that tells the system to place a separator before this menu item. /// if a separator should be displayed before this menu item; otherwise, . [DefaultValue(false)] public bool SeparatorBefore { get => 1 == key.GetValue("SeparatorBefore", 0) as int?; set => UpdateValue("SeparatorBefore", value ? 1 : 0, RegistryValueKind.DWord); } /// Gets or sets a value that controls if verb visibility can be suppressed through policy settings. /// A value. [DefaultValue((Shell32.RESTRICTIONS)0)] public Shell32.RESTRICTIONS SuppressionPolicy { get => (Shell32.RESTRICTIONS)(int)key.GetValue("SuppressionPolicy", 0)!; set => UpdateValue("SuppressionPolicy", (int)value, RegistryValueKind.DWord); } /// Gets or sets an optional CLSID for a handler that controls if verb visibility can be suppressed through policy settings. /// The handler's CLSID value. [DefaultValue(null)] public Guid? SuppressionPolicyEx { get => key.GetGuidValue("SuppressionPolicyEx"); set => UpdateValue("SuppressionPolicyEx", value); } /// Determines if another is equal to this instance. /// The other . /// if the items are equal; otherwise . public bool Equals(CommandVerb? other) => Equals((RegBasedSettings?)other); }