Created
April 24, 2019 10:33
-
-
Save u1735067/0609396bbed8318263155445c85d011d to your computer and use it in GitHub Desktop.
Abandoned Python PATH editor script ; `rundll32 sysdm.cpl,EditEnvironmentVariables` is simpler to use and takes care of the ENV refresh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
import sys | |
import argparse | |
from collections import OrderedDict | |
import configparser | |
import pathlib | |
import json | |
import requests | |
import re | |
import sys, os, winreg | |
''' | |
nsis change user path | |
https://nsis.sourceforge.io/Docs/Chapter4.html | |
https://nsis.sourceforge.io/Path_Manipulation#Warning | |
https://nsis.sourceforge.io/Environmental_Variables:_append,_prepend,_and_remove_entries#Installer_Examples | |
https://www.smartmontools.org/browser/trunk/smartmontools/os_win32/installer.nsi?rev=4110#L636 | |
https://serverfault.com/questions/33681/how-can-i-modify-a-user-s-path-environment-variable-without-logging-out | |
https://ss64.com/nt/setx.html | |
> rundll32 sysdm.cpl,EditEnvironmentVariables | |
https://docs.microsoft.com/en-us/windows/desktop/sysinfo/registry-functions | |
https://docs.python.org/3.7/library/winreg.html#winreg.OpenKey | |
https://docs.python.org/3.7/library/winreg.html#winreg.QueryValueEx | |
https://docs.python.org/3.7/library/winreg.html#winreg.SetValueEx | |
https://docs.python.org/3.7/library/winreg.html#value-types | |
''' | |
class PathTool: | |
@staticmethod | |
def menu(): | |
choices = [ | |
{'key': 'P', 'entry': 'Print current path', 'action': PathTool.print_current}, | |
{'key': 'A', 'entry': '', 'action': PathTool.add_entry}, | |
{'key': 'A', 'entry': '', 'action': PathTool.add_entry}, | |
] | |
def print_current(): | |
try: | |
with winreg.OpenKeyEx(winreg.HKEY_CURRENT_USER, 'Environment') as key: | |
path_value, path_type = winreg.QueryValueEx(key, 'PATH') | |
splitted_path = path_value.split(os.pathsep) | |
except: | |
print('Failed to retreive path: {}'.format(e)) | |
sys.exit(1) | |
print('Current paths in PATH ({}):'.format(len(splitted_path))) | |
for i, path in enumerate(splitted_path, start=1): | |
print(' - {}: {}'.format(i, path)) | |
import ctypes, ctypes.wintypes | |
class Win32RefreshEnv: | |
# https://github.com/Muterra/py_hypergolix/blob/master/hypergolix/winpath.py | |
# https://github.com/shankj3/silver-giggle/blob/master/client/set_registry_proxy.py | |
# https://programtalk.com/python-examples/ctypes.windll.user32.SendMessageTimeoutW/ | |
# https://programtalk.com/vs2/python/11577/scalarizr/tests/acceptance/updclient/omnibus_test_project/package-scripts/mock-scalarizr/windows_helpers.py/ | |
# https://github.com/python/cpython/blob/79da388a4016e24c4258dcc62cd0fa9dde0acb5b/Tools/msi/bundle/bootstrap/PythonBootstrapperApplication.cpp#L1177 | |
# https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessagetimeoutw | |
# https://nsis.sourceforge.io/Docs/Chapter4.html | |
# https://nsis.sourceforge.io/Path_Manipulation#Warning | |
# https://nsis.sourceforge.io/Environmental_Variables:_append,_prepend,_and_remove_entries#Installer_Examples | |
# https://www.smartmontools.org/browser/trunk/smartmontools/os_win32/installer.nsi?rev=4110#L636 | |
HWND_BROADCAST = 0xFFFF | |
WM_SETTINGCHANGE = 0x1A # https://docs.microsoft.com/en-us/windows/desktop/winmsg/wm-settingchange | |
class SMTO: | |
NORMAL = 0x00 # The calling thread is not prevented from processing other requests while waiting for the function to return. | |
BLOCK = 0x01 # Prevents the calling thread from processing any other requests until the function returns. | |
ABORTIFHUNG = 0x02 # The function returns without waiting for the time-out period to elapse if the receiving thread appears to not respond or "hangs." | |
NOTIMEOUTIFNOTHUNG = 0x08 # The function does not enforce the time-out period as long as the receiving thread is processing messages. | |
ERRORONEXIT = 0x20 # The function should return 0 if the receiving window is destroyed or its owning thread dies while the message is being processed. | |
@classmethod | |
def refresh_env_sendtimeout(cls, timeout=500): | |
""" | |
""" | |
# WPARAM = ctypes.c_int64 if 'PROGRAMFILES(X86)' in os.environ else ctypes.c_int # ctypes.wintypes.UINT_PTR | |
LPARAM = ctypes.wintypes.LPWSTR | |
PDWORD_PTR = ctypes.POINTER(ctypes.wintypes.PDWORD) | |
# https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessagetimeoutw | |
SendMessageTimeout = ctypes.windll.user32.SendMessageTimeoutW | |
SendMessageTimeout.argtypes = ( | |
ctypes.wintypes.HWND, | |
ctypes.wintypes.UINT, | |
ctypes.wintypes.WPARAM, | |
LPARAM, | |
ctypes.wintypes.UINT, # fuFlags, SMTO | |
ctypes.wintypes.UINT, # uTimeout (ms) | |
PDWORD_PTR # lpdwResult / ctypes.wintypes.UINT | |
) | |
#SendMessageTimeout.restype = ctypes.wintypes.LRESULT = ctypes.wintypes.LONG_PTR | |
SendMessageTimeout.restype = cls.res_boolint_handler | |
SendMessageTimeout(cls.HWND_BROADCAST, cls.WM_SETTINGCHANGE, 0, 'Environment', cls.SMTO.NORMAL | cls.SMTO.ABORTIFHUNG, timeout, None) | |
# https://docs.python.org/3/library/ctypes.html#return-types | |
@staticmethod | |
def res_boolint_handler(res): | |
if not res: | |
raise ctypes.WinError() | |
return res | |
@classmethod | |
def refresh_env_postmsg(cls): | |
''' | |
Do not work: messages including pointers (like string) can't be sent asynchronously | |
res = 0 | |
err = 1159: Le message ne peut être utilisé qu’avec des opérations synchrones. https://assiste.com/Codes_erreur/Erreur_systeme_1159_0x487.html | |
''' | |
# https://stackoverflow.com/questions/1951658/sendmessagehwnd-broadcast-hangs | |
# https://stackoverflow.com/questions/32677687/how-to-make-sendmessage-unblocking | |
# https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-sendmessage | |
# https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-postmessagew | |
# http://www.vbforums.com/showthread.php?466660-Difference-SendMessage-SendMessageA-SendMessageW | |
# https://stackoverflow.com/questions/38449979/terminate-application-from-using-ironpython-and-ctypes | |
# https://stackoverflow.com/questions/9964396/python-check-if-a-system-is-32-or-64-bit-to-determine-whether-to-run-the-funct | |
# https://github.com/kennethreitz-archive/its.py/blob/master/its.py | |
# python WM_WININICHANGE | |
# https://stackoverflow.com/questions/21138014/how-to-add-to-and-remove-from-systems-environment-variable-path | |
# https://github.com/jaraco/jaraco.windows | |
# https://bugs.python.org/issue30374 | |
# https://github.com/python/cpython/blob/3.7/Tools/scripts/win_add2path.py | |
# https://github.com/pywinauto/pywinauto/blob/master/pywinauto/win32structures.py | |
# https://github.com/pywinauto/pywinauto/blob/master/pywinauto/win32functions.py | |
# https://stackoverflow.com/questions/8447308/ctypes-and-string | |
# https://www.programcreek.com/python/example/53959/ctypes.windll | |
# https://github.com/MarioVilas/winappdbg/search?q=GuessStringType&unscoped_q=GuessStringType | |
# https://github.com/MarioVilas/winappdbg/blob/8afbafc658dc30463492fb528779095be8c52b4e/winappdbg/win32/defines.py | |
# https://stackoverflow.com/questions/37966432/how-to-pass-const-char-from-python-to-c-function | |
# https://docs.microsoft.com/en-us/windows/desktop/winprog/windows-data-types#long-ptr | |
# https://en.wikibooks.org/wiki/Windows_Programming/Handles_and_Data_Types | |
# https://stackoverflow.com/questions/2208828/detect-64bit-os-windows-in-python | |
# https://github.com/python/cpython/blob/master/Lib/ctypes/__init__.py | |
# https://github.com/python/cpython/blob/master/Lib/ctypes/wintypes.py | |
# WPARAM = ctypes.c_int64 if 'PROGRAMFILES(X86)' in os.environ else ctypes.c_int # ctypes.wintypes.UINT_PTR | |
# WPARAM = ctypes.c_int # ctypes.wintypes.UINT_PTR | |
# LPARAM = ctypes.c_int64 if 'PROGRAMFILES(X86)' in os.environ else ctypes.c_long # ctypes.wintypes.LONG_PTR | |
LPARAM = ctypes.wintypes.LPWSTR | |
# https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-postmessagew | |
PostMessage = ctypes.windll.user32.PostMessageW | |
PostMessage.argtypes = ctypes.wintypes.HWND, ctypes.wintypes.UINT, ctypes.wintypes.WPARAM, LPARAM | |
# PostMessage.restype = ctypes.wintypes.BOOL | |
PostMessage.restype = cls.res_boolint_handler | |
PostMessage(cls.HWND_BROADCAST, cls.WM_SETTINGCHANGE, 0, 'Environment') | |
# https://gist.github.com/EBNull/6135237 | |
# https://msdn.microsoft.com/en-us/d852e148-985c-416f-a5a7-27b6914b45d4 | |
# https://gist.github.com/santa4nt/11068180 | |
# print(Win32RefreshEnv.id2msg(ctypes.windll.kernel32.GetLastError())) | |
# print(Win32RefreshEnv.id2msg(ctypes.GetLastError())) | |
# print(Win32RefreshEnv.id2msg(ctypes.GetLastError())) | |
# print(ctypes.FormatError(ctypes.GetLastError())) | |
@staticmethod | |
def id2msg(id): | |
# __all__ = ( | |
# FormatMessageSystem, | |
# LCID_ENGLISH, | |
# LCID_NEUTRAL, | |
# ) | |
# import ctypes | |
# import ctypes.wintypes | |
LANG_NEUTRAL = 0x00 | |
SUBLANG_NEUTRAL = 0x00 | |
SUBLANG_DEFAULT = 0x01 | |
LANG_ENGLISH = 0x09 | |
SUBLANG_ENGLISH_US = 0x01 | |
def MAKELANGID(primary, sublang): | |
return (primary & 0xFF) | (sublang & 0xFF) << 16 | |
LCID_ENGLISH = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US) | |
LCID_DEFAULT = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) | |
LCID_NEUTRAL = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL) | |
assert LCID_NEUTRAL == 0 | |
FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100 | |
FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 | |
FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200 | |
def FormatMessageSystem(id, langid=LCID_ENGLISH): | |
sys_flag = FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS | |
bufptr = ctypes.wintypes.LPWSTR() | |
chars = ctypes.windll.kernel32.FormatMessageW(sys_flag, None, id, langid, ctypes.byref(bufptr), 0, None) | |
if chars == 0: | |
chars = ctypes.windll.kernel32.FormatMessageW(sys_flag, None, id, LCID_NEUTRAL, ctypes.byref(bufptr), 0, None) | |
if chars == 0: | |
#XXX: You probably want to call GetLastError() here | |
return "FormatMessageW failed" | |
val = bufptr.value[:chars] | |
ctypes.windll.kernel32.LocalFree(bufptr) | |
return val | |
return FormatMessageSystem(id) | |
Win32RefreshEnv.refresh_env_sendtimeout() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment