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(".");
}
}