From ef50eca37c04ea1466f69cc32237834b1938d7ba Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Tue, 17 Feb 2015 22:32:12 +0530 Subject: [PATCH] Add functions to enumerate keys and delete values --- src/calibre/utils/winreg/lib.py | 39 ++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/src/calibre/utils/winreg/lib.py b/src/calibre/utils/winreg/lib.py index c512734abc..6b2378d3fd 100644 --- a/src/calibre/utils/winreg/lib.py +++ b/src/calibre/utils/winreg/lib.py @@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import, __license__ = 'GPL v3' __copyright__ = '2015, Kovid Goyal ' -import ctypes, ctypes.wintypes as types, _winreg as winreg, struct +import ctypes, ctypes.wintypes as types, _winreg as winreg, struct, datetime import winerror, win32con # Binding to C library {{{ @@ -131,6 +131,20 @@ RegSetKeyValue = cwrap( RegDeleteTree = cwrap( 'RegDeleteTreeW', LONG, a('key', HKEY), a('sub_key', LPCWSTR, None)) +RegDeleteKeyValue = cwrap( + 'RegDeleteKeyValueW', LONG, a('key', HKEY), a('sub_key', LPCWSTR, None), a('name', LPCWSTR, None)) +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 filetime_to_datettime(ft): + timestamp = ft.dwHighDateTime + timestamp <<= 32 + timestamp |= ft.dwLowDateTime + return datetime.datetime(1601, 1, 1, 0, 0, 0) + datetime.timedelta(microseconds=timestamp/10) + # }}} class Key(object): @@ -145,6 +159,27 @@ class Key(object): else: self.hkey = HKEY() + 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) + lname_buf = DWORD(len(name_buf)) + i = 0 + while True: + lname_buf.value = len(name_buf) + try: + file_time = RegEnumKeyEx(self.hkey, i, name_buf, ctypes.byref(lname_buf)) + except ValueError: + raise RuntimeError('Enumerating keys failed with buffer too small, which should never happen') + if get_last_write_times: + yield name_buf.value[:lname_buf.value], filetime_to_datettime(file_time) + else: + yield name_buf.value[:lname_buf.value] + i += 1 + + def delete_value(self, sub_key=None, name=None): + ' Delete the named value from this key. If name is None the default value is deleted. ' + RegDeleteKeyValue(self.hkey, sub_key, name) + def delete_tree(self, sub_key=None): ''' Delete this key and all its children. Note that a key is not actually deleted till the last handle to it is closed. ''' @@ -237,4 +272,6 @@ if __name__ == '__main__': k.set_default_value(r'other\key', '%PATH%', has_expansions=True) pprint(tuple(k.itervalues(get_data=True))) k.set_default_value(r'delete\me\please', 'xxx') + pprint(tuple(k.iterkeynames(get_last_write_times=True))) k.delete_tree('delete') + pprint(tuple(k.iterkeynames(get_last_write_times=True)))