using System.Diagnostics; using Microsoft.Win32; namespace LanMountainDesktop.Launcher.Services; /// /// 老版本检测器 - 检测 0.8.x 及更早的单应用模式安装 /// internal sealed class LegacyVersionDetector { private const string LegacyAppName = "LanMountainDesktop"; private const string LegacyExeName = "LanMountainDesktop.exe"; /// /// 检测是否存在老版本安装 /// public static LegacyVersionInfo? DetectLegacyInstallation() { // 1. 检查注册表(安装版) var registryInfo = DetectFromRegistry(); if (registryInfo != null) { return registryInfo; } // 2. 检查常见安装目录 var commonPaths = DetectFromCommonPaths(); if (commonPaths != null) { return commonPaths; } // 3. 检查便携版位置 var portableInfo = DetectPortableInstallation(); if (portableInfo != null) { return portableInfo; } return null; } /// /// 从注册表检测安装信息 /// private static LegacyVersionInfo? DetectFromRegistry() { try { // 检查 HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall using var key = Registry.LocalMachine.OpenSubKey( @$"Software\Microsoft\Windows\CurrentVersion\Uninstall\{LegacyAppName}"); if (key != null) { var installLocation = key.GetValue("InstallLocation") as string; var displayVersion = key.GetValue("DisplayVersion") as string; var uninstallString = key.GetValue("UninstallString") as string; if (!string.IsNullOrWhiteSpace(installLocation) && File.Exists(Path.Combine(installLocation, LegacyExeName))) { return new LegacyVersionInfo { Version = displayVersion ?? "0.8.x", InstallPath = installLocation, UninstallCommand = uninstallString, InstallType = LegacyInstallType.Registry }; } } // 检查 HKCU(用户级安装) using var userKey = Registry.CurrentUser.OpenSubKey( @$"Software\Microsoft\Windows\CurrentVersion\Uninstall\{LegacyAppName}"); if (userKey != null) { var installLocation = userKey.GetValue("InstallLocation") as string; var displayVersion = userKey.GetValue("DisplayVersion") as string; var uninstallString = userKey.GetValue("UninstallString") as string; if (!string.IsNullOrWhiteSpace(installLocation) && File.Exists(Path.Combine(installLocation, LegacyExeName))) { return new LegacyVersionInfo { Version = displayVersion ?? "0.8.x", InstallPath = installLocation, UninstallCommand = uninstallString, InstallType = LegacyInstallType.Registry }; } } } catch (Exception ex) { Console.WriteLine($"[LegacyVersionDetector] Registry detection failed: {ex.Message}"); } return null; } /// /// 从常见安装路径检测 /// private static LegacyVersionInfo? DetectFromCommonPaths() { var commonPaths = new[] { Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), LegacyAppName), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), LegacyAppName), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), LegacyAppName), Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), LegacyAppName), }; foreach (var path in commonPaths) { try { if (Directory.Exists(path)) { // 检查是否存在老版本的特征文件(没有 app-* 目录) var exePath = Path.Combine(path, LegacyExeName); var hasAppDirs = Directory.GetDirectories(path, "app-*").Length > 0; if (File.Exists(exePath) && !hasAppDirs) { // 尝试读取版本信息 var version = TryGetFileVersion(exePath); return new LegacyVersionInfo { Version = version ?? "0.8.x", InstallPath = path, UninstallCommand = FindUninstaller(path), InstallType = LegacyInstallType.CommonPath }; } } } catch (Exception ex) { Console.WriteLine($"[LegacyVersionDetector] Path detection failed for {path}: {ex.Message}"); } } return null; } /// /// 检测便携版安装 /// private static LegacyVersionInfo? DetectPortableInstallation() { try { // 检查启动器所在目录的父目录(便携版常见布局) var launcherDir = AppContext.BaseDirectory; var parentDir = Path.GetFullPath(Path.Combine(launcherDir, "..")); if (Directory.Exists(parentDir)) { var exePath = Path.Combine(parentDir, LegacyExeName); var hasAppDirs = Directory.GetDirectories(parentDir, "app-*").Length > 0; // 如果存在 exe 且没有 app-* 目录,可能是老版本 if (File.Exists(exePath) && !hasAppDirs) { var version = TryGetFileVersion(exePath); // 检查是否真的是老版本(通过文件版本或特定标记) if (IsLegacyVersion(version)) { return new LegacyVersionInfo { Version = version ?? "0.8.x", InstallPath = parentDir, UninstallCommand = null, // 便携版没有卸载程序 InstallType = LegacyInstallType.Portable }; } } } } catch (Exception ex) { Console.WriteLine($"[LegacyVersionDetector] Portable detection failed: {ex.Message}"); } return null; } /// /// 查找卸载程序 /// private static string? FindUninstaller(string installPath) { try { // 常见的卸载程序命名 var uninstallerNames = new[] { "unins000.exe", "uninstall.exe", "Uninstall.exe" }; foreach (var name in uninstallerNames) { var path = Path.Combine(installPath, name); if (File.Exists(path)) { return path; } } } catch { } return null; } /// /// 获取文件版本 /// private static string? TryGetFileVersion(string filePath) { try { var versionInfo = FileVersionInfo.GetVersionInfo(filePath); return versionInfo.FileVersion; } catch { return null; } } /// /// 判断是否为老版本(版本号 < 1.0.0) /// private static bool IsLegacyVersion(string? version) { if (string.IsNullOrWhiteSpace(version)) { return true; // 无法确定版本时,保守认为是老版本 } if (Version.TryParse(version.Split(' ')[0], out var v)) { return v.Major < 1; } return true; } /// /// 打开卸载界面 /// public static void OpenUninstallInterface(LegacyVersionInfo info) { try { if (!string.IsNullOrWhiteSpace(info.UninstallCommand)) { // 有卸载命令,直接执行 var parts = info.UninstallCommand.Split(new[] { ' ' }, 2); var fileName = parts[0].Trim('"'); var arguments = parts.Length > 1 ? parts[1] : ""; Logger.Info( $"Opening legacy uninstall interface with elevation reason 'legacy_uninstall'. " + $"InstallPath='{info.InstallPath}'; Version='{info.Version}'."); Process.Start(new ProcessStartInfo { FileName = fileName, Arguments = arguments, UseShellExecute = true, Verb = "runas" // 请求管理员权限 }); } else { // 没有卸载命令,打开系统卸载面板 Process.Start(new ProcessStartInfo { FileName = "appwiz.cpl", UseShellExecute = true }); } } catch (Exception ex) { Console.Error.WriteLine($"[LegacyVersionDetector] Failed to open uninstall: {ex.Message}"); // 兜底:打开系统卸载面板 try { Process.Start(new ProcessStartInfo { FileName = "appwiz.cpl", UseShellExecute = true }); } catch { } } } /// /// 在资源管理器中显示老版本位置 /// public static void ShowInExplorer(string path) { try { Process.Start(new ProcessStartInfo { FileName = "explorer.exe", Arguments = $"/select,\"{path}\"", UseShellExecute = false }); } catch (Exception ex) { Console.Error.WriteLine($"[LegacyVersionDetector] Failed to show in explorer: {ex.Message}"); } } } /// /// 老版本信息 /// public class LegacyVersionInfo { public string Version { get; set; } = "0.8.x"; public string InstallPath { get; set; } = ""; public string? UninstallCommand { get; set; } public LegacyInstallType InstallType { get; set; } } /// /// 老版本安装类型 /// public enum LegacyInstallType { Registry, // 注册表安装版 CommonPath, // 常见路径安装 Portable // 便携版 }