You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/AutomatedTesting/Gem/PythonTests/automatedtesting_shared/windows_registry_setting.py

162 lines
6.3 KiB
Python

"""
Copyright (c) Contributors to the Open 3D Engine Project.
For complete copyright and license terms please see the LICENSE at the root of this distribution.
SPDX-License-Identifier: Apache-2.0 OR MIT
Class for querying and setting a windows registry setting.
"""
import pytest
import logging
from typing import List, Optional, Tuple, Any
from winreg import (
CreateKey,
OpenKey,
QueryValueEx,
DeleteValue,
SetValueEx,
KEY_ALL_ACCESS,
KEY_WRITE,
REG_SZ,
REG_MULTI_SZ,
REG_DWORD,
HKEY_CURRENT_USER,
)
from .platform_setting import PlatformSetting
logger = logging.getLogger(__name__)
class WindowsRegistrySetting(PlatformSetting):
def __init__(self, workspace: pytest.fixture, subkey: str, key: str, hive: Optional[str] = None) -> None:
super().__init__(workspace, subkey, key)
self._hive = None
try:
if hive is not None:
self._hive = self._str_to_hive(hive)
except ValueError:
logger.warning(f"Windows Registry Hive {hive} not recognized, using default: HKEY_CURRENT_USER")
finally:
if self._hive is None:
self._hive = HKEY_CURRENT_USER
def get_value(self, get_type: Optional[bool] = False) -> Any:
"""Retrieves the fast scan value in Windows registry (and optionally the type). If entry DNE, returns None."""
if self.entry_exists():
registryKey = OpenKey(self._hive, self._key)
value = QueryValueEx(registryKey, self._subkey)
registryKey.Close()
# Convert windows data type to universal data type flag: PlatformSettings.DATA_TYPE
# And handles unicode conversion for strings
value = self._convert_value(value)
return value if get_type else value[0]
else:
logger.warning(f"Could not retrieve Registry entry; key: {self._key}, subkey: {self._subkey}.")
return None
def set_value(self, value: Any) -> bool:
"""Sets the Windows registry value."""
value, win_type = self._format_data(value)
registryKey = None
result = False
try:
CreateKey(self._hive, self._subkey)
registryKey = OpenKey(self._hive, self._key, 0, KEY_WRITE)
SetValueEx(registryKey, self._subkey, 0, win_type, value)
result = True
except WindowsError as e:
logger.warning(f"Windows error caught while setting fast scan registry: {e}")
finally:
if registryKey is not None:
# Close key if it's been opened successfully
registryKey.Close()
return result
def delete_entry(self) -> bool:
"""Deletes the Windows registry entry for fast scan enabled"""
try:
if self.entry_exists():
registryKey = OpenKey(self._hive, self._key, 0, KEY_ALL_ACCESS)
DeleteValue(registryKey, self._subkey)
registryKey.Close()
return True
except WindowsError:
logger.error(f"Could not delete registry entry; key: {self._key}, subkey: {self._subkey}")
finally:
return False
def entry_exists(self) -> bool:
"""Checks for existence of the setting in Windows registry."""
try:
# Attempt to open and query key. If fails then the entry DNE
registryKey = OpenKey(self._hive, self._key)
QueryValueEx(registryKey, self._subkey)
registryKey.Close()
return True
except WindowsError:
return False
@staticmethod
def _format_data(value: bool or int or str or List[str]) -> Tuple[int or str or List[str], int]:
"""Formats the type of the value provided. Returns the formatted value and the windows registry type (int)."""
if type(value) == str:
return value, REG_SZ
elif type(value) == bool:
value = "true" if value else "false"
return value, REG_SZ
elif type(value) == int or type(value) == float:
if type(value) == float:
logger.warning(f"Windows registry does not support floats. Truncating {value} to integer")
value = int(value)
return value, REG_DWORD
elif type(value) == list:
for single_value in value:
if type(single_value) != str:
# fmt:off
raise ValueError(
f"Windows Registry lists only support strings, got a {type(single_value)} in the list")
# fmt:on
return value, REG_MULTI_SZ
else:
raise ValueError(f"Windows registry expected types: int, str and [str], found {type(value)}")
@staticmethod
def _convert_value(value_tuple: Tuple[Any, int]) -> Tuple[Any, PlatformSetting.DATA_TYPE]:
"""Converts the Windows registry data and type (tuple) to a (standardized) data and PlatformSetting.DATA_TYPE"""
value, windows_type = value_tuple
if windows_type == REG_SZ:
# Convert from unicode to string
return value, PlatformSetting.DATA_TYPE.STR
elif windows_type == REG_MULTI_SZ:
# Convert from unicode to string
return [string for string in value], PlatformSetting.DATA_TYPE.STR_LIST
elif windows_type == REG_DWORD:
return value, PlatformSetting.DATA_TYPE.INT
else:
raise ValueError(f"Type flag not recognized: {windows_type}")
@staticmethod
def _str_to_hive(hive_str: str) -> int:
"""Converts a string to a Windows Registry Hive enum (int)"""
from winreg import HKEY_CLASSES_ROOT, HKEY_CURRENT_CONFIG, HKEY_LOCAL_MACHINE, HKEY_USERS
lower = hive_str.lower()
if lower == "hkey_current_user" or lower == "current_user":
return HKEY_CURRENT_USER
elif lower == "hkey_classes_root" or lower == "classes_root":
return HKEY_CLASSES_ROOT
elif lower == "hkey_current_config" or lower == "current_config":
return HKEY_CURRENT_CONFIG
elif lower == "hkey_local_machine" or lower == "local_machine":
return HKEY_LOCAL_MACHINE
elif lower == "hkey_users" or lower == "users":
return HKEY_USERS
else:
raise ValueError(f"Hive: {hive_str} not recognized")