[Tutor] walk registry using _winreg

eryksun eryksun at gmail.com
Thu May 30 22:05:23 CEST 2013


On Thu, May 30, 2013 at 10:47 AM, Albert-Jan Roskam <fomcl at yahoo.com> wrote:
>
> def walkRegistry(regkey, keyToSet="file_locations",
>                  valueToSet="temp_dir",
>                  HKEY=_winreg.HKEY_CURRENT_USER, verbose=False):

I suppose you don't need the "sam" option in your case, but in general
it's needed for 64-bit Windows in order to handle both native and
WOW64 keys.

For a WOW64 process, the native 64-bit keys can be read with
sam=KEY_READ | KEY_WOW64_64KEY. For a 64-bit process, the WOW64 keys
can be read with sam=KEY_READ | KEY_WOW64_32KEY.

A WOW64 process will have "PROCESSOR_ARCHITEW6432" defined in os.environ.


>     aReg = _winreg.OpenKey(HKEY, regkey)

You should use a "with" statement here instead of depending on the
garbage collection of the generator frame.

>     try:
>         while True:
>             key = _winreg.EnumKey(aReg, i)
>             i += 1
>             if key:
>                 new_regkey = os.path.join(regkey, key)

There's too much code here under the banner of one "try" suite.
OpenKey and QueryValueEx in the subsequent statements may raise a
WindowsError for various reasons.

Also, as you're currently doing things it leaves several open handles
as you recursively create generators. It's likely not an issue (the
registry isn't deeply nested), but in general I prefer to close a
resource as immediately as is possible.

I'd enumerate the subkeys in a list and only yield a key/value match
for the current regkey (that's basically how os.walk traverses the
file system). This can match on the initial key. If you don't want
that, it can be worked around (e.g. a flag, or a helper function), but
I don't think the additional complexity is worth it.

    import os
    import _winreg

    def walkRegistry(regkey,
                     keyToSet="file_locations",
                     valueToSet="temp_dir",
                     HKEY=_winreg.HKEY_CURRENT_USER,
                     sam=_winreg.KEY_READ,
                     onerror=None,
                     verbose=False):

        try:
            aReg = _winreg.OpenKey(HKEY, regkey)
        except WindowsError as e:
            if onerror is not None:
                onerror(e)
            return

        i = 0
        subkeys = []
        with aReg:
            while True:
                try:
                    subkeys.append(_winreg.EnumKey(aReg, i))
                except WindowsError:
                    break
                i += 1
            # check the key name; not the key path
            if os.path.basename(regkey) == keyToSet:
                if verbose:
                    print "---> FOUND KEY:", regkey
                try:
                    data = _winreg.QueryValueEx(aReg, valueToSet)[0]
                except WindowsError:  # value not found
                    pass
                else:
                    if verbose:
                        print "---> FOUND KEY,VALUE PAIR"
                    yield regkey, valueToSet, data

        for key in subkeys:
            new_regkey = os.path.join(regkey, key)
            for item in walkRegistry(
                    new_regkey, keyToSet, valueToSet,
                    HKEY, sam, onerror, verbose):
                yield item


Minimally tested (sorry):

    >>> HKEY = _winreg.HKEY_LOCAL_MACHINE
    >>> regkey = r'Software\Python\PythonCore\2.7'

    >>> res = list(
    ... walkRegistry(regkey, 'PythonPath', '', HKEY, verbose=True))

    ---> FOUND KEY: Software\Python\PythonCore\2.7\PythonPath
    ---> FOUND KEY,VALUE PAIR

    >>> res[0][2]
    u'C:\\Python27\\Lib;C:\\Python27\\DLLs;C:\\Python27\\Lib\\lib-tk'


More information about the Tutor mailing list