From 20b0812c8257279728c093d2e7bf55470e022242 Mon Sep 17 00:00:00 2001 From: M_Viper Date: Sun, 4 Oct 2026 14:48:17 +0000 Subject: [PATCH] Delete Setup/Installer.cs via Git Manager GUI --- Setup/Installer.cs | 388 --------------------------------------------- 1 file changed, 388 deletions(-) delete mode 100644 Setup/Installer.cs diff --git a/Setup/Installer.cs b/Setup/Installer.cs deleted file mode 100644 index 4383a8b..0000000 --- a/Setup/Installer.cs +++ /dev/null @@ -1,388 +0,0 @@ -using System.Diagnostics; -using System.IO; -using Microsoft.Win32; - -namespace DeskCoreSetup; - -/// Installation/Deinstallation – nur für den aktuellen Benutzer, ohne Administratorrechte. -public static class Installer -{ - public const string AppName = "DeskCore"; - public const string Publisher = "M_Viper"; - public const string ExeName = "DeskCore.exe"; - public const string UninstallerName = "DeskCore-Uninstall.exe"; - private const string UninstallKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall\DeskCore"; - private const string RunKey = @"Software\Microsoft\Windows\CurrentVersion\Run"; - - public static string Version - { - get - { - var v = typeof(Installer).Assembly.GetName().Version!; - return $"{v.Major}.{v.Minor}.{v.Build}"; - } - } - - /// Pfad dieses Setups (auch als Deinstallationsprogramm). - public static string SelfPath => System.Reflection.Assembly.GetExecutingAssembly().Location; - - public static string DefaultDir => - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Programs", AppName); - - private static string StartMenuLink => - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), AppName + ".lnk"); - - private static string DesktopLink => - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), AppName + ".lnk"); - - /// Ordner einer vorhandenen Installation (oder null). - public static string? InstalledDir - { - get - { - using var k = Registry.CurrentUser.OpenSubKey(UninstallKey); - return k?.GetValue("InstallLocation") as string is { } d && File.Exists(Path.Combine(d, ExeName)) ? d : null; - } - } - - public static string? InstalledVersion - { - get - { - using var k = Registry.CurrentUser.OpenSubKey(UninstallKey); - return k?.GetValue("DisplayVersion") as string; - } - } - - public static bool AutostartEnabled - { - get - { - using var k = Registry.CurrentUser.OpenSubKey(RunKey); - return k?.GetValue(AppName) is string; - } - } - - public static bool DesktopLinkExists => File.Exists(DesktopLink); - - public static string LicenseText => ReadResourceText("payload.LICENSE.txt"); - - // ---------- Installieren ---------- - - public static void Install(string dir, bool desktopLink, bool autostart, IProgress<(double, string)> progress, - bool installRuntime = false) - { - if (!Runtime.Is64BitWindows) - throw new InvalidOperationException("DeskCore benötigt ein 64-Bit-Windows (Windows 10 oder 11)."); - if (installRuntime && !Runtime.IsInstalled) - { - // 0–60 % für die Laufzeit, Rest für DeskCore - Runtime.Install((v, text) => progress.Report((v * 0.6, text))); - var inner = progress; - progress = new Scaled(inner, 0.6, 0.4); - } - - progress.Report((0.05, "DeskCore wird beendet …")); - CloseRunningApp(); - RemoveLegacyInstall(); - - progress.Report((0.2, "Dateien werden kopiert …")); - Directory.CreateDirectory(dir); - var exe = Path.Combine(dir, ExeName); - WriteResource("payload.DeskCore.exe", exe); - WriteResource("payload.LICENSE.txt", Path.Combine(dir, "LICENSE.txt")); - - // Setup selbst als Deinstallationsprogramm ablegen - var self = SelfPath; - var uninstaller = Path.Combine(dir, UninstallerName); - if (!string.Equals(Path.GetFullPath(self), Path.GetFullPath(uninstaller), StringComparison.OrdinalIgnoreCase)) - { - MoveAside(uninstaller); - File.Copy(self, uninstaller, overwrite: true); - } - - progress.Report((0.55, "Verknüpfungen werden angelegt …")); - CreateShortcut(StartMenuLink, exe); - if (desktopLink) CreateShortcut(DesktopLink, exe); - - progress.Report((0.75, "Windows wird eingerichtet …")); - using (var run = Registry.CurrentUser.CreateSubKey(RunKey)) - { - if (autostart) run.SetValue(AppName, $"\"{exe}\" --minimized"); - else run.DeleteValue(AppName, throwOnMissingValue: false); - } - - using (var k = Registry.CurrentUser.CreateSubKey(UninstallKey)) - { - long size = new[] { exe, uninstaller, Path.Combine(dir, "LICENSE.txt") } - .Where(File.Exists).Sum(f => new FileInfo(f).Length) / 1024; - k.SetValue("DisplayName", AppName); - k.SetValue("DisplayVersion", Version); - k.SetValue("Publisher", Publisher); - k.SetValue("DisplayIcon", $"{exe},0"); - k.SetValue("InstallLocation", dir); - k.SetValue("UninstallString", $"\"{uninstaller}\" --uninstall"); - k.SetValue("QuietUninstallString", $"\"{uninstaller}\" --uninstall /S"); - k.SetValue("URLInfoAbout", "https://m-viper.de"); - k.SetValue("InstallDate", DateTime.Now.ToString("yyyyMMdd")); - k.SetValue("EstimatedSize", (int)size, RegistryValueKind.DWord); - k.SetValue("NoModify", 1, RegistryValueKind.DWord); - k.SetValue("NoRepair", 1, RegistryValueKind.DWord); - } - - progress.Report((1.0, "Fertig")); - } - - // ---------- Frühere Version "DeskHub" entfernen ---------- - - private const string LegacyName = "DeskHub"; - private const string LegacyUninstallKey = @"Software\Microsoft\Windows\CurrentVersion\Uninstall\DeskHub"; - - /// Ordner einer alten Installation unter dem früheren Namen "DeskHub" – nur unsere eigene. - public static string? LegacyInstallDir - { - get - { - using var k = Registry.CurrentUser.OpenSubKey(LegacyUninstallKey); - // "DeskHub" heißt auch ein anderes Programm → nur mit unserem Herausgeber anfassen - if (k?.GetValue("Publisher") as string != Publisher) return null; - return k.GetValue("InstallLocation") as string; - } - } - - private static void RemoveLegacyInstall() - { - var dir = LegacyInstallDir; - if (dir is null) return; - var exe = Path.Combine(dir, LegacyName + ".exe"); - - // nur Prozesse beenden, die wirklich aus dem alten Ordner laufen - foreach (var p in Process.GetProcessesByName(LegacyName)) - { - try - { - if (p.MainModule?.FileName is { } f && Storage_IsUnder(f, dir)) - { - p.Kill(); - p.WaitForExit(10000); - } - } - catch { } - } - - DeleteIfPointsTo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Programs), LegacyName + ".lnk"), exe); - DeleteIfPointsTo(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory), LegacyName + ".lnk"), exe); - using (var run = Registry.CurrentUser.OpenSubKey(RunKey, writable: true)) - { - if (run?.GetValue(LegacyName) is string cmd && cmd.IndexOf(exe, StringComparison.OrdinalIgnoreCase) >= 0) - run.DeleteValue(LegacyName, throwOnMissingValue: false); - } - - foreach (var f in new[] { exe, Path.Combine(dir, "LICENSE.txt"), Path.Combine(dir, LegacyName + "-Uninstall.exe") }) - MoveAside(f); - CleanupOldFiles(dir); - try { Directory.Delete(dir); } catch { } // nur wenn leer - Registry.CurrentUser.DeleteSubKeyTree(LegacyUninstallKey, throwOnMissingSubKey: false); - } - - // ---------- Deinstallieren ---------- - - public static readonly string[] DataDirs = - [ - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), AppName), // Kategorien - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), AppName), // Einstellungen - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), AppName), // Rückgängig-Zwischenablage - ]; - - public static void Uninstall(bool removeData, IProgress<(double, string)> progress) - { - // Nur im eingetragenen Installationsordner löschen – nie dort, wo das Setup zufällig liegt (z. B. Downloads) - var dir = InstalledDir; - var exe = dir is null ? "" : Path.Combine(dir, ExeName); - - progress.Report((0.1, "DeskCore wird beendet …")); - CloseRunningApp(); - - progress.Report((0.3, "Verknüpfungen werden entfernt …")); - DeleteIfPointsTo(StartMenuLink, exe); - DeleteIfPointsTo(DesktopLink, exe); - - progress.Report((0.45, "Windows-Einträge werden entfernt …")); - using (var run = Registry.CurrentUser.OpenSubKey(RunKey, writable: true)) - run?.DeleteValue(AppName, throwOnMissingValue: false); - Registry.CurrentUser.DeleteSubKeyTree(UninstallKey, throwOnMissingSubKey: false); - - if (removeData) - { - progress.Report((0.6, "Kategorien und Einstellungen werden in den Papierkorb gelegt …")); - foreach (var d in DataDirs.Where(Directory.Exists)) - { - try - { - Microsoft.VisualBasic.FileIO.FileSystem.DeleteDirectory(d, - Microsoft.VisualBasic.FileIO.UIOption.OnlyErrorDialogs, - Microsoft.VisualBasic.FileIO.RecycleOption.SendToRecycleBin); - } - catch { } - } - } - - progress.Report((0.85, "Dateien werden entfernt …")); - if (dir is null) { progress.Report((1.0, "Fertig")); return; } - TryDelete(exe); - TryDelete(Path.Combine(dir, "LICENSE.txt")); - CleanupOldFiles(dir); - - // Das laufende Deinstallationsprogramm kann sich nicht selbst löschen → kurz nach dem Beenden per cmd. - // rmdir ohne /s entfernt den Ordner nur, wenn er danach leer ist. - var self = SelfPath; - if (Storage_IsUnder(self, dir)) - { - Process.Start(new ProcessStartInfo("cmd.exe", - $"/c ping 127.0.0.1 -n 3 > nul & del /f /q \"{self}\" & del /f /q \"{Path.Combine(dir, "*.old")}\" & rmdir \"{dir}\"") - { - CreateNoWindow = true, UseShellExecute = false, WindowStyle = ProcessWindowStyle.Hidden, - }); - } - else - { - TryDelete(Path.Combine(dir, UninstallerName)); - try { Directory.Delete(dir); } catch { } // nur wenn leer - } - progress.Report((1.0, "Fertig")); - } - - // ---------- Helfer ---------- - - /// Rechnet Fortschritt 0–1 in einen Teilbereich um. - private sealed class Scaled(IProgress<(double, string)> inner, double offset, double factor) : IProgress<(double, string)> - { - public void Report((double, string) value) => inner.Report((offset + value.Item1 * factor, value.Item2)); - } - - /// Laufendes DeskCore beenden (das X versteckt es nur im Infobereich). - private static void CloseRunningApp() - { - foreach (var p in Process.GetProcessesByName("DeskCore")) - { - try - { - p.Kill(); - p.WaitForExit(10000); - } - catch { } - } - } - - private static void WriteResource(string name, string path) - { - CleanupOldFiles(Path.GetDirectoryName(path)!); - MoveAside(path); - for (int attempt = 1; ; attempt++) - { - try - { - using var s = typeof(Installer).Assembly.GetManifestResourceStream(name) - ?? throw new InvalidOperationException($"Installationsdatei {name} fehlt."); - using var f = File.Create(path); - s.CopyTo(f); - return; - } - catch (IOException) when (attempt < 10) - { - Thread.Sleep(500); - } - catch (IOException) when (attempt >= 10) - { - throw new IOException($"„{Path.GetFileName(path)}“ wird noch verwendet. Bitte DeskCore beenden (Rechtsklick auf das Symbol im Infobereich → Beenden) und erneut versuchen."); - } - } - } - - /// - /// Vorhandene Datei beiseite umbenennen. Das klappt unter Windows auch dann, wenn sie noch geöffnet ist - /// (z. B. vom Explorer für das Icon oder vom Virenscanner) – überschreiben würde dagegen fehlschlagen. - /// - private static void MoveAside(string path) - { - if (!File.Exists(path)) return; - try { File.Delete(path); return; } catch { } - try { File.Move(path, $"{path}.{Guid.NewGuid():N}.old"); } catch { } - } - - /// Beiseitegelegte Dateien früherer Installationen wegräumen (sofern nicht mehr in Benutzung). - private static void CleanupOldFiles(string dir) - { - if (!Directory.Exists(dir)) return; - foreach (var f in Directory.GetFiles(dir, "*.old")) - try { File.Delete(f); } catch { } - } - - private static string ReadResourceText(string name) - { - using var s = typeof(Installer).Assembly.GetManifestResourceStream(name); - if (s is null) return ""; - using var r = new StreamReader(s); - return r.ReadToEnd().Trim(); - } - - private static void CreateShortcut(string link, string target) - { - Directory.CreateDirectory(Path.GetDirectoryName(link)!); - dynamic shell = Activator.CreateInstance(Type.GetTypeFromProgID("WScript.Shell")!)!; - dynamic lnk = shell.CreateShortcut(link); - lnk.TargetPath = target; - lnk.WorkingDirectory = Path.GetDirectoryName(target); - lnk.IconLocation = $"{target},0"; - lnk.Description = "Desktop-Icons in Kategorien sortieren"; - lnk.Save(); - } - - private static void DeleteIfPointsTo(string link, string target) - { - if (!File.Exists(link)) return; - try - { - dynamic shell = Activator.CreateInstance(Type.GetTypeFromProgID("WScript.Shell")!)!; - string t = shell.CreateShortcut(link).TargetPath; - if (!string.Equals(t, target, StringComparison.OrdinalIgnoreCase)) return; - } - catch { return; } - // Explorer/Indexdienst halten Verknüpfungen manchmal kurz fest → mehrmals versuchen - for (int i = 0; i < 10 && File.Exists(link); i++) - { - try { File.Delete(link); } - catch { Thread.Sleep(300); } - } - } - - private static void TryDelete(string path) - { - try { if (File.Exists(path)) File.Delete(path); } catch { } - } - - private static bool Storage_IsUnder(string path, string dir) => - (Path.GetFullPath(path)).StartsWith(Path.GetFullPath(dir).TrimEnd('\\') + "\\", StringComparison.OrdinalIgnoreCase); - - public static long DataSize() - { - long sum = 0; - foreach (var d in DataDirs.Where(Directory.Exists)) - { - try - { - foreach (var f in Directory.EnumerateFiles(d, "*", SearchOption.AllDirectories)) - try { sum += new FileInfo(f).Length; } catch { } - } - catch { } - } - return sum; - } - - public static string FormatSize(long bytes) => bytes switch - { - < 1024 * 1024 => $"{Math.Max(1, bytes / 1024)} KB", - < 1024L * 1024 * 1024 => $"{bytes / 1024.0 / 1024:0.#} MB", - _ => $"{bytes / 1024.0 / 1024 / 1024:0.##} GB", - }; -}