diff --git a/Setup/Runtime.cs b/Setup/Runtime.cs
deleted file mode 100644
index ed332a6..0000000
--- a/Setup/Runtime.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using System.ComponentModel;
-using System.Diagnostics;
-using System.IO;
-using System.Net;
-using System.Net.Http;
-using System.Runtime.InteropServices;
-using System.Security.Cryptography.X509Certificates;
-using Microsoft.Win32;
-
-namespace DeskCoreSetup;
-
-/// Prüft und installiert die von DeskCore benötigte "Microsoft .NET 9 Desktop Runtime".
-public static class Runtime
-{
- public const string DisplayName = "Microsoft .NET 9 Desktop Runtime";
- public const int Major = 9;
- public const string DownloadPage = "https://dotnet.microsoft.com/de-de/download/dotnet/9.0";
- // offizieller Microsoft-Kurzlink auf die jeweils aktuelle 9.0-Version
- private const string InstallerUrl = "https://aka.ms/dotnet/9.0/windowsdesktop-runtime-win-x64.exe";
-
- public static bool Is64BitWindows => Environment.Is64BitOperatingSystem;
-
- public static bool IsInstalled
- {
- get
- {
- try
- {
- var dir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
- "dotnet", "shared", "Microsoft.WindowsDesktop.App");
- if (Directory.Exists(dir) && Directory.GetDirectories(dir).Any(d => Path.GetFileName(d).StartsWith($"{Major}.")))
- return true;
- }
- catch { }
- try
- {
- using var hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
- using var k = hklm.OpenSubKey(@"SOFTWARE\dotnet\Setup\InstalledVersions\x64\sharedfx\Microsoft.WindowsDesktop.App");
- if (k?.GetValueNames().Any(n => n.StartsWith($"{Major}.")) == true) return true;
- }
- catch { }
- return false;
- }
- }
-
- /// Lädt die Laufzeit von Microsoft und installiert sie (Windows fragt einmal nach Administratorrechten).
- public static void Install(Action progress)
- {
- ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;
- var file = Path.Combine(Path.GetTempPath(), $"windowsdesktop-runtime-{Major}-win-x64.exe");
-
- using (var http = new HttpClient { Timeout = TimeSpan.FromMinutes(20) })
- {
- http.DefaultRequestHeaders.UserAgent.ParseAdd("DeskCore-Setup");
- using var resp = http.GetAsync(InstallerUrl, HttpCompletionOption.ResponseHeadersRead).GetAwaiter().GetResult();
- resp.EnsureSuccessStatusCode();
- long total = resp.Content.Headers.ContentLength ?? 0;
- using var input = resp.Content.ReadAsStreamAsync().GetAwaiter().GetResult();
- using var output = File.Create(file);
- var buffer = new byte[81920];
- long done = 0;
- int read;
- while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
- {
- output.Write(buffer, 0, read);
- done += read;
- progress(total > 0 ? (double)done / total : 0,
- total > 0 ? $"{DisplayName} wird heruntergeladen … {done / 1048576} von {total / 1048576} MB"
- : $"{DisplayName} wird heruntergeladen … {done / 1048576} MB");
- }
- }
-
- // Sicherheit: nur ausführen, wenn die Datei gültig von Microsoft signiert ist
- if (!IsSignedByMicrosoft(file))
- {
- try { File.Delete(file); } catch { }
- throw new InvalidOperationException("Die heruntergeladene Datei ist nicht gültig von Microsoft signiert und wurde nicht ausgeführt.");
- }
-
- progress(1, $"{DisplayName} wird installiert – bitte die Windows-Abfrage bestätigen …");
- Process p;
- try
- {
- p = Process.Start(new ProcessStartInfo(file, "/install /quiet /norestart") { UseShellExecute = true, Verb = "runas" })!;
- }
- catch (Win32Exception ex) when (ex.NativeErrorCode == 1223)
- {
- throw new InvalidOperationException($"Die Installation von {DisplayName} wurde abgebrochen.");
- }
- p.WaitForExit();
- try { File.Delete(file); } catch { }
- // 0 = ok, 3010/1641 = ok, Neustart empfohlen
- if (p.ExitCode is not (0 or 3010 or 1641) || !IsInstalled)
- throw new InvalidOperationException($"{DisplayName} konnte nicht installiert werden (Code {p.ExitCode}).");
- }
-
- // ---------- Signaturprüfung (WinVerifyTrust) ----------
-
- private static bool IsSignedByMicrosoft(string file)
- {
- try
- {
- var subject = X509Certificate.CreateFromSignedFile(file).Subject;
- if (subject.IndexOf("O=Microsoft Corporation", StringComparison.OrdinalIgnoreCase) < 0) return false;
- }
- catch { return false; }
- return VerifyTrust(file);
- }
-
- private static bool VerifyTrust(string file)
- {
- var fileInfo = new WINTRUST_FILE_INFO
- {
- cbStruct = (uint)Marshal.SizeOf(),
- pcwszFilePath = file,
- };
- var pFile = Marshal.AllocHGlobal(Marshal.SizeOf());
- try
- {
- Marshal.StructureToPtr(fileInfo, pFile, false);
- var data = new WINTRUST_DATA
- {
- cbStruct = (uint)Marshal.SizeOf(),
- dwUIChoice = 2, // WTD_UI_NONE
- fdwRevocationChecks = 0, // WTD_REVOKE_NONE
- dwUnionChoice = 1, // WTD_CHOICE_FILE
- pFile = pFile,
- dwStateAction = 0,
- dwProvFlags = 0x40, // WTD_SAFER_FLAG
- };
- var action = new Guid("00AAC56B-CD44-11d0-8CC2-00C04FC295EE"); // WINTRUST_ACTION_GENERIC_VERIFY_V2
- return WinVerifyTrust(IntPtr.Zero, ref action, ref data) == 0;
- }
- finally
- {
- Marshal.FreeHGlobal(pFile);
- }
- }
-
- [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
- private struct WINTRUST_FILE_INFO
- {
- public uint cbStruct;
- public string pcwszFilePath;
- public IntPtr hFile;
- public IntPtr pgKnownSubject;
- }
-
- [StructLayout(LayoutKind.Sequential)]
- private struct WINTRUST_DATA
- {
- public uint cbStruct;
- public IntPtr pPolicyCallbackData;
- public IntPtr pSIPClientData;
- public uint dwUIChoice;
- public uint fdwRevocationChecks;
- public uint dwUnionChoice;
- public IntPtr pFile;
- public uint dwStateAction;
- public IntPtr hWVTStateData;
- public IntPtr pwszURLReference;
- public uint dwProvFlags;
- public uint dwUIContext;
- public IntPtr pSignatureSettings;
- }
-
- [DllImport("wintrust.dll", ExactSpelling = true, SetLastError = false, CharSet = CharSet.Unicode)]
- private static extern int WinVerifyTrust(IntPtr hwnd, ref Guid pgActionID, ref WINTRUST_DATA pWVTData);
-}