vbAccelerator - Contents of code file: Touch\ClassAssociations.cs

using System;
using System.Collections;
using Microsoft.Win32;
using System.IO;

namespace vbAccelerator.Components.Shell
{
   /// <summary>
   /// Predefined Shell object classes
   /// </summary>
   public enum PredefinedClassKey : int
   {
      /// <summary>
      /// All files in the shell's namespace.  RegistryKey *
      /// </summary>
      AllFiles,
      /// <summary>
      /// All files and file directories.  RegistryKey AllFileSystemObjects
      /// </summary>
      AllFileSystemObjects,
      /// <summary>
      /// All folders, including shell extension folders. RegistryKey Folder
      /// </summary>
      Folder,
      /// <summary>
      /// All file system directories. RegistryKey Directory
      /// </summary>
      Directory,
      /// <summary>
      /// Entire Network (under My Network Places) RegistryKey Network
      /// </summary>
      Network,
      /// <summary>
      /// All network shares RegistryKey NetShare
      /// </summary>
      NetShare,
      /// <summary>
      /// All network servers RegistryKey NetServer
      /// </summary>
      NetServer,
      /// <summary>
      /// All printers
      /// </summary>
      Printers,
      /// <summary>
      /// Audio CD in CD drive RegistryKey AudioCD
      /// </summary>
      AudioCD,
      /// <summary>
      /// DVD drive (Registry key DVD under W2k or above, DVDFile under 98/ME)
      /// </summary>
      DVD
   }

   /// <summary>
   /// Specifies registry hives for which ClassAssociations can be set
   /// </summary>
   public enum PredefinedClassKeyHive : int
   {
      ClassesRoot,
      LocalMachine,
      CurrentUser
   }

   /// <summary>
   /// Summary description for ClassAssociations.
   /// </summary>
   public class ClassAssociations : CollectionBase
   {
      private PredefinedClassKey m_key = PredefinedClassKey.AllFiles;
      private PredefinedClassKeyHive m_baseKey =
       PredefinedClassKeyHive.LocalMachine;
      private Stack m_removeList = new Stack();

      /// <summary>
      /// Returns the Predefined Class Key that this object was constructed
      /// for
      /// </summary>
      public PredefinedClassKey Key
      {
         get
         {
            return this.m_key;
         }
      }

      /// <summary>
      /// Gets/sets the ClassAssociation at the specified index
      /// </summary>
      public ClassAssociation this[int index]
      {
         get
         {
            return (ClassAssociation)this.InnerList[index];
         }
         set
         {
            this.InnerList[index] = value;
         }
      }

      /// <summary>
      /// Adds a new ClassAssociation. Throws InvalidOperation
      /// if the item already exists
      /// </summary>
      /// <param name="ca">ClassAssociation to add</param>
      /// <exception cref="InvalidOperationException">If the item already
       exists</exception>
      public void Add(ClassAssociation ca)
      {
         foreach (ClassAssociation a in this.InnerList)
         {
            if (ca.CompareTo(a) == 0)
            {
               throw new InvalidOperationException(
                  String.Format("The verb {0} is already a member of this
                   collection",
                  ca.Verb)
                  );
            }
         }
         this.InnerList.Add(ca);
      }

      /// <summary>
      /// Returns the index of the class association with the specified verb, or
      /// -1 if it's not there
      /// </summary>
      /// <param name="verb">Verb to look for</param>
      /// <returns>Index of item with the specified verb, or -1 if it's not
       there</returns>
      public int IndexOf(string verb)
      {
         int index = -1;
         for (int i = 0; i < this.InnerList.Count; i++)
         {
            if (verb.Equals(((ClassAssociation)this.InnerList[i]).Verb))
            {
               index = i;
               break;
            }
         }
         return index;
      }

      /// <summary>
      /// Removes an existing ClassAssociation
      /// </summary>
      /// <param name="index">Index of association to remove</param>
      public void Remove(int index)
      {
         ClassAssociation ca = this[index];
         this.m_removeList.Push(ca);
         this.InnerList.Remove(index);         
      }

      /// <summary>
      /// Refreshes the object's data from the registry
      /// </summary>
      public void Refresh()
      {
         this.InnerList.Clear();

         RegistryKey rootKey = getRootKey();
         RegistryKey items = rootKey.OpenSubKey(SubKeyName);
         
         RegistryKey shell = items.OpenSubKey("shell");
         if (shell != null)
         {
            foreach (string verb in shell.GetSubKeyNames())
            {
               RegistryKey verbKey = shell.OpenSubKey(verb);
               string menuText = (string)verbKey.GetValue("", "");
               RegistryKey commandKey = verbKey.OpenSubKey("command");
               string command = "";
               if (commandKey != null)
               {
                  command = (string)commandKey.GetValue("", "");
               }
               ClassAssociation ca = new ClassAssociation(
                  this, verb, menuText, command);
               this.InnerList.Add(ca);
            }
         }
      }

      /// <summary>
      /// Saves the specified ClassAssociations to the registry
      /// </summary>
      /// <exception cref="InvalidOperationException">If creating any registry
       keys fails</exception>
      public void Save()
      {
         RegistryKey rootKey = getRootKey();
         RegistryKey items = rootKey.OpenSubKey(SubKeyName);
         RegistryKey shell = items.OpenSubKey("shell", true);
         if ((shell == null) && (this.InnerList.Count > 0))
         {
            // need to create the key
            shell = rootKey.CreateSubKey("shell");
            if (shell == null)
            {
               throw new InvalidOperationException("Unable to create shell
                key");
            }            
         }

         while (m_removeList.Count > 0)
         {
            ClassAssociation ca = (ClassAssociation)m_removeList.Pop();
            shell.DeleteSubKeyTree(ca.Verb);
         }

         foreach (ClassAssociation ca in this.InnerList)
         {
            if (ca.IsDirty)
            {
               RegistryKey verbKey = shell.CreateSubKey(ca.Verb);
               if (verbKey == null)
               {
                  throw new InvalidOperationException(
                     String.Format("Unable to create verb key {0}", ca.Verb));
               }
               if (ca.MenuText.Trim().Length > 0)
               {
                  verbKey.SetValue("", ca.MenuText);
               }
               RegistryKey commandKey = verbKey.CreateSubKey("command");
               if (commandKey == null)
               {
                  throw new InvalidOperationException(
                     String.Format("Unable to create command key for {0}",
                      ca.Command));
               }
               commandKey.SetValue("", ca.Command);
               commandKey.Close();
               verbKey.Close();
            }
         }

         shell.Close();
      }

      /// <summary>
      /// Returns the registry key containing this ClassAssociation's
      /// data
      /// </summary>
      /// <returns>Registry Key containing this ClassAssociation's
       data</returns>
      public Microsoft.Win32.RegistryKey RegistryKey()
      {
         RegistryKey key = getRootKey();
         return key.OpenSubKey(SubKeyName);
      }

      private Microsoft.Win32.RegistryKey getRootKey()
      {
         RegistryKey rootKey = null;
         switch (m_baseKey)
         {
            case PredefinedClassKeyHive.LocalMachine:
               rootKey = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Classes");
               break;
            case PredefinedClassKeyHive.ClassesRoot:
               rootKey = Registry.ClassesRoot;
               break;
            case PredefinedClassKeyHive.CurrentUser:
               rootKey = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Classes");
               break;
         }
         return rootKey;
      }

      /// <summary>
      /// Returns the key name for the PredefinedClassKey that this
      /// class was constructed for
      /// </summary>
      public string SubKeyName
      {
         get
         {
            
            string subKey = "";
            switch (m_key)
            {
               case PredefinedClassKey.AllFiles:
                  subKey = "*";
                  break;
               case PredefinedClassKey.DVD:
                  if (System.Environment.OSVersion.Platform ==
                   PlatformID.Win32NT)
                  {
                     subKey = "DVD";
                  }
                  else
                  {
                     subKey = "DVDFile";
                  }
                  break;
               default:
                  subKey = Enum.GetName(m_key.GetType(), m_key);
                  break;               
            }
            return subKey;
         }
      }

      /// <summary>
      /// Constructs a new instance of the class on HKEY_LOCAL_MACHINE
      /// for the specified key
      /// </summary>
      /// <param name="key">The Predefined class to read or modify verbs
       in</param>
      public ClassAssociations(PredefinedClassKey key) :
       this(PredefinedClassKeyHive.LocalMachine, key)
      {
      }
      /// <summary>
      /// Constructs a new instance of the class on the specified
      /// registry hive for the specified key
      /// </summary>
      /// <param name="baseKey">Hive to use</param>
      /// <param name="key">The Predefined class to read or modify verbs
       in</param>
      public ClassAssociations(PredefinedClassKeyHive baseKey,
       PredefinedClassKey key)
      {
         m_baseKey = baseKey;
         m_key = key;
         Refresh();
      }

   }

   /// <summary>
   /// Returns details of a command association 
   /// </summary>
   public class ClassAssociation : IComparable
   {
      private string m_verb = "";
      private string m_menuText = "";
      private string m_command = "";
      private bool m_dirty = true;
      
      public virtual System.Int32 CompareTo ( System.Object obj )
      {
         return m_verb.CompareTo(((ClassAssociation)obj).Verb);
      }
      public virtual System.Int32 CompareTo (ClassAssociation ca)
      {
         return m_verb.CompareTo(ca.Verb);
      }

      /// <summary>
      /// Gets/sets the verb (the keyname in the registry) for this command.
      /// </summary>
      public string Verb
      {
         get
         {
            return this.m_verb;
         }
         set
         {
            this.m_verb = value;
            this.m_dirty = true;
         }
      }

      /// <summary>
      /// Gets/sets the menu text that will be displayed in the context menu
      /// for this command
      /// </summary>
      public string MenuText
      {
         get
         {
            return this.m_menuText;         
         }
         set
         {
            this.m_menuText = value;
            this.m_dirty = true;
         }
      }

      /// <summary>
      /// Gets/sets the command to execute
      /// </summary>
      public string Command
      {
         get
         {
            return this.m_command;
         }
         set
         {
            this.m_command = value;
            this.m_dirty = true;
         }
      }

      /// <summary>
      /// Gets/sets whether this item needs to be saved or not
      /// </summary>
      public bool IsDirty
      {
         get
         {
            return this.m_dirty;
         }
      }

      /// <summary>
      /// Creates a new class association
      /// </summary>
      /// <param name="verb">The verb (keyname in the registry) for this
       command.</param>
      /// <param name="menuText">The context menu text to display</param>
      /// <param name="command">The command to execute</param>
      public ClassAssociation(string verb, string menuText, string command)
      {
         this.m_verb = verb;
         this.m_menuText = menuText;
         this.m_command = command;
      }

      /// <summary>
      /// Creates a existing class association associated with the 
      /// ClassAssociations Refresh method. Internal method.
      /// </summary>
      /// <param name="verb">The verb (keyname in the registry) for this
       command.</param>
      /// <param name="menuText">The context menu text to display</param>
      /// <param name="command">The command to execute</param>
      internal ClassAssociation(ClassAssociations owner, string verb, string
       menuText, string command)
      {
         this.m_dirty = false;
         this.m_verb = verb;
         this.m_menuText = menuText;
         this.m_command = command;
      }


   }
}