Avoid pywin32 dependency on Windows (#635)

Instead use winreg/_winreg for the registry and ctypes for the
SendMessage call
This commit is contained in:
Amin Yahyaabadi
2020-10-07 10:01:03 -05:00
committed by GitHub
parent 31f5f842ff
commit 53c184e8d3

View File

@@ -21,6 +21,13 @@ import subprocess
import sys import sys
import sysconfig import sysconfig
import zipfile import zipfile
if os.name == 'nt':
try:
import winreg
except ImportError:
# old python 2 name
import _winreg as winreg
import ctypes.wintypes
if sys.version_info >= (3,): if sys.version_info >= (3,):
from urllib.parse import urljoin from urllib.parse import urljoin
@@ -291,31 +298,15 @@ def remove_tree(d):
debug_print('remove_tree threw an exception, ignoring: ' + str(e)) debug_print('remove_tree threw an exception, ignoring: ' + str(e))
def import_pywin32():
if WINDOWS:
try:
import win32api
import win32con
return win32api, win32con
except Exception:
exit_with_error('Failed to import Python Windows extensions win32api and win32con. Make sure you are using the version of python available in emsdk, or install PyWin extensions to the distribution of Python you are attempting to use. (This script was launched in python instance from "' + sys.executable + '")')
def win_set_environment_variable_direct(key, value, system=True): def win_set_environment_variable_direct(key, value, system=True):
prev_path = os.environ['PATH']
try: try:
py = find_used_python()
if py:
py_path = to_native_path(py.expand_vars(py.activated_path))
os.environ['PATH'] = os.environ['PATH'] + ';' + py_path
win32api, win32con = import_pywin32()
if system: if system:
# Read globally from ALL USERS section. # Read globally from ALL USERS section.
folder = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', 0, win32con.KEY_ALL_ACCESS) folder = winreg.OpenKeyEx(winreg.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment', 0, winreg.KEY_ALL_ACCESS)
else: else:
# Register locally from CURRENT USER section. # Register locally from CURRENT USER section.
folder = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, 'Environment', 0, win32con.KEY_ALL_ACCESS) folder = winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, 'Environment', 0, winreg.KEY_ALL_ACCESS)
win32api.RegSetValueEx(folder, key, 0, win32con.REG_EXPAND_SZ, value) winreg.SetValueEx(folder, key, 0, winreg.REG_EXPAND_SZ, value)
debug_print('Set key=' + key + ' with value ' + value + ' in registry.') debug_print('Set key=' + key + ' with value ' + value + ' in registry.')
except Exception as e: except Exception as e:
# 'Access is denied.' # 'Access is denied.'
@@ -323,32 +314,25 @@ def win_set_environment_variable_direct(key, value, system=True):
exit_with_error('Error! Failed to set the environment variable \'' + key + '\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.') exit_with_error('Error! Failed to set the environment variable \'' + key + '\'! Setting environment variables permanently requires administrator access. Please rerun this command with administrative privileges. This can be done for example by holding down the Ctrl and Shift keys while opening a command prompt in start menu.')
errlog('Failed to write environment variable ' + key + ':') errlog('Failed to write environment variable ' + key + ':')
errlog(str(e)) errlog(str(e))
win32api.RegCloseKey(folder) folder.Close()
os.environ['PATH'] = prev_path
return None return None
win32api.RegCloseKey(folder) folder.Close()
os.environ['PATH'] = prev_path HWND_BROADCAST = ctypes.wintypes.HWND(0xFFFF) # win32con.HWND_BROADCAST == 65535
win32api.PostMessage(win32con.HWND_BROADCAST, win32con.WM_SETTINGCHANGE, 0, 'Environment') WM_SETTINGCHANGE = 0x001A # win32con.WM_SETTINGCHANGE == 26
ctypes.windll.user32.SendMessageA(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 'Environment')
def win_get_environment_variable(key, system=True): def win_get_environment_variable(key, system=True):
prev_path = os.environ['PATH']
try: try:
py = find_used_python()
if py:
py_path = to_native_path(py.expand_vars(py.activated_path))
os.environ['PATH'] = os.environ['PATH'] + ';' + py_path
try: try:
import win32api
import win32con
if system: if system:
# Read globally from ALL USERS section. # Read globally from ALL USERS section.
folder = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment') folder = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment')
else: else:
# Register locally from CURRENT USER section. # Register locally from CURRENT USER section.
folder = win32api.RegOpenKey(win32con.HKEY_CURRENT_USER, 'Environment') folder = winreg.OpenKey(winreg.HKEY_CURRENT_USER, 'Environment')
value = str(win32api.RegQueryValueEx(folder, key)[0]) value = str(winreg.QueryValueEx(folder, key)[0])
except Exception: except Exception:
# PyWin32 is not available - read via os.environ. This has the drawback # PyWin32 is not available - read via os.environ. This has the drawback
# that expansion items such as %PROGRAMFILES% will have been expanded, so # that expansion items such as %PROGRAMFILES% will have been expanded, so
@@ -361,13 +345,11 @@ def win_get_environment_variable(key, system=True):
errlog('Failed to read environment variable ' + key + ':') errlog('Failed to read environment variable ' + key + ':')
errlog(str(e)) errlog(str(e))
try: try:
win32api.RegCloseKey(folder) folder.Close()
except Exception: except Exception:
pass pass
os.environ['PATH'] = prev_path
return None return None
win32api.RegCloseKey(folder) folder.Close()
os.environ['PATH'] = prev_path
return value return value
@@ -2058,21 +2040,6 @@ def get_release_hash(arg, releases_info):
return releases_info.get(arg, None) or releases_info.get('sdk-' + arg + '-64bit') return releases_info.get(arg, None) or releases_info.get('sdk-' + arg + '-64bit')
# Finds the best-matching python tool for use.
def find_used_python():
# Find newest tool first - those are always at the end of the list.
for t in reversed(tools):
if t.id == 'python' and t.is_installed() and t.is_active() and t.is_env_active():
return t
for t in reversed(tools):
if t.id == 'python' and t.is_installed() and t.is_active():
return t
for t in reversed(tools):
if t.id == 'python' and t.is_installed():
return t
return None
def version_key(ver): def version_key(ver):
return tuple(map(int, re.split('[._-]', ver))) return tuple(map(int, re.split('[._-]', ver)))