From 4d3c9b78c4354c1a2df05ea9ba793e8ca23a4639 Mon Sep 17 00:00:00 2001 From: Romuald Bierbasz Date: Wed, 25 Sep 2019 11:46:18 +0200 Subject: [PATCH] Add RegistryMonitor --- setup.py | 2 +- src/galaxy/registry_monitor.py | 98 ++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/galaxy/registry_monitor.py diff --git a/setup.py b/setup.py index fd7cebc..6eb2df4 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="galaxy.plugin.api", - version="0.50", + version="0.51", description="GOG Galaxy Integrations Python API", author='Galaxy team', author_email='galaxy@gog.com', diff --git a/src/galaxy/registry_monitor.py b/src/galaxy/registry_monitor.py new file mode 100644 index 0000000..02b1a5a --- /dev/null +++ b/src/galaxy/registry_monitor.py @@ -0,0 +1,98 @@ +import platform +if platform.system().lower() == "windows": + import logging + import ctypes + from ctypes.wintypes import LONG, HKEY, LPCWSTR, DWORD, BOOL, HANDLE, LPVOID + + LPSECURITY_ATTRIBUTES = LPVOID + + RegOpenKeyEx = ctypes.windll.advapi32.RegOpenKeyExW + RegOpenKeyEx.restype = LONG + RegOpenKeyEx.argtypes = [HKEY, LPCWSTR, DWORD, DWORD, ctypes.POINTER(HKEY)] + + RegCloseKey = ctypes.windll.advapi32.RegCloseKey + RegCloseKey.restype = LONG + RegCloseKey.argtypes = [HKEY] + + RegNotifyChangeKeyValue = ctypes.windll.advapi32.RegNotifyChangeKeyValue + RegNotifyChangeKeyValue.restype = LONG + RegNotifyChangeKeyValue.argtypes = [HKEY, BOOL, DWORD, HANDLE, BOOL] + + CloseHandle = ctypes.windll.kernel32.CloseHandle + CloseHandle.restype = BOOL + CloseHandle.argtypes = [HANDLE] + + CreateEvent = ctypes.windll.kernel32.CreateEventW + CreateEvent.restype = BOOL + CreateEvent.argtypes = [LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCWSTR] + + WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject + WaitForSingleObject.restype = DWORD + WaitForSingleObject.argtypes = [HANDLE, DWORD] + + ERROR_SUCCESS = 0x00000000 + + KEY_READ = 0x00020019 + KEY_QUERY_VALUE = 0x00000001 + + REG_NOTIFY_CHANGE_NAME = 0x00000001 + REG_NOTIFY_CHANGE_LAST_SET = 0x00000004 + + WAIT_OBJECT_0 = 0x00000000 + WAIT_TIMEOUT = 0x00000102 + +class RegistryMonitor: + + def __init__(self, root, subkey): + self._root = root + self._subkey = subkey + self._event = CreateEvent(None, False, False, None) + + self._key = None + self._open_key() + if self._key: + self._set_key_update_notification() + + def close(self): + CloseHandle(self._event) + if self._key: + RegCloseKey(self._key) + self._key = None + + def is_updated(self): + wait_result = WaitForSingleObject(self._event, 0) + + # previously watched + if wait_result == WAIT_OBJECT_0: + self._set_key_update_notification() + return True + + # no changes or no key before + if wait_result != WAIT_TIMEOUT: + # unexpected error + logging.warning("Unexpected WaitForSingleObject result %s", wait_result) + return False + + if self._key is None: + self._open_key() + + if self._key is None: + return False + + self._set_key_update_notification() + return True + + def _set_key_update_notification(self): + filter_ = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET + status = RegNotifyChangeKeyValue(self._key, True, filter_, self._event, True) + if status != ERROR_SUCCESS: + # key was deleted + RegCloseKey(self._key) + self._key = None + + def _open_key(self): + access = KEY_QUERY_VALUE | KEY_READ + self._key = HKEY() + rc = RegOpenKeyEx(self._root, self._subkey, 0, access, ctypes.byref(self._key)) + if rc != ERROR_SUCCESS: + self._key = None