# Beendet alle laufenden Prozesse dieses Projekts (Electron, Node/Vite, und # einen verwaisten lokalen Input-Helper-Kindprozess), bevor eine neue Instanz # startet. # # Warum das noetig ist: Ein normales Schliessen der App (X-Button) raeumt # sauber auf (main.ts: app.on("will-quit") beendet den gespawnten # input-helper.ps1-Kindprozess). Wird die App aber gewaltsam beendet - z.B. # ueber Task-Manager "Task beenden" oder ein Skript, das Stop-Process -Force # auf den Electron-Prozess anwendet - greift dieser Cleanup-Handler NICHT, # und der Kindprozess (PowerShell mit dem Input-Helper) bleibt als Waise # aktiv, obwohl das Hauptfenster laengst weg ist. Dieses Skript faengt genau # das ab: es wird vor JEDEM Start (npm run dev und npm run dev:admin, ueber # den "predev"-Hook) ausgefuehrt und raeumt vorherige Instanzen kompromisslos # weg, egal wie sie beendet wurden. $ErrorActionPreference = "Stop" $project = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path $electronPath = Join-Path $project "node_modules\electron\dist\electron.exe" $devControlPort = 17317 $killed = 0 $candidatePids = @{} try { $health = Invoke-RestMethod -Method Get -Uri "http://127.0.0.1:$devControlPort/health" -TimeoutSec 2 -ErrorAction Stop if ($health.appBuild -and $health.appBuild.cwd -eq $project) { Write-Host "Dev-Control-Port $devControlPort gehoert zu diesem Projekt (PID $($health.appBuild.pid), Signatur $($health.appBuild.signature)). Versuche Self-Shutdown..." try { Invoke-RestMethod -Method Get -Uri "http://127.0.0.1:$devControlPort/dev/shutdown?reason=restart" -TimeoutSec 2 -ErrorAction Stop | Out-Null Start-Sleep -Milliseconds 900 } catch { Write-Host "Self-Shutdown nicht verfuegbar oder fehlgeschlagen: $($_.Exception.Message)" -ForegroundColor Yellow } } } catch { # No dev-control server or an older/stuck process; continue with process scan. } Get-CimInstance Win32_Process | Where-Object { ($_.Name -eq "electron.exe" -and $_.ExecutablePath -eq $electronPath) -or ($_.Name -eq "node.exe" -and $_.CommandLine -like "*$project*") -or ($_.Name -eq "powershell.exe" -and $_.CommandLine -like "*input-helper.ps1*") } | ForEach-Object { $candidatePids[[int]$_.ProcessId] = $_.Name } try { Get-NetTCPConnection -LocalPort $devControlPort -State Listen -ErrorAction Stop | ForEach-Object { if ($_.OwningProcess -gt 0) { $owner = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue $candidatePids[[int]$_.OwningProcess] = if ($owner) { "$($owner.ProcessName) port $devControlPort" } else { "port $devControlPort owner" } } } } catch { # Get-NetTCPConnection can be unavailable on some machines; process matching # above still handles the normal non-elevated path. } $failed = 0 foreach ($entry in $candidatePids.GetEnumerator()) { Write-Host "Beende alte Instanz: $($entry.Value) (PID $($entry.Key))" try { Stop-Process -Id $entry.Key -Force -ErrorAction Stop $killed++ } catch { Write-Host "WARNUNG: Konnte PID $($entry.Key) nicht beenden: $($_.Exception.Message)" -ForegroundColor Yellow $failed++ } } if ($killed -gt 0) { # Windows braucht einen Moment, um Ports/Handles wirklich freizugeben. Start-Sleep -Milliseconds 500 Write-Host "$killed alte Prozess(e) beendet." } if ($failed -gt 0) { Write-Host "$failed alte Prozess(e) konnten nicht beendet werden. Wenn das ein Admin-Prozess ist, starte npm run dev:admin und bestaetige UAC oder schliesse die alte App manuell." -ForegroundColor Yellow throw "$failed alte Prozess(e) konnten nicht beendet werden." } if ($killed -eq 0 -and $failed -eq 0) { Write-Host "Keine alten Instanzen gefunden." } else { Start-Sleep -Milliseconds 300 }