From 28f41cd27c09a40fa0854742cae8288154f6b689 Mon Sep 17 00:00:00 2001 From: lincube Date: Fri, 24 Apr 2026 10:05:30 +0800 Subject: [PATCH] Resolve dev paths and fix splash UI thread Compute a solutionRoot and expand development search paths (LanMountainDesktop and dev-test) in DeploymentLocator, add logging when scanning/finding hosts, and return distinct full paths. Ensure backward-compatible path checks. Fix cross-thread UI calls: invoke splashWindow.DismissAsync on the UI thread in LauncherFlowCoordinator, and make SplashWindow.DismissAsync ensure it runs on the UI thread before closing (simplified Close call). These changes improve development host discovery and prevent UI-thread access issues during shutdown. --- .../Services/DeploymentLocator.cs | 46 +++++++++++-------- .../Services/LauncherFlowCoordinator.cs | 2 +- .../Views/SplashWindow.axaml.cs | 16 ++++--- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs b/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs index 81e041b..15e4c85 100644 --- a/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs +++ b/LanMountainDesktop.Launcher/Services/DeploymentLocator.cs @@ -1,4 +1,4 @@ -using System.Globalization; +using System.Globalization; using System.Text.Json; using LanMountainDesktop.Launcher.Models; using LanMountainDesktop.Shared.Contracts.Launcher; @@ -360,51 +360,59 @@ internal sealed class DeploymentLocator /// private static string? ScanDevelopmentPaths(string executable) { + var solutionRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", "..", "..")); + var possiblePaths = new[] { - // 浠?Launcher 椤圭洰杩愯 + // 标准开发路径:解决方案根目录下的 LanMountainDesktop 项目 + Path.Combine(solutionRoot, "LanMountainDesktop", "bin", "Debug", "net10.0", executable), + Path.Combine(solutionRoot, "LanMountainDesktop", "bin", "Release", "net10.0", executable), + + // 向后兼容 Path.Combine(AppContext.BaseDirectory, "..", "..", "LanMountainDesktop", "bin", "Debug", "net10.0", executable), Path.Combine(AppContext.BaseDirectory, "..", "..", "LanMountainDesktop", "bin", "Release", "net10.0", executable), - // 浠庤В鍐虫柟妗堟牴鐩綍杩愯 - Path.Combine(AppContext.BaseDirectory, "..", "LanMountainDesktop", "bin", "Debug", "net10.0", executable), - Path.Combine(AppContext.BaseDirectory, "..", "LanMountainDesktop", "bin", "Release", "net10.0", executable), - - // dev-test 鐩綍 - Path.Combine(AppContext.BaseDirectory, "..", "dev-test", "app-1.0.0-dev", executable), + // dev-test 目录 + Path.Combine(solutionRoot, "dev-test", "app-1.0.0-dev", executable), }; foreach (var path in possiblePaths.Select(Path.GetFullPath).Distinct()) { + Logger.Info($"Scanning development path: {path}"); if (File.Exists(path)) { + Logger.Info($"Found host at: {path}"); return path; } } return null; - } - + } + /// - /// 鑾峰彇寮€鍙戠幆澧冨彲鑳界殑涓荤▼搴忚矾寰? /// + /// 鑾峰彇寮€鍙戞ā寮忥細鏌ユ壘涓荤▼搴忚経 + /// private static IEnumerable GetDevelopmentPaths(string executable) { var launcherDir = AppContext.BaseDirectory; + // 计算解决方案根目录:从 LanMountainDesktop.Launcher\bin\Debug\net10.0\ 向上4级 + var solutionRoot = Path.GetFullPath(Path.Combine(launcherDir, "..", "..", "..", "..")); + var possiblePaths = new[] { - // 浠?Launcher 椤圭洰杩愯锛?.\LanMountainDesktop\bin\Debug\net10.0\LanMountainDesktop.exe + // 标准开发路径:解决方案根目录下的 LanMountainDesktop 项目 + Path.Combine(solutionRoot, "LanMountainDesktop", "bin", "Debug", "net10.0", executable), + Path.Combine(solutionRoot, "LanMountainDesktop", "bin", "Release", "net10.0", executable), + + // 向后兼容:如果 Launcher 在特殊目录结构中 Path.Combine(launcherDir, "..", "..", "LanMountainDesktop", "bin", "Debug", "net10.0", executable), Path.Combine(launcherDir, "..", "..", "LanMountainDesktop", "bin", "Release", "net10.0", executable), - // 浠庤В鍐虫柟妗堟牴鐩綍杩愯锛歀anMountainDesktop\bin\Debug\net10.0\LanMountainDesktop.exe - Path.Combine(launcherDir, "..", "LanMountainDesktop", "bin", "Debug", "net10.0", executable), - Path.Combine(launcherDir, "..", "LanMountainDesktop", "bin", "Release", "net10.0", executable), - - // 浠?dev-test 鐩綍杩愯 - Path.Combine(launcherDir, "..", "dev-test", "app-1.0.0-dev", executable), + // dev-test 目录 + Path.Combine(solutionRoot, "dev-test", "app-1.0.0-dev", executable), }; - + return possiblePaths.Select(Path.GetFullPath).Distinct(); } diff --git a/LanMountainDesktop.Launcher/Services/LauncherFlowCoordinator.cs b/LanMountainDesktop.Launcher/Services/LauncherFlowCoordinator.cs index fc49cbd..a17558b 100644 --- a/LanMountainDesktop.Launcher/Services/LauncherFlowCoordinator.cs +++ b/LanMountainDesktop.Launcher/Services/LauncherFlowCoordinator.cs @@ -955,7 +955,7 @@ internal sealed class LauncherFlowCoordinator { try { - await splashWindow.DismissAsync().ConfigureAwait(false); + await Dispatcher.UIThread.InvokeAsync(() => splashWindow.DismissAsync()); } catch (Exception ex) { diff --git a/LanMountainDesktop.Launcher/Views/SplashWindow.axaml.cs b/LanMountainDesktop.Launcher/Views/SplashWindow.axaml.cs index 1657024..d6b91db 100644 --- a/LanMountainDesktop.Launcher/Views/SplashWindow.axaml.cs +++ b/LanMountainDesktop.Launcher/Views/SplashWindow.axaml.cs @@ -79,6 +79,14 @@ public partial class SplashWindow : Window, ISplashStageReporter } _dismissed = true; + + // 确保在UI线程上执行 + if (!Dispatcher.UIThread.CheckAccess()) + { + await Dispatcher.UIThread.InvokeAsync(async () => await DismissAsync()); + return; + } + ConfigureForVisualMode(); if (_mode == StartupVisualMode.SlideSplash) @@ -91,13 +99,7 @@ public partial class SplashWindow : Window, ISplashStageReporter await AnimateOpacityAsync(Opacity, 0d, FadeAnimationDuration).ConfigureAwait(false); } - await Dispatcher.UIThread.InvokeAsync(() => - { - if (IsVisible) - { - Close(); - } - }); + Close(); } public void Report(string stage, string message)