Return to Snippet

Revision: 10087
at December 8, 2008 10:36 by jimfred


Updated Code
/// <summary>
/// Given a registry key, get a list of child sub-keys.
/// This function recursively calls itself. 
/// Intended to be used in an implementation of recursive enumeration in 
/// either a foreach loop or a LINQ expression.
/// If access to a key is not allowed, such subkeys are not included in the list and 
/// a Debug.WriteLine prints the key name.
/// <example>
/// string searchString = "dll".ToLower(); // Example search for mention of dll. 'ToLower' is used for non-case-sensisitve search.
/// Microsoft.Win32.RegistryKey keyStart = rkLm.OpenSubKey(@"SOFTWARE\Adobe\"); 
///
/// // LINQ expression to retrieve a list of strings based on the 'where' condition.
/// IEnumerable<string> regVals2 =
///    // These two 'from' clauses allow nested enumeration of keys and their values.
///    from key in GetSubKeys(keyStart)
///    from valueName in key.GetValueNames()
///    // create a string 'value' for convenient access to value.
///    let value = key.GetValue(valueName).ToString()
///    where
///        // this example where clause searches for searchString.
///        // and of course could be enhanced to narrow search results.
///        // 'ToLower' is used for non-case-sensisitve search.
///        value.ToLower().Contains(searchString) ||
///        valueName.ToLower().Contains(searchString) ||
///        key.Name.ToLower().Contains(searchString)
///    // format a string containing the key name, value name and value.
///    // Hint: call a member function here to allow setting of break points.
///    select string.Format("{0}: {1}={2}", key.Name, valueName.ToString(), value);
/// </example>
/// </summary>
/// <param name="keyParentArg">A registry key</param>
/// <returns>An IEnumerable List of subkeys under the keyParentArg.</returns>
static IEnumerable<Microsoft.Win32.RegistryKey> GetSubKeys(Microsoft.Win32.RegistryKey keyParentArg)
{
    // This link... http://www.csharphelp.com/archives2/archive430.html 
    //   ...has a GetSubKeys implementation without try/catch.
    //   Omitting try/catch will cause LINQ expressions to abort prematurely. 
    // This link... http://support.microsoft.com/kb/267908 - 
    //   ...has an example that enumerates using advapi32.dll without .NET or LINQ.
    // This link... http://blog.domaindotnet.com/2008/09/08/the_fastest_dot_net_hash_set_collection_with_linq_extended_features/ 
    //   ...has an alternative implementation (using GetAllSubkeys and TryOpenSubKey) that 
    //   I thought was more complex than necessary for simple registry enumeration. This
    //   GetSubKeys function provides similar functionality with one function.
    
    // This list will be built as subkeys are added.
    List<Microsoft.Win32.RegistryKey> keysFound = new List<Microsoft.Win32.RegistryKey>();

    try
    {
        if (keyParentArg.SubKeyCount > 0)
        {
            foreach (string strKeyChild in keyParentArg.GetSubKeyNames())
            {
                try
                {
                    Microsoft.Win32.RegistryKey keyChild = keyParentArg.OpenSubKey(strKeyChild);
                    if (keyChild != null)
                    {
                        keysFound.Add(keyChild);

                        // Recursive call back into this method
                        IEnumerable<Microsoft.Win32.RegistryKey> keyGrandChildren = GetSubKeys(keyChild);

                        if (keyGrandChildren != null)
                        {
                            keysFound.AddRange(keyGrandChildren);
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(false);
                        }
                    } // if not null.
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + " failed trying " + strKeyChild + " in " + keyParentArg);
                }
            } // foreach
        } // if
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + " failed trying " + keyParentArg);
    }
    
    return keysFound;
} // GetSubKeys()

Revision: 10086
at December 7, 2008 16:59 by jimfred


Initial Code
/// <summary>
/// Given a registry key, get a list of child sub-keys.
/// This function recursively calls itself. 
/// Intended to be used in an implementation of recursive enumeration in 
/// either a foreach loop or a LINQ expression.
/// If access to a key is not allowed, such subkeys are not included in the list and 
/// a Debug.WriteLine prints the key name.
/// <example>
/// string searchString = "dll".ToLower(); // Example search for mention of dll.
/// Microsoft.Win32.RegistryKey keyStart = rkLm.OpenSubKey(@"SOFTWARE\Adobe\"); 
///
/// // LINQ expression to retrieve a list of strings based on the 'where' condition.
/// IEnumerable<string> regVals2 =
///    // These two 'from' clauses allow nested enumeration of keys and their values.
///    from key in GetSubKeys(keyStart)
///    from valueName in key.GetValueNames()
///    // create a string 'value' for convenient access to value.
///    let value = key.GetValue(valueName).ToString()
///    where
///        // this example where clause searches for searchString.
///        // and of course could be enhanced to narrow search results.
///        // 'ToLower' is used for non-case-sensisitve search.
///        value.ToLower().Contains(searchString) ||
///        valueName.ToLower().Contains(searchString) ||
///        key.Name.ToLower().Contains(searchString)
///    // format a string containing the key name, value name and value.
///    // Hint: call a member function here to allow setting of break points.
///    select string.Format("{0}: {1}={2}", key.Name, valueName.ToString(), value);
/// </example>
/// </summary>
/// <param name="keyParentArg">A registry key</param>
/// <returns>An IEnumerable List of subkeys under the keyParentArg.</returns>
static IEnumerable<Microsoft.Win32.RegistryKey> GetSubKeys(Microsoft.Win32.RegistryKey keyParentArg)
{
    // This link... http://www.csharphelp.com/archives2/archive430.html 
    //   ...has a GetSubKeys implementation without try/catch.
    //   Omitting try/catch will cause LINQ expressions to abort prematurely. 
    // This link... http://support.microsoft.com/kb/267908 - 
    //   ...has an example that enumerates using advapi32.dll without .NET or LINQ.
    // This link... http://blog.domaindotnet.com/2008/09/08/the_fastest_dot_net_hash_set_collection_with_linq_extended_features/ 
    //   ...has an alternative implementation (using GetAllSubkeys and TryOpenSubKey) that 
    //   I thought was more complex than necessary for simple registry enumeration. This
    //   GetSubKeys function provides similar functionality with one function.
    
    // This list will be built as subkeys are added.
    List<Microsoft.Win32.RegistryKey> keysFound = new List<Microsoft.Win32.RegistryKey>();

    try
    {
        if (keyParentArg.SubKeyCount > 0)
        {
            foreach (string strKeyChild in keyParentArg.GetSubKeyNames())
            {
                try
                {
                    Microsoft.Win32.RegistryKey keyChild = keyParentArg.OpenSubKey(strKeyChild);
                    if (keyChild != null)
                    {
                        keysFound.Add(keyChild);

                        // Recursive call back into this method
                        IEnumerable<Microsoft.Win32.RegistryKey> keyGrandChildren = GetSubKeys(keyChild);

                        if (keyGrandChildren != null)
                        {
                            keysFound.AddRange(keyGrandChildren);
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(false);
                        }
                    } // if not null.
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + " failed trying " + strKeyChild + " in " + keyParentArg);
                }
            } // foreach
        } // if
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message + Environment.NewLine + " failed trying " + keyParentArg);
    }
    
    return keysFound;
} // GetSubKeys()

Initial URL
See URLs in comments in function

Initial Description
This static function allows LINQ or foreach access to registry keys to search for keys, value names and/or values. See example usage in <example>. This was created to find occurrences of driver references ( MyDriver.sys and corresponding OEMnnn.INF) in the registry.

LINQ access to the registry provides for fancy conditions in where-clauses.
Try/catch blocks are used to handle (ignore) access exceptions.

Initial Title
GetSubKeys - static function provides recursive access to registry keys with LINQ queries or foreach loops

Initial Tags


Initial Language
C#