   [.net] traversing the windows registry woes
  hi, im having some problems with my tree traversal code for my registry scanner.it will nest deeper without a problem, when he is at the deepest nestinglevel it will go trough each element at that level, checking at each element if it has subkeys.this works until i am at the last item of the deepest level, at wich point it should return to the previous nestinglevel and take the next item at that level (i'm trying to implement my own depth-first traversal system). But i get a nasty outofbounds error. i'll post the code:the key container is a linkedlistevery key i store as a key object, and a values list as shown belownamespace ToolBox{    /// <summary>    /// Encapsulates a registrykey, with all its included data    /// </summary>    ///    class KeyContents    { public RegistryKey Key { get; set; }   public string KeyName { get; set; }   public List<string> Values { get; set; }   public List<string> ValueTypes { get; set; }   public string[] ValueNames { get; set; } public KeyContents(RegistryKey key)   {  Values = new List<string>();  ValueTypes = new List<string>();  Key = key;  KeyName = key.Name;   }   public void StoreValues()   {  ValueNames = Key.GetValueNames();    for (int i = 0; i < ValueNames.Length; i++)  { Values.Add(Key.GetValue(ValueNames).ToString()); ValueTypes.Add(Key.GetValueKind(ValueNames).ToString());  }   }    }}then i got my traverse class, wich contains methods to go a depthlevel deeper (garechts()) , a next item method (GaBenede()), a method to go 1 level back (GaTerug()) and a method to get the parent's keys called GetParentSubkeys()HERE IS WHERE MY PROGRAM STOPS! at the "KeyContents subkeysParentKeyContents"line, with an indexoutofbounds exception :( namespace ToolBox{    class Traverse    {   public void GaRechts(Position last, KeyStore store, PositionManager posManager)   {  Position current = new Position(0, 0, 0);    current.NestingLevel = last.NestingLevel + 1;  current.ElementNumber = 1;  KeyContents input = store.GetKey();  current.AmountOfElements = input.Key.SubKeyCount;  posManager.Path.AddLast(current);  string[] subkeys = input.Key.GetSubKeyNames();  KeyContents output = new KeyContents(input.Key.OpenSubKey(subkeys[0]));  output.StoreValues();  store.AddKeyContents(output);  //DialogResult box =  MessageBox.Show(store.keystore.Last.Value.KeyName, "rechts");}   public void GaBeneden(Position last, KeyStore store, PositionManager posManager)   {  Position current = new Position(0, 0, 0);  current.AmountOfElements = posManager.Path.Last.Value.AmountOfElements;  current.ElementNumber = last.ElementNumber + 1;  current.NestingLevel = last.NestingLevel;  posManager.Path.AddLast(current);  //current <> last  KeyContents subkeysParentKeyContents = getParentSubKeys(current, store);  string[] subkeyNames = subkeysParentKeyContents.Key.GetSubKeyNames();KeyContents test = new KeyContents(subkeysParentKeyContents.Key.OpenSubKey(subkeyNames[current.ElementNumber])); test.StoreValues(); store.keystore.AddLast(test);    }   public void GaTerug(PositionManager posManager, Position current)   {  while (posManager.Path.Last.Value.NestingLevel == posManager.Path.Last.Previous.Value.NestingLevel)  { posManager.Path.RemoveLast();  }  posManager.Path.RemoveLast();  current = posManager.Path.Last.Value;}   public KeyContents getParentSubKeys(Position current, KeyStore store)   {  //test  int parentPosition = store.keystore.Count - current.ElementNumber ;KeyContents parentKeyContents = store.keystore.ElementAt(parentPosition); return parentKeyContents;   }    }}then, to keep track of where i am at anytime, i got a list of Position objects, representing the history of my traversal called the Positionmanager class.Here is  the Position Class codenamespace ToolBox{    /// <summary>    /// A logical position in the registry.    /// </summary>    class Position    {   /// <summary>   /// The number of levels deep you are in a registry root.   /// </summary>   public int NestingLevel { get;  set; }   /// <summary>   /// The currently selected RegistryKey to do operations on.   /// </summary>   public int ElementNumber { get;  set; }   /// <summary>   /// The amount of elements at the current level of the hive.   /// </summary>   public int AmountOfElements { get; set; }   /// <summary>   /// Initialises a new position object in the Registry.   /// </summary> public Position(int nestinglevel, int elementnumber, int amountofelements)   {  NestingLevel = nestinglevel;  ElementNumber = elementnumber;  AmountOfElements = amountofelements;   }    }}now, ill post my scanner code.namespace ToolBox{    class Scanner    {   PositionManager positionManager = new PositionManager();   Traverse traverser = new Traverse();   KeyStore keyStore = new KeyStore();   KeyContents keyContents;  public void RechtsBeneden()   {  while (keyStore.keystore.Last.Value.Key.SubKeyCount != 0)  { traverser.GaRechts(positionManager.Path.Last.Value, keyStore, positionManager);  }  while (positionManager.Path.Last.Value.ElementNumber != positionManager.Path.Last.Value.AmountOfElements)  { traverser.GaBeneden(positionManager.Path.Last.Value, keyStore, positionManager);   }  TerugBeneden();  }   public void TerugBeneden()   {  if (positionManager.Path.Last.Value.NestingLevel != 0)  { traverser.GaTerug(positionManager, positionManager.Path.Last.Value);  }  while (positionManager.Path.Last.Value.ElementNumber != positionManager.Path.Last.Value.AmountOfElements)  { traverser.GaBeneden(positionManager.Path.Last.Value, keyStore, positionManager); RechtsBeneden();  }   } public void Start()   {  List<string> HiveList = new List<string>();  HiveList.Add(RegistryHive.ClassesRoot.ToString());  HiveList.Add(RegistryHive.CurrentUser.ToString());  HiveList.Add(RegistryHive.LocalMachine.ToString());  HiveList.Add(RegistryHive.Users.ToString());  HiveList.Add(RegistryHive.CurrentConfig.ToString());  Position startPos = new Position(0, 1, 5);  positionManager.Path.AddFirst(startPos);  keyContents = new KeyContents(Registry.ClassesRoot);  keyContents.StoreValues();    keyStore.AddKeyContents(keyContents);  for (int i = 0; i < HiveList.Count; i++)  { RechtsBeneden();  }   }    }}Im trying to solve this for a few days, emberassingly enough, but im lost.Any help greatly appreciated.   
  I tried to follow your logic but I gave up at one point, because honestly I think you're doing this way too complicated. Instead of trying to sanitize your traversal I'd start over. Start with a simple traversal first - and make sure it works - and later add storing/processing/whatever.I see you got an understanding of recursion, i.e. the mutual recursion of RechtsBeneden() and TerugBeneden(). But a DFS(*) can even be solved with a single recursion. The point is: instead of keeping state of your navigation with PositionManager et.al. give your recursion functions parameters. Here's a bare DFS for the registry.public void DepthFirstWalker(RegistryKey key){    ProcessKey(key);    foreach (var name in key.GetSubKeyNames())    {   RegistryKey child = key.OpenSubKey(name);   DepthFirstWalker(child);   child.Close();    }}From there do with your RegistryKey whatever you want (ProcessKey function), i.e. storing the key's name (and/or the RegistryKey), the value names, types or even the values.Of course, this is for a bare scanning and will not (directly) keep track of parent/child relationship. If you intend to do so you will need a tree class of some sort:public class MyRegistryTreeNode{    public MyRegistryTreeNode(RegistryKey key)    {   Key = key;    }    public RegistryKey Key;    public List<MyRegistryTreeNode> Children = new List<MyRegistryTreeNode>();}Then, when traversing, create new tree nodes as you walk registry keys.public void DepthFirstWalker(MyRegistryTreeNode node){    foreach (var name in node.Key.GetSubKeyNames())    {   RegistryKey child = node.Key.OpenSubKey(name);   MyRegistryTreeNode childNode = new MyRegistryTreeNode(child);   node.Children.Add(childNode);   DepthFirstWalker(childNode);   child.Close();    }}Hope that helps(*) Actually it's not a search, in this case it's a simple traversal.   ;  thanks i will look the link up.yeah it made sense to me, somehow :)This is my own implementation without looking for a matching existing pattern thats more sane ;)