Add API to conveniently get a value by name from a registry key

This commit is contained in:
Kovid Goyal 2015-03-05 13:26:57 +05:30
parent 7b8eff6efd
commit 3b9479763b

View File

@ -28,6 +28,9 @@ HKEY_CLASSES_ROOT = HKCR = HKEY(ULONG(winreg.HKEY_CLASSES_ROOT).value)
HKEY_LOCAL_MACHINE = HKLM = HKEY(ULONG(winreg.HKEY_LOCAL_MACHINE).value)
KEY_READ = winreg.KEY_READ
KEY_ALL_ACCESS = winreg.KEY_ALL_ACCESS
RRF_RT_ANY = 0x0000ffff
RRF_NOEXPAND = 0x10000000
RRF_ZEROONFAILURE = 0x20000000
class FILETIME(ctypes.Structure):
_fields_ = [("dwLowDateTime", DWORD), ("dwHighDateTime", DWORD)]
@ -147,6 +150,18 @@ RegEnumKeyEx = cwrap(
'RegEnumKeyExW', LONG, a('key', HKEY), a('index', DWORD), a('name', LPWSTR), a('name_size', LPDWORD), a('reserved', LPDWORD, None),
a('cls', LPWSTR, None), a('cls_size', LPDWORD, None), a('last_write_time', ctypes.POINTER(FILETIME), in_arg=False),
errcheck=enum_value_errcheck)
def get_value_errcheck(result, func, args):
if result == winerror.ERROR_SUCCESS:
return args
if result == winerror.ERROR_MORE_DATA:
raise ValueError('buffer too small')
if result == winerror.ERROR_FILE_NOT_FOUND:
raise KeyError('No such value found')
raise ctypes.WinError(result)
RegGetValue = cwrap(
'RegGetValueW', LONG, a('key', HKEY), a('sub_key', LPCWSTR, None), a('value_name', LPCWSTR, None), a('flags', DWORD, RRF_RT_ANY),
a('data_type', LPDWORD, 0), a('data', ctypes.c_void_p, 0), a('size', LPDWORD, 0), errcheck=get_value_errcheck
)
def filetime_to_datettime(ft):
@ -169,6 +184,22 @@ class Key(object):
else:
self.hkey = HKEY()
def get(self, value_name=None, default=None, sub_key=None):
data_buf = ctypes.create_string_buffer(1024)
len_data_buf = DWORD(len(data_buf))
data_type = DWORD(0)
while True:
len_data_buf.value = len(data_buf)
try:
RegGetValue(self.hkey, sub_key, value_name, RRF_RT_ANY | RRF_NOEXPAND | RRF_ZEROONFAILURE,
ctypes.byref(data_type), data_buf, len_data_buf)
break
except ValueError:
data_buf = ctypes.create_string_buffer(2 * len(data_buf))
except KeyError:
return default
return convert_registry_data(data_buf, len_data_buf.value, data_type.value)
def iterkeynames(self, get_last_write_times=False):
' Iterate over the names of all keys in this key '
name_buf = ctypes.create_unicode_buffer(1024)
@ -283,6 +314,7 @@ if __name__ == '__main__':
k.set('none test')
k.set_default_value(r'other\key', '%PATH%', has_expansions=True)
pprint(tuple(k.itervalues(get_data=True)))
pprint(k.get('unicode test'))
k.set_default_value(r'delete\me\please', 'xxx')
pprint(tuple(k.iterkeynames(get_last_write_times=True)))
k.delete_tree('delete')