Modul: Update (nui_update)
UpdateChecker lädt beim Start ein kleines version.json-Manifest von einem eigenen Patch-Server und vergleicht dessen version-Feld mit der aktuell laufenden Version (NUISTUDIO_VERSION, einzige Quelle der Wahrheit — siehe oberstes CMakeLists.txt).DownloadAndInstall auf: lädt die neue .exe, verifiziert optional ihren SHA-256-Hash gegen version.json, und übergibt an den unten beschriebenen Neustart-Mechanismus.Die ursprüngliche Umsetzung schrieb ein .bat-Skript, das per tasklist/find in einer Poll-Schleife auf das Verschwinden der eigenen PID wartete, dann die heruntergeladene .exe über die laufende kopierte, den Editor neu startete und sich selbst löschte. Das führte real zu genau der Klasse Fehler, die Text-basiertes Polling mit sich bringt: PID-Erkennung per String-Vergleich ist locale-abhängig und bietet kein echtes "der Prozess ist jetzt wirklich weg"-Signal, nur ein Sekundentakt-Raten. In der Praxis blieb der Vorgang wiederholt hängen — NUIStudio.update.bat/NUIStudio.update.exe blieben neben der unveränderten alten .exe liegen, bis manuell nachgeholfen wurde.
Die aktuelle Umsetzung ersetzt das Skript vollständig durch einen echten Win32-Mechanismus:
DownloadAndInstall dupliziert das eigene Prozess-Handle (DuplicateHandle(GetCurrentProcess(), ...)) als vererbbar und startet die frisch heruntergeladene .exe direkt — nicht über cmd.exe — mit dem versteckten Argument --finish-update <Handle-Wert> <Zielpfad>. Das vererbte Handle referenziert exakt diesen Prozess, nie eine bloße PID, die nach dem Beenden von Windows an einen völlig anderen, neuen Prozess vergeben werden könnte.main.cpp erkennt dieses Argument über CommandLineToArgvW, bevor überhaupt ein Fenster oder ein DirectX-12-Gerät erzeugt wird, und verzweigt direkt in RunFinishUpdateAndExit — der normale Editor-Start läuft in diesem versteckten Modus nie an.RunFinishUpdateAndExit ruft WaitForSingleObject auf das übergebene Handle — ein echtes Betriebssystem-Signal, kein Poll-Intervall, mit 5 Minuten Timeout als reine Sicherheitsgrenze für den Fall eines wirklich hängenden Eltern-Prozesses..exe per MoveFileExW selbst auf den Zielpfad um. Das ist auf NTFS unproblematisch — eine laufende ausführbare Datei bleibt über ihr offenes Datei-Objekt funktionsfähig, unabhängig davon, welcher (oder ob überhaupt ein) Verzeichniseintrag noch auf sie zeigt. Ein kurzer Retry (bis zu 20 Versuche à 250 ms) fängt einen kurzzeitigen Virenscanner-/Indexer-Zugriff auf die gerade freigewordene alte Datei ab..exe wird am Zielpfad gestartet, der Helfer-Prozess beendet sich. Gelingt das Umbenennen ausnahmsweise nicht, startet stattdessen die unverändert gebliebene alte Version neu — der Nutzer steht nie ganz ohne laufende Anwendung da.Kein Skript, kein Selbstlösch-Trick, keine cmd.exe-Zwischenschicht.
Da dieser Mechanismus reine Windows-Prozesslebenszyklus-Logik ist (kein GPU-Bezug, aber auch keine reine Funktion — WaitForSingleObject/MoveFileExW/CreateProcessW brauchen echte Prozesse), sind die automatisierten Tests bewusst zweigeteilt:
tests/UpdateTests/UpdaterTests.cpp: reine Unit-Tests für ParseFinishUpdateArgs (die argv-Erkennung des versteckten Modus) — deterministisch, ohne echten Prozess.DownloadAndInstall es tut, und bestätigte über drei Wiederholungen hinweg: Die Übernahme (Umbenennen + Neustart) erfolgt rund 107 ms, nachdem der beobachtete Prozess tatsächlich endet — reproduzierbar, ohne zurückbleibende Prozesse oder Dateien.