using Microsoft.Win32; using System; using System.Collections.Generic; using System.Linq; using Vanara.Collections; namespace Vanara.Windows.Shell { /// A dictionary of Command Verbs defined in the Windows Registry. /// public class CommandVerbDictionary : RegistryBasedVirtualDictionary { private const string rootKeyName = "shell"; private readonly RegBasedSettings parent; internal CommandVerbDictionary(RegBasedSettings parent, bool readOnly) : base(parent.key.OpenSubKey(rootKeyName, !readOnly), readOnly) => this.parent = parent; /// Get the filtered list of keys under the base. public override IEnumerable Keys => baseKey?.GetSubKeyNames() ?? new string[0]; /// Gets or sets the order of the command verbs. /// The ordered list of command verbs. public IList Order { get { var order = baseKey.GetValue("", null)?.ToString(); var vals = Values.ToList(); if (order != null) { var orderedItems = order.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (var i = orderedItems.Length - 1; i >= 0; i--) { var match = vals.Find(c => string.Equals(c.Name, orderedItems[i], StringComparison.InvariantCultureIgnoreCase)); if (match == null) continue; vals.Remove(match); vals.Insert(0, match); } } return vals; } set { switch (value?.Count ?? 0) { case 0: baseKey.DeleteValue("", false); break; case 1: baseKey.SetValue("", value.First().Name); break; default: baseKey.SetValue("", string.Join(",", value.Select(c => c.Name).ToArray())); break; } } } /// Adds the specified command verb. /// The command verb name. /// /// The command verb display name. This is the string shown to the user when requesting a context menu for a shell item. /// /// The command to execute. /// A instance which has been added to the registry. public CommandVerb Add(string verb, string displayName = null, string command = null) { if (baseKey == null && !readOnly) baseKey = parent.key.CreateSubKey(rootKeyName); return ShellRegistrar.RegisterCommandVerb(parent.key, verb, displayName, command); } /// Determines if a specified key is in the filtered list of keys under the base. /// The name of the key to check. /// if the key is found; otherwise . public override bool ContainsKey(string verb) => baseKey?.HasSubKey(verb) ?? false; /// Removes the specified key from this dictionary and the registry. /// The name of the command verb to remove. /// A value indicating success () or failure (). public bool Remove(string verb) { try { baseKey.DeleteSubKeyTree(verb); return true; } catch { return false; } } /// Tries to get the with the name . /// The verb name. /// On success, the corresponding instance; on failure. /// A value indicating if was found. public override bool TryGetValue(string verb, out CommandVerb value) { value = null; if (!ContainsKey(verb)) return false; value = new CommandVerb(baseKey.OpenSubKey(verb, !readOnly), verb, readOnly); return true; } } /// A virtual dictionary that is based on values in the Windows Registry. /// Type used to capture multiple values within the registry. /// public abstract class RegistryBasedVirtualDictionary : VirtualReadOnlyDictionary { /// Read-only flag. protected readonly bool readOnly; /// The base registry key for this dictionary. protected RegistryKey baseKey; /// Initializes a new instance of the class. /// The base registry key. /// if set to render this dictionary read-only. protected RegistryBasedVirtualDictionary(RegistryKey baseKey, bool readOnly) { this.baseKey = baseKey; this.readOnly = readOnly; } /// Get the filtered list of keys under the base. public override IEnumerable Keys => baseKey?.GetSubKeyNames().Where(SubKeyFilter) ?? new string[0]; /// Determines if a specified key is in the filtered list of keys under the base. /// The name of the key to check. /// if the key is found; otherwise . public override bool ContainsKey(string key) => (baseKey?.HasSubKey(key) ?? false) && SubKeyFilter(key); /// /// Returns a value that indicates if the provided value should be included in the list of available keys. /// /// Name of the key. /// if is an included key; otherwise . protected virtual bool SubKeyFilter(string keyName) => true; } internal class ProgIdDictionary : RegistryBasedVirtualDictionary { private static readonly string[] badKeys = { "*", "AllFileSystemObjects", "AppID", "Applications", "AudioCD", "Briefcase", "CID", "CID.Local", "CLSID", "CompressedFolder", "ConflictFolder", "DVD", "DVDFile", "DesktopBackground", "DirectShow", "Directory", "Drive", "ExplorerCLSIDFlags", "Folder", "Interface", "LibraryFolder", "Local Settings", "MIME", "Media Servers", "Media Type", "MediaFoundation", "NetServer", "NetShare", "Network", "Printers", "Stack", "SystemFileAssociations", "TypeLib", "Unknown", "UserLibraryFolder", "VideoClipContainers", "VirtualStore" }; public ProgIdDictionary(bool readOnly) : base(Registry.ClassesRoot, readOnly) { } public override bool TryGetValue(string key, out ProgId value) { value = null; if (!ContainsKey(key)) return false; value = new ProgId(key, readOnly); return true; } protected override bool SubKeyFilter(string keyName) => !keyName.StartsWith(".") && !keyName.StartsWith("Kind.") && Array.BinarySearch(badKeys, keyName, StringComparer.OrdinalIgnoreCase) < 0; } internal class ShellAssociationDictionary : RegistryBasedVirtualDictionary { public ShellAssociationDictionary(bool readOnly) : base(Registry.ClassesRoot, readOnly) { } public override bool TryGetValue(string key, out ShellAssociation value) { value = null; if (!ContainsKey(key)) return false; value = ShellAssociation.FromFileExtension(key); return !(value is null); } protected override bool SubKeyFilter(string keyName) => keyName.StartsWith("."); } }