Skip to content

Instantly share code, notes, and snippets.

@u1735067
Created April 24, 2019 10:33
Show Gist options
  • Save u1735067/0609396bbed8318263155445c85d011d to your computer and use it in GitHub Desktop.
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
#!/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