can any one change this code in c#, from winreg import * from typing import Tuple, Optional, List
# Let's make sure the dictionnary goes from most recent to oldest KNOWN_VERSIONS = { '16.0': '2016/2019/O365', '15.0': '2013', '14.0': '2010', '12.0': '2007', '11.0': '2003', '10.0': '2002', '9.0': '2000', '8.0': '97', '7.0': '95', }
def get_value(hive: int, key: str, value: Optional[str], arch: int = 0) -> str: """ Returns a value from a given registry path
:param hive: registry hive (windows.registry.HKEY_LOCAL_MACHINE...) :param key: which registry key we're searching for :param value: which value we query, may be None if unnamed value is searched :param arch: which registry architecture we seek (0 = default, windows.registry.KEY_WOW64_64KEY, windows.registry.KEY_WOW64_32KEY) Giving multiple arches here will return first result :return: value """
def _get_value(hive: int, key: str, value: Optional[str], arch: int) -> str: try: open_reg = ConnectRegistry(None, hive) open_key = OpenKey(open_reg, key, 0, KEY_READ | arch) value, type = QueryValueEx(open_key, value) # Return the first match return value except (FileNotFoundError, TypeError, OSError) as exc: raise FileNotFoundError('Registry key [%s] with value [%s] not found. %s' % (key, value, exc))
# 768 = 0 | KEY_WOW64_64KEY | KEY_WOW64_32KEY (where 0 = default) if arch == 768: for _arch in [KEY_WOW64_64KEY, KEY_WOW64_32KEY]: try: return _get_value(hive, key, value, _arch) except FileNotFoundError: pass raise FileNotFoundError else: return _get_value(hive, key, value, arch)
def get_keys(hive: int, key: str, arch: int = 0, open_reg: HKEYType = None, recursion_level: int = 1, filter_on_names: List[str] = None, combine: bool = False) -> dict: """ :param hive: registry hive (windows.registry.HKEY_LOCAL_MACHINE...) :param key: which registry key we're searching for :param arch: which registry architecture we seek (0 = default, windows.registry.KEY_WOW64_64KEY, windows.registry.KEY_WOW64_32KEY) :param open_reg: (handle) handle to already open reg key (for recursive searches), do not give this in your function call :param recursion_level: recursivity level :param filter_on_names: list of strings we search, if none given, all value names are returned :param combine: shall we combine multiple arch results or return first match :return: list of strings """ def _get_keys(hive: int, key: str, arch: int, open_reg: HKEYType, recursion_level: int, filter_on_names: List[str]): try: if not open_reg: open_reg = ConnectRegistry(None, hive) open_key = OpenKey(open_reg, key, 0, KEY_READ | arch) subkey_count, value_count, _ = QueryInfoKey(open_key)
output = {} values = [] for index in range(value_count): name, value, type = EnumValue(open_key, index) if isinstance(filter_on_names, list) and name not in filter_on_names: pass else: values.append({'name': name, 'value': value, 'type': type}) if not values == []: output[''] = values
if recursion_level > 0: for subkey_index in range(subkey_count): try: subkey_name = EnumKey(open_key, subkey_index) sub_values = get_keys(hive=0, key=key + '\\' + subkey_name, arch=arch, open_reg=open_reg, recursion_level=recursion_level - 1, filter_on_names=filter_on_names) output[subkey_name] = sub_values except FileNotFoundError: pass
return output
except (FileNotFoundError, TypeError, OSError) as exc: raise FileNotFoundError('Cannot query registry key [%s]. %s' % (key, exc))
# 768 = 0 | KEY_WOW64_64KEY | KEY_WOW64_32KEY (where 0 = default) if arch == 768: result = {} for _arch in [KEY_WOW64_64KEY, KEY_WOW64_32KEY]: try: if combine: result.update(_get_keys(hive, key, _arch, open_reg, recursion_level, filter_on_names)) else: return _get_keys(hive, key, _arch, open_reg, recursion_level, filter_on_names) except FileNotFoundError: pass return result else: return _get_keys(hive, key, arch, open_reg, recursion_level, filter_on_names)
def get_office_click_and_run_ident(): # type: () -> Optional[str] """ Try to find the office product via clickandrun productID """ try: click_and_run_ident = get_value(HKEY_LOCAL_MACHINE, r'Software\Microsoft\Office\ClickToRun\Configuration', 'ProductReleaseIds', arch=KEY_WOW64_64KEY |KEY_WOW64_32KEY,) except FileNotFoundError: click_and_run_ident = None return click_and_run_ident
def _get_used_word_version(): # type: () -> Optional[int] """ Try do determine which version of Word is used (in case multiple versions are installed) """ try: word_ver = get_value(HKEY_CLASSES_ROOT, r'Word.Application\CurVer', None) except FileNotFoundError: word_ver = None try: version = int(word_ver.split('.')[2]) except (IndexError, ValueError, AttributeError): version = None return version
def _get_installed_office_version(): # type: () -> Optional[str, bool] """ Try do determine which is the highest current version of Office installed """ for possible_version, _ in KNOWN_VERSIONS.items(): try: office_keys = get_keys(HKEY_LOCAL_MACHINE, r'SOFTWARE\Microsoft\Office\{}'.format(possible_version), recursion_level=2, arch=KEY_WOW64_64KEY |KEY_WOW64_32KEY, combine=True)
try: is_click_and_run = True if office_keys['ClickToRunStore'] is not None else False except: is_click_and_run = False
try: is_valid = True if office_keys['Word'] is not None else False if is_valid: return possible_version, is_click_and_run except KeyError: pass except FileNotFoundError: pass return None, None
def get_office_version(): # type: () -> Tuple[str, Optional[str]] """ It's plain horrible to get the office version installed Let's use some tricks, ie detect current Word used """
word_version = _get_used_word_version() office_version, is_click_and_run = _get_installed_office_version()
# Prefer to get used word version instead of installed one if word_version is not None: office_version = word_version
version = float(office_version) click_and_run_ident = get_office_click_and_run_ident()
def _get_office_version(): # type: () -> str if version: if version < 16: try: return KNOWN_VERSIONS['{}.0'.format(version)] except KeyError: pass # Special hack to determine which of 2016, 2019 or O365 it is if version == 16: if isinstance(click_and_run_ident, str): if '2016' in click_and_run_ident: return '2016' if '2019' in click_and_run_ident: return '2019' if 'O365' in click_and_run_ident: return 'O365' return '2016/2019/O365' # Let's return whatever we found out return 'Unknown: {}'.format(version, click_and_run_ident)
if isinstance(click_and_run_ident, str) or is_click_and_run: click_and_run_suffix = 'ClickAndRun' else: click_and_run_suffix = None
return _get_office_version(), click_and_run_suffix