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:
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user