v1.8.89: fix DLL error on auto-update — clean all stale _MEI dirs, launch via explorer.exe

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
chrome-storm-c442
2026-03-02 02:11:02 -05:00
parent acc93f98e3
commit 1218f4d72d
3 changed files with 59 additions and 31 deletions

View File

@@ -262,47 +262,75 @@ class UpdateChecker:
return self._apply_linux(binary_path, current_exe)
def _apply_windows(self, new_exe: str, current_exe: str) -> bool:
"""Windows update: create hidden .vbs that runs .bat silently."""
"""Windows update: PowerShell script waits for exit, copies, launches."""
try:
tmp_dir = tempfile.gettempdir()
bat_path = os.path.join(tmp_dir, "sm_update.bat")
ps_path = os.path.join(tmp_dir, "sm_update.ps1")
vbs_path = os.path.join(tmp_dir, "sm_update.vbs")
pid = os.getpid()
# Clean up old PyInstaller _MEI dirs to avoid DLL conflicts
mei_dir = getattr(sys, '_MEIPASS', '')
exe_dir = os.path.dirname(current_exe)
bat_content = f"""@echo off
:wait
tasklist /fi "PID eq {pid}" 2>NUL | find "{pid}" >NUL
if %ERRORLEVEL% == 0 (
timeout /t 1 /nobreak >NUL
goto wait
)
timeout /t 2 /nobreak >NUL
if exist "{mei_dir}" rmdir /s /q "{mei_dir}" >NUL 2>NUL
copy /Y "{new_exe}" "{current_exe}" >NUL
if %ERRORLEVEL% NEQ 0 (
timeout /t 3 /nobreak >NUL
copy /Y "{new_exe}" "{current_exe}" >NUL
if %ERRORLEVEL% NEQ 0 exit /b 1
)
timeout /t 2 /nobreak >NUL
start "" "{current_exe}"
del "{new_exe}" >NUL 2>NUL
del "{bat_path}"
del "%~f0"
ps_content = f"""
$ErrorActionPreference = 'Stop'
$pid = {pid}
$src = '{new_exe}'
$dst = '{current_exe}'
$mei = '{mei_dir}'
$exeDir = '{exe_dir}'
$tempDir = '{tmp_dir}'
# Wait for old process to exit
while (Get-Process -Id $pid -ErrorAction SilentlyContinue) {{
Start-Sleep -Seconds 1
}}
Start-Sleep -Seconds 2
# Clean ALL stale _MEI directories (PyInstaller temp dirs)
Get-ChildItem -Path $tempDir -Directory -Filter '_MEI*' -ErrorAction SilentlyContinue | ForEach-Object {{
Remove-Item -Path $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
}}
Start-Sleep -Seconds 1
# Copy with retry
$copied = $false
for ($i = 0; $i -lt 5; $i++) {{
try {{
Copy-Item -Path $src -Destination $dst -Force
$srcSize = (Get-Item $src).Length
$dstSize = (Get-Item $dst).Length
if ($srcSize -eq $dstSize) {{
$copied = $true
break
}}
}} catch {{}}
Start-Sleep -Seconds 2
}}
if (-not $copied) {{ exit 1 }}
Start-Sleep -Seconds 2
# Launch new exe via explorer.exe (mimics user double-click, clean environment)
Start-Process explorer.exe $dst
# Cleanup
Start-Sleep -Seconds 3
Remove-Item -Path $src -Force -ErrorAction SilentlyContinue
Remove-Item -Path '{ps_path}' -Force -ErrorAction SilentlyContinue
"""
with open(bat_path, "w") as f:
f.write(bat_content)
with open(ps_path, "w", encoding="utf-8") as f:
f.write(ps_content)
# VBS wrapper runs .bat completely hidden (no CMD flash)
vbs_content = f'CreateObject("Wscript.Shell").Run """{bat_path}""", 0, False\n'
# VBS wrapper launches PowerShell hidden (no window flash)
vbs_content = (
'CreateObject("Wscript.Shell").Run '
'"powershell -ExecutionPolicy Bypass -WindowStyle Hidden '
f'-File ""{ps_path}""""", 0, False\n'
)
with open(vbs_path, "w") as f:
f.write(vbs_content)
# Launch VBS via os.startfile — most reliable on Windows,
# works from frozen exe without PATH issues
os.startfile(vbs_path)
return True