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