Skip to content

Commit 4d3c9b7

Browse files
committed
Add RegistryMonitor
1 parent 392e4c5 commit 4d3c9b7

File tree

2 files changed

+99
-1
lines changed

2 files changed

+99
-1
lines changed

Diff for: setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name="galaxy.plugin.api",
5-
version="0.50",
5+
version="0.51",
66
description="GOG Galaxy Integrations Python API",
77
author='Galaxy team',
88
author_email='[email protected]',

Diff for: src/galaxy/registry_monitor.py

+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import platform
2+
if platform.system().lower() == "windows":
3+
import logging
4+
import ctypes
5+
from ctypes.wintypes import LONG, HKEY, LPCWSTR, DWORD, BOOL, HANDLE, LPVOID
6+
7+
LPSECURITY_ATTRIBUTES = LPVOID
8+
9+
RegOpenKeyEx = ctypes.windll.advapi32.RegOpenKeyExW
10+
RegOpenKeyEx.restype = LONG
11+
RegOpenKeyEx.argtypes = [HKEY, LPCWSTR, DWORD, DWORD, ctypes.POINTER(HKEY)]
12+
13+
RegCloseKey = ctypes.windll.advapi32.RegCloseKey
14+
RegCloseKey.restype = LONG
15+
RegCloseKey.argtypes = [HKEY]
16+
17+
RegNotifyChangeKeyValue = ctypes.windll.advapi32.RegNotifyChangeKeyValue
18+
RegNotifyChangeKeyValue.restype = LONG
19+
RegNotifyChangeKeyValue.argtypes = [HKEY, BOOL, DWORD, HANDLE, BOOL]
20+
21+
CloseHandle = ctypes.windll.kernel32.CloseHandle
22+
CloseHandle.restype = BOOL
23+
CloseHandle.argtypes = [HANDLE]
24+
25+
CreateEvent = ctypes.windll.kernel32.CreateEventW
26+
CreateEvent.restype = BOOL
27+
CreateEvent.argtypes = [LPSECURITY_ATTRIBUTES, BOOL, BOOL, LPCWSTR]
28+
29+
WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
30+
WaitForSingleObject.restype = DWORD
31+
WaitForSingleObject.argtypes = [HANDLE, DWORD]
32+
33+
ERROR_SUCCESS = 0x00000000
34+
35+
KEY_READ = 0x00020019
36+
KEY_QUERY_VALUE = 0x00000001
37+
38+
REG_NOTIFY_CHANGE_NAME = 0x00000001
39+
REG_NOTIFY_CHANGE_LAST_SET = 0x00000004
40+
41+
WAIT_OBJECT_0 = 0x00000000
42+
WAIT_TIMEOUT = 0x00000102
43+
44+
class RegistryMonitor:
45+
46+
def __init__(self, root, subkey):
47+
self._root = root
48+
self._subkey = subkey
49+
self._event = CreateEvent(None, False, False, None)
50+
51+
self._key = None
52+
self._open_key()
53+
if self._key:
54+
self._set_key_update_notification()
55+
56+
def close(self):
57+
CloseHandle(self._event)
58+
if self._key:
59+
RegCloseKey(self._key)
60+
self._key = None
61+
62+
def is_updated(self):
63+
wait_result = WaitForSingleObject(self._event, 0)
64+
65+
# previously watched
66+
if wait_result == WAIT_OBJECT_0:
67+
self._set_key_update_notification()
68+
return True
69+
70+
# no changes or no key before
71+
if wait_result != WAIT_TIMEOUT:
72+
# unexpected error
73+
logging.warning("Unexpected WaitForSingleObject result %s", wait_result)
74+
return False
75+
76+
if self._key is None:
77+
self._open_key()
78+
79+
if self._key is None:
80+
return False
81+
82+
self._set_key_update_notification()
83+
return True
84+
85+
def _set_key_update_notification(self):
86+
filter_ = REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET
87+
status = RegNotifyChangeKeyValue(self._key, True, filter_, self._event, True)
88+
if status != ERROR_SUCCESS:
89+
# key was deleted
90+
RegCloseKey(self._key)
91+
self._key = None
92+
93+
def _open_key(self):
94+
access = KEY_QUERY_VALUE | KEY_READ
95+
self._key = HKEY()
96+
rc = RegOpenKeyEx(self._root, self._subkey, 0, access, ctypes.byref(self._key))
97+
if rc != ERROR_SUCCESS:
98+
self._key = None

0 commit comments

Comments
 (0)