import os from subprocess import PIPE, Popen import ctypes import ssl import urllib2 import _winreg import time import re class disable_file_system_redirection: _disable = ctypes.windll.kernel32.Wow64DisableWow64FsRedirection _revert = ctypes.windll.kernel32.Wow64RevertWow64FsRedirection def __enter__(self): self.old_value = ctypes.c_long() self.success = self._disable(ctypes.byref(self.old_value)) def __exit__(self, type, value, traceback): if self.success: self._revert(self.old_value) with disable_file_system_redirection(): arch = os.popen("wmic os get OSArchitecture").read() userout = os.popen('query user').read() username = re.findall("(.*)Active", userout)[0].split()[0] sid = os.popen('wmic useraccount where name="%s" get sid' % username).read().splitlines()[1].strip() url = "https://cdn-patchportal-one.comodo.com/portal/packages/spm/VulkanSDK/x64/vulkansdk-windows-X64-1.4.350.0.exe" Down_path = os.environ["TEMP"] fileName = url.split("/")[-1] DownTo = os.path.join(Down_path, fileName) INSTALL_ROOT = r"C:\Windows\TEMP\VulkanSDK" LOG_FILE = r"C:\Windows\TEMP\vulkan_spm_debug.log" REGKEY_TEMPLATE = r"HKEY_USERS\%s\Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" def log(msg): try: with open(LOG_FILE, "a") as f: f.write("%s | %s\n" % (time.strftime("%Y-%m-%d %H:%M:%S"), msg)) except Exception: pass def ecmd(command): from subprocess import Popen, PIPE with disable_file_system_redirection(): obj = Popen(command, shell=True, stdout=PIPE, stderr=PIPE) out, err = obj.communicate() if obj.returncode == 0: return out.strip() if out else obj.returncode else: return err.strip() if err else obj.returncode def downloadFile(DownTo, fromURL, retries=3, delay=10): headers = {'User-Agent': 'Mozilla/5.0'} context = ssl._create_unverified_context() last_err = None for attempt in range(1, retries + 1): try: request = urllib2.Request(fromURL, headers=headers) req = urllib2.urlopen(request, timeout=30, context=context) with open(DownTo, "wb") as f: while True: chunk = req.read(1024 * 1024) if not chunk: break f.write(chunk) if os.path.isfile(DownTo): return DownTo except Exception as e: last_err = e if attempt < retries: time.sleep(delay) raise Exception("Download failed after %d attempts: %s" % (retries, last_err)) def wait_for_install_folder(timeout=180, interval=5): waited = 0 while waited < timeout: if os.path.isdir(INSTALL_ROOT) and os.path.isdir(os.path.join(INSTALL_ROOT, "Bin")): log("Install folder detected after %d seconds." % waited) return True time.sleep(interval) waited += interval log("Install folder NOT detected within %d seconds." % timeout) return False def find_guid_under_default(timeout=60, interval=5): """Locate the newly created GUID under HKU\\.DEFAULT that matches Vulkan SDK.""" path = r".DEFAULT\Software\Microsoft\Windows\CurrentVersion\Uninstall" waited = 0 while waited < timeout: try: key = _winreg.OpenKey(_winreg.HKEY_USERS, path) for i in range(_winreg.QueryInfoKey(key)[0]): try: sub = _winreg.EnumKey(key, i) skey = _winreg.OpenKey(key, sub) try: name = _winreg.QueryValueEx(skey, "DisplayName")[0] if "Vulkan SDK" in name: log("Found new GUID under .DEFAULT: %s" % sub) return sub except Exception: pass except Exception: pass except Exception as e: log("Error scanning .DEFAULT: %s" % e) time.sleep(interval) waited += interval log("No GUID found under .DEFAULT after %d seconds." % timeout) return None def migrate_reg_to_user_hive(guid): """Export from HKU\\.DEFAULT, delete it there, rewrite path to the logged-in user's SID, re-import.""" reg_path = os.path.join(Down_path, "vulkan_%s.reg" % guid) src_default = r"HKEY_USERS\.DEFAULT\Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % guid export_result = os.popen('reg export "%s" "%s" /y' % (src_default, reg_path)).read() log("reg export result: %s" % export_result) if not os.path.isfile(reg_path): log("Export failed - reg file not created.") return False del_result = os.popen('reg delete "%s" /f' % src_default).read() log("reg delete .DEFAULT entry result: %s" % del_result) with open(reg_path, "rb") as f: raw = f.read() content = raw.decode("utf-16") new_key_path = REGKEY_TEMPLATE % (sid, guid) new_content = re.sub(r"\[.*\{.*\}\]", "[%s]" % new_key_path, content, count=1) with open(reg_path, "wb") as f: f.write(new_content.encode("utf-16")) import_result = os.popen('reg import "%s"' % reg_path).read() log("reg import result: %s" % import_result) try: os.remove(reg_path) except Exception: pass return True def get_uninstall_info_from_user_hive(): """Scan HKEY_USERS\\{sid}\\...\\Uninstall for the current Vulkan SDK entry.""" path = r"%s\Software\Microsoft\Windows\CurrentVersion\Uninstall" % sid try: key = _winreg.OpenKey(_winreg.HKEY_USERS, path) except Exception as e: log("No uninstall key found under user hive: %s" % e) return None, None for i in range(_winreg.QueryInfoKey(key)[0]): try: sub = _winreg.EnumKey(key, i) skey = _winreg.OpenKey(key, sub) try: name = _winreg.QueryValueEx(skey, "DisplayName")[0] if "Vulkan SDK" in name: uninstall_string = _winreg.QueryValueEx(skey, "UninstallString")[0] log("Found existing entry in user hive: guid=%s name=%s" % (sub, name)) return sub, uninstall_string except Exception: pass except Exception: pass return None, None def spm_install(dir, args): with disable_file_system_redirection(): log("=== spm_install start ===") downloadFile(DownTo, url) ecmd('"%s" --root "%s" --accept-licenses --accept-messages --confirm-command install' % (DownTo, INSTALL_ROOT)) if wait_for_install_folder(timeout=180, interval=5): guid = find_guid_under_default(timeout=60, interval=5) if guid: migrate_reg_to_user_hive(guid) else: log("Install folder present but no registry GUID found - cannot register in Control Panel.") else: log("Install may have failed - folder never appeared.") if os.path.exists(DownTo): os.remove(DownTo) log("=== spm_install end ===") def spm_uninstall(dir, args): with disable_file_system_redirection(): log("=== spm_uninstall start ===") guid, uninstall_string = get_uninstall_info_from_user_hive() if uninstall_string: uninstall_string = uninstall_string.replace('"', '') log("Running uninstaller: %s" % uninstall_string) ecmd('"%s" --silent' % uninstall_string) time.sleep(5) # Explicitly remove the registry entry to prevent double-entry on next install key_path = r"HKEY_USERS\%s\Software\Microsoft\Windows\CurrentVersion\Uninstall\%s" % (sid, guid) del_result = os.popen('reg delete "%s" /f' % key_path).read() log("reg delete after uninstall: %s" % del_result) else: log("No existing Vulkan SDK entry found - nothing to uninstall.") # Clean up leftover install folder if uninstaller didn't remove it if os.path.isdir(INSTALL_ROOT): os.popen('RD /S /Q "%s"' % INSTALL_ROOT) log("Removed leftover install folder.") log("=== spm_uninstall end ===") def spm_update(dir, args): with disable_file_system_redirection(): spm_uninstall(None, None) time.sleep(15) spm_install(None, None)