[Tutor] walk registry using _winreg

Dave Angel davea at davea.name
Wed May 29 14:11:18 CEST 2013


On 05/29/2013 04:11 AM, Albert-Jan Roskam wrote:
> Hello,
>
> I created a program to go through the windows registry and look for a certain key ("file_locations", though in the example I am using a key that every windows user has on his/her computer). If found, I want to replace the data associated with value "temp_dir" in that key. I have chosen this strategy because the exact registry keys may have changed from version to version. Also, multiple versions of the program may be installed on a given computer. I pasted the code below this mail, but also here: http://pastebin.com/TEkyekfi
>
> Is this the correct way to do this? I would actually prefer to specify only "valueNameToSearch" and not also "keyToSearch". As in: start walking through the registry starting at <regkey>, return every key where a temp_dir is defined.
>
> Thank you in advance!
>
>
> Regards,
> Albert-Jan
>
Please specify Python version.  I'll assume 2.7.  Obviously this is 
Windows, though it's also conceivable that it matters which version of 
Windows (XP, Win8, whatever).

First comment is that I'd be writing walkRegistry as a generator, using 
yield for the items found, rather than building a list.  It's generally 
easier to reuse that way, and won't get you in trouble if there are tons 
of matches.  See os.walk for an example.

A generator also would naturally eliminate the need to know KeyToSearch.

>
> import _winreg
> import os
>
> global __debug__
> __debug__ = True
>
> def walkRegistry(regkey, keyToSearch="file_locations",
>                   valueNameToSearch="temp_dir", verbose=False):
>      """Recursively search the Windows registry (HKEY_CURRENT_USER),
>      starting at top <regkey>. Return a list of three tuples that contain
>      the registry key, the value and the associated data"""
>      if verbose:
>          print regkey
>      aReg = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, regkey)
>      i, keys, founds = 0, [], []
>      try:
>          while True:
>              i += 1
>              key = _winreg.EnumKey(aReg, i)

I believe these are zero-based indexes, so you're skipping the first one.

>              keys.append(key)
>              if key == keyToSearch:

If this were a generator, you'd not be restricting the key here.  By 
restricting this key, you're limiting which subkeys you're going to 
search, and in the general case, I believe you're currently skipping 
values incorrectly.

>                  keyx = os.path.join(regkey, key)
>                  aReg = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, keyx)

Unsure here, but having another open here feels wrong.

>                  data, type_ = _winreg.QueryValueEx(aReg, valueNameToSearch)
>                  founds.append((keyx, valueNameToSearch, data))

Generally, recursion should happen here, rather than building a list and 
doing the recursion below.

>      except WindowsError:
>          for key in keys:
>              try:
>                  new_regkey = os.path.join(regkey, key)
>                  walkRegistry(new_regkey, keyToSearch,
>                               valueNameToSearch, verbose)

Nesting exceptions makes me nervous, and doing it recursively, makes me 
even more so.  If you move the recursion to the above area, then all the 
exception has to do is break out of the while loop.

>              except WindowsError:
>                  pass
>      return founds
>
> def setRegistry(regkey, keyToSet, valueToSet, replacementData, verbose=False):
>      """Search for <keyToSet> starting at top <regkey>. If <keyToSet> is found
>      exactly once, replace registry data associated with <valueToSet> with
>      <replacementData>."""
>      founds = walkRegistry(regkey, keyToSet, valueToSet, verbose)

If you changed walkRegistry as I suggest above, then this call becomes 
something like:
        for item in walkRegistry(regkey, keyToSet, valueToSet, verbose):


and inside the loop, you'll be testing the 'item' tuple for your 
criteria.  The test is done here, and NOT in the walkRegistry() function.

>      if not founds:
>          return
>      elif len(founds) == 1:
>          keyx, valueNameToSearch, data = founds[0]
>      else:
>          msg = "Registry value %r is found multiple times"
>          raise ValueError(msg % valueToSet)
>
>      if not __debug__:
>          try:
>              key = _winreg.OpenKey(_winreg.HKEY_CURRENT_USER, keyx,
>                                    0, _winreg.KEY_ALL_ACCESS)
>          except:
>              key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, regkey)
>          _winreg.SetValueEx(keyx, valueToSet, 0, _winreg.REG_SZ,
>                             replacementData)
>          _winreg.CloseKey(keyx)
>
> regkey = u"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer"
> print founds = walkRegistry(regkey, u"Shell Folders", u"Cookies", True)
> setRegistry(regkey, u"Shell Folders", u"Cookies", "this is the replacement value", False)
>
>


-- 
DaveA


More information about the Tutor mailing list