using System.Runtime.InteropServices; using Windows.ApplicationModel; using YMhut.Box.Core.App; namespace YMhut.Box.WinUI.Services; internal static class RuntimeLayoutBootstrapper { public static bool TryRelaunchFromWritableLayoutIfNeeded() { try { CleanupLegacyPersistentRuntime(); if (IsPackaged() || !RequiresLegacyCompressedLayout(AppContext.BaseDirectory)) { return false; } const string title = "YMhut Box 启动失败"; var message = "检测到旧版压缩语言资源布局,YMhut Box 不再把运行时复制到用户目录。\n\n" + "请使用新版安装包覆盖安装。安装引导程序会清理旧布局并重新铺设程序文件。\n\n" + "This installation still uses the legacy compressed language layout. YMhut Box no longer creates a persistent runtime copy under LocalAppData. Please reinstall with the latest setup package."; CrashLog.Write(message); ShowStartupError(title, message); return true; } catch (Exception exception) { CrashLog.Write(exception); return false; } } public static string InstalledExecutablePath => InstallLayoutPaths.ResolveInstalledExecutablePath(); public static string InstalledWorkingDirectory => Path.GetDirectoryName(InstalledExecutablePath) ?? AppContext.BaseDirectory; private static bool RequiresLegacyCompressedLayout(string directory) { var legacyLangRoot = Path.Combine(directory, "resources", "lang"); return Directory.Exists(legacyLangRoot) && Directory.EnumerateFiles(legacyLangRoot, "*.bin", SearchOption.TopDirectoryOnly).Any() && !HasPureLangSatelliteResources(directory); } private static bool HasPureLangSatelliteResources(string directory) { var langRoot = Path.Combine(directory, "lang"); if (!Directory.Exists(langRoot)) { return false; } foreach (var culture in new[] { "zh-CN", "en-US" }) { var cultureRoot = Path.Combine(langRoot, culture); if (!Directory.Exists(cultureRoot)) { return false; } if (!Directory.EnumerateFiles(cultureRoot, "*.mui", SearchOption.AllDirectories).Any() && !Directory.EnumerateFiles(cultureRoot, "*.resources.dll", SearchOption.AllDirectories).Any()) { return false; } } return true; } private static void CleanupLegacyPersistentRuntime() { var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); var legacyRoots = new[] { Path.Combine(localAppData, "YMhut Box", "WinUI"), Path.Combine(localAppData, "YMhut Box"), Path.Combine(localAppData, "ymhut_box") }; foreach (var root in legacyRoots) { foreach (var name in AppPaths.RuntimePayloadDirectoryNames) { TryDeleteDirectory(Path.Combine(root, name)); } } } private static void TryDeleteDirectory(string directory) { try { if (Directory.Exists(directory)) { Directory.Delete(directory, recursive: true); } } catch (Exception exception) { CrashLog.Write($"Unable to remove legacy runtime directory '{directory}': {exception.Message}"); } } private static bool IsPackaged() { try { _ = Package.Current.Id.FullName; return true; } catch { return false; } } private static void ShowStartupError(string title, string message) { try { _ = MessageBoxW(IntPtr.Zero, message, title, 0x00000010); } catch { } } [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = false)] private static extern int MessageBoxW(IntPtr hWnd, string text, string caption, uint type); }