diff --git a/ProjBobcat/ProjBobcat/Class/Helper/FileTypeHelper.cs b/ProjBobcat/ProjBobcat/Class/Helper/FileTypeHelper.cs index 59aa670..0f7d593 100644 --- a/ProjBobcat/ProjBobcat/Class/Helper/FileTypeHelper.cs +++ b/ProjBobcat/ProjBobcat/Class/Helper/FileTypeHelper.cs @@ -24,9 +24,9 @@ public static async Task TryDetectFileTypeAsync(string filePath) await using var fs = File.OpenRead(filePath); using var archive = ArchiveFactory.Open(fs); - if (archive.Entries.Any(e => e.Key.Equals("manifest.json", StringComparison.OrdinalIgnoreCase))) + if (archive.Entries.Any(e => e.Key?.Equals("manifest.json", StringComparison.OrdinalIgnoreCase) ?? false)) return AssetFileType.CurseForgeModPack; - if (archive.Entries.Any(e => e.Key.Equals("modrinth.index.json", StringComparison.OrdinalIgnoreCase))) + if (archive.Entries.Any(e => e.Key?.Equals("modrinth.index.json", StringComparison.OrdinalIgnoreCase) ?? false)) return AssetFileType.ModrinthModPack; break; } diff --git a/ProjBobcat/ProjBobcat/Class/Helper/GameResourcesResolveHelper.cs b/ProjBobcat/ProjBobcat/Class/Helper/GameResourcesResolveHelper.cs index cc29791..c21fa07 100644 --- a/ProjBobcat/ProjBobcat/Class/Helper/GameResourcesResolveHelper.cs +++ b/ProjBobcat/ProjBobcat/Class/Helper/GameResourcesResolveHelper.cs @@ -147,19 +147,19 @@ static async Task GetFabricModInfo( public static ModLoaderType GetModLoaderType(IArchive archive) { var fabricEntry = archive.Entries.Any(e => - e.Key.EndsWith("fabric.mod.json", StringComparison.OrdinalIgnoreCase)); + e.Key?.EndsWith("fabric.mod.json", StringComparison.OrdinalIgnoreCase) ?? false); if (fabricEntry) return ModLoaderType.Fabric; var neoforgeEntry = archive.Entries.Any(e => - e.Key.EndsWith("_neoforge.mixins.json", StringComparison.OrdinalIgnoreCase)); + e.Key?.EndsWith("_neoforge.mixins.json", StringComparison.OrdinalIgnoreCase) ?? false); if (neoforgeEntry) return ModLoaderType.NeoForge; var forgeEntry = archive.Entries.Any(e => - e.Key.EndsWith("META-INF/mods.toml", StringComparison.OrdinalIgnoreCase)); + e.Key?.EndsWith("META-INF/mods.toml", StringComparison.OrdinalIgnoreCase) ?? false); var forgeNewEntry = archive.Entries.Any(e => - e.Key.EndsWith("mcmod.info", StringComparison.OrdinalIgnoreCase)); + e.Key?.EndsWith("mcmod.info", StringComparison.OrdinalIgnoreCase) ?? false); if (forgeEntry || forgeNewEntry) return ModLoaderType.Forge; @@ -184,13 +184,13 @@ public static async IAsyncEnumerable ResolveModListAsync( var modInfoEntry = archive.Entries.FirstOrDefault(e => - e.Key.Equals("mcmod.info", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("mcmod.info", StringComparison.OrdinalIgnoreCase) ?? false); var fabricModInfoEntry = archive.Entries.FirstOrDefault(e => - e.Key.Equals("fabric.mod.json", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("fabric.mod.json", StringComparison.OrdinalIgnoreCase) ?? false); var tomlInfoEntry = archive.Entries.FirstOrDefault(e => - e.Key.Equals("META-INF/mods.toml", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("META-INF/mods.toml", StringComparison.OrdinalIgnoreCase) ?? false); var isEnabled = ext.Equals(".jar", StringComparison.OrdinalIgnoreCase); @@ -249,9 +249,9 @@ public static async IAsyncEnumerable ResolveModListAsync( if (!ArchiveHelper.TryOpen(file, out var archive)) return null; var packIconEntry = - archive.Entries.FirstOrDefault(e => e.Key.Equals("pack.png", StringComparison.OrdinalIgnoreCase)); + archive.Entries.FirstOrDefault(e => e.Key?.Equals("pack.png", StringComparison.OrdinalIgnoreCase) ?? false); var packInfoEntry = archive.Entries.FirstOrDefault(e => - e.Key.Equals("pack.mcmeta", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("pack.mcmeta", StringComparison.OrdinalIgnoreCase) ?? false); var fileName = Path.GetFileName(file); byte[]? imageBytes; @@ -357,8 +357,11 @@ public static async IAsyncEnumerable ResolveResour static GameShaderPackResolvedInfo? ResolveShaderPackFile(string file) { if (!ArchiveHelper.TryOpen(file, out var archive)) return null; - if (!archive.Entries.Any(e => e.Key.StartsWith("shaders/", StringComparison.OrdinalIgnoreCase))) - return null; + if (archive == null) return null; + if (!archive.Entries.Any(e => + Path.GetFileName(e.Key?.TrimEnd(Path.DirectorySeparatorChar)) + ?.Equals("shaders", StringComparison.OrdinalIgnoreCase) ?? false)) + return null; var model = new GameShaderPackResolvedInfo(Path.GetFileName(file), false); diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Authenticator/MicrosoftAuthenticator.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Authenticator/MicrosoftAuthenticator.cs index c7c8984..fc5acb4 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Authenticator/MicrosoftAuthenticator.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Authenticator/MicrosoftAuthenticator.cs @@ -449,7 +449,7 @@ public static void Configure(MicrosoftAuthenticatorAPISettings apiSettings) GraphAuthResultModel? result; while (true) { - await Task.Delay(TimeSpan.FromSeconds(deviceTokenResModel.Interval)); + await Task.Delay(TimeSpan.FromSeconds(deviceTokenResModel.Interval + 2)); using var userAuthResultReq = new HttpRequestMessage(HttpMethod.Post, MSDeviceTokenStatusUrl) { @@ -482,15 +482,6 @@ public static void Configure(MicrosoftAuthenticatorAPISettings apiSettings) return result; } - public static string GetLoginUri(string clientId, string redirectUri) - { - return Uri.EscapeDataString("https://login.live.com/oauth20_authorize.srf" - + $"?client_id={clientId}" - + "&response_type=code" - + $"&scope={MSAuthScope}" - + $"&redirect_uri={redirectUri}"); - } - static async Task SendRequest(string url, TReq model, JsonTypeInfo typeInfo, JsonTypeInfo reqTypeInfo) { diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/ForgeInstallerFactory.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/ForgeInstallerFactory.cs index 701fee8..2a54a86 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/ForgeInstallerFactory.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/ForgeInstallerFactory.cs @@ -27,9 +27,9 @@ public static bool IsLegacyForgeInstaller(string forgeExecutable, string forgeVe using var archive = ArchiveFactory.Open(Path.GetFullPath(forgeExecutable)); var legacyUniversalJar = - archive.Entries.Any(entry => entry.Key.Equals($"forge-{forgeVersion}-universal.jar")); + archive.Entries.Any(entry => entry.Key?.Equals($"forge-{forgeVersion}-universal.jar") ?? false); var installProfileJson = archive.Entries.Any(entry => - entry.Key.Equals("install_profile.json", StringComparison.OrdinalIgnoreCase)); + entry.Key?.Equals("install_profile.json", StringComparison.OrdinalIgnoreCase) ?? false); return legacyUniversalJar && installProfileJson; } diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs index 87175f5..387288a 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/HighVersionForgeInstaller.cs @@ -94,7 +94,7 @@ public async Task InstallForgeTaskAsync() InvokeStatusChangedEvent("解析 Version.json", 0.1); var versionJsonEntry = - archive.Entries.FirstOrDefault(e => e.Key.Equals("version.json", StringComparison.OrdinalIgnoreCase)); + archive.Entries.FirstOrDefault(e => e.Key?.Equals("version.json", StringComparison.OrdinalIgnoreCase) ?? false); if (versionJsonEntry == default) return GetCorruptedFileResult(); @@ -127,7 +127,7 @@ public async Task InstallForgeTaskAsync() var installProfileEntry = archive.Entries.FirstOrDefault(e => - e.Key.Equals("install_profile.json", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("install_profile.json", StringComparison.OrdinalIgnoreCase) ?? false); if (installProfileEntry == default) return GetCorruptedFileResult(); @@ -145,9 +145,9 @@ public async Task InstallForgeTaskAsync() InvokeStatusChangedEvent("解析 Lzma", 0.4); var serverLzma = archive.Entries.FirstOrDefault(e => - e.Key.Equals("data/server.lzma", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("data/server.lzma", StringComparison.OrdinalIgnoreCase) ?? false); var clientLzma = archive.Entries.FirstOrDefault(e => - e.Key.Equals("data/client.lzma", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("data/client.lzma", StringComparison.OrdinalIgnoreCase) ?? false); if (serverLzma != default) { @@ -195,17 +195,17 @@ public async Task InstallForgeTaskAsync() InvokeStatusChangedEvent("解压 Forge Jar", 0.5); var forgeJar = archive.Entries.FirstOrDefault(e => - e.Key.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}.jar", - StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}.jar", + StringComparison.OrdinalIgnoreCase) ?? false); var forgeUniversalJar = archive.Entries.FirstOrDefault(e => - e.Key.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}-universal.jar", - StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals($"maven/net/minecraftforge/forge/{forgeVersion}/forge-{forgeVersion}-universal.jar", + StringComparison.OrdinalIgnoreCase) ?? false); if (forgeJar != default) { if (forgeUniversalJar != default) { - var forgeUniversalSubPath = forgeUniversalJar.Key[(forgeUniversalJar.Key.IndexOf('/') + 1)..]; + var forgeUniversalSubPath = forgeUniversalJar.Key![(forgeUniversalJar.Key!.IndexOf('/') + 1)..]; var forgeUniversalLibPath = Path.Combine(RootPath, GamePathHelper.GetLibraryPath(forgeUniversalSubPath)); @@ -228,7 +228,7 @@ public async Task InstallForgeTaskAsync() forgeUniversalJar.WriteTo(forgeUniversalFs); } - var forgeSubPath = forgeJar.Key[(forgeJar.Key.IndexOf('/') + 1)..]; + var forgeSubPath = forgeJar.Key![(forgeJar.Key!.IndexOf('/') + 1)..]; var forgeLibPath = Path.Combine(RootPath, GamePathHelper.GetLibraryPath(forgeSubPath)); @@ -493,7 +493,7 @@ public async Task InstallForgeTaskAsync() using var libArchive = ArchiveFactory.Open(Path.GetFullPath(libPath)); var libEntry = libArchive.Entries.FirstOrDefault(e => - e.Key.Equals("META-INF/MANIFEST.MF", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals("META-INF/MANIFEST.MF", StringComparison.OrdinalIgnoreCase) ?? false); if (libEntry == null) return GetCorruptedFileResult(); diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs index b20b680..0b3b05e 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ForgeInstaller/LegacyForgeInstaller.cs @@ -45,10 +45,11 @@ public async Task InstallForgeTaskAsync() using var reader = ArchiveFactory.Open(ForgeExecutablePath); var profileEntry = - reader.Entries.FirstOrDefault(e => e.Key.Equals("install_profile.json", StringComparison.Ordinal)); + reader.Entries.FirstOrDefault(e => + e.Key?.Equals("install_profile.json", StringComparison.Ordinal) ?? false); var legacyJarEntry = reader.Entries.FirstOrDefault(e => - e.Key.Equals($"forge-{ForgeVersion}-universal.jar", StringComparison.OrdinalIgnoreCase)); + e.Key?.Equals($"forge-{ForgeVersion}-universal.jar", StringComparison.OrdinalIgnoreCase) ?? false); if (profileEntry == default) return new ForgeInstallResult diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs index f8be2f7..a68d293 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/CurseForgeInstaller.cs @@ -220,6 +220,7 @@ public async Task InstallTaskAsync() foreach (var entry in archive.Entries) { + if (string.IsNullOrEmpty(entry.Key)) continue; if (string.IsNullOrEmpty(manifest.Overrides) || !entry.Key.StartsWith(manifest.Overrides, StringComparison.OrdinalIgnoreCase)) continue; @@ -258,7 +259,7 @@ public async Task InstallTaskAsync() { using var archive = ArchiveFactory.Open(Path.GetFullPath(ModPackPath)); var manifestEntry = - archive.Entries.FirstOrDefault(x => x.Key.Equals("manifest.json", StringComparison.OrdinalIgnoreCase)); + archive.Entries.FirstOrDefault(x => x.Key?.Equals("manifest.json", StringComparison.OrdinalIgnoreCase) ?? false); if (manifestEntry == default) return default; diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs index 0b1d6d9..98a2b4c 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/ModPackInstaller/ModrinthInstaller.cs @@ -23,7 +23,7 @@ public sealed class ModrinthInstaller : ModPackInstallerBase, IModrinthInstaller using var archive = ArchiveFactory.Open(Path.GetFullPath(ModPackPath)); var manifestEntry = archive.Entries.FirstOrDefault(x => - x.Key.Equals("modrinth.index.json", StringComparison.OrdinalIgnoreCase)); + x.Key?.Equals("modrinth.index.json", StringComparison.OrdinalIgnoreCase) ?? false); if (manifestEntry == default) return default; @@ -111,6 +111,7 @@ public async Task InstallTaskAsync() foreach (var entry in archive.Entries) { + if (string.IsNullOrEmpty(entry.Key)) continue; if (!entry.Key.StartsWith(decompressPrefix, StringComparison.OrdinalIgnoreCase)) continue; var subPath = entry.Key[(decompressPrefix.Length + 1)..]; diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs index 227afd0..b8401f8 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Installer/OptifineInstaller.cs @@ -57,7 +57,7 @@ public async Task InstallTaskAsync() var launchWrapperVersion = "1.12"; var launchWrapperOfEntry = - entries.FirstOrDefault(e => e.Key.Equals("launchwrapper-of.txt", StringComparison.OrdinalIgnoreCase)); + entries.FirstOrDefault(e => e.Key?.Equals("launchwrapper-of.txt", StringComparison.OrdinalIgnoreCase) ?? false); if (launchWrapperOfEntry != null) { @@ -67,7 +67,7 @@ public async Task InstallTaskAsync() } var launchWrapperEntry = - entries.FirstOrDefault(x => x.Key.Equals($"launchwrapper-of-{launchWrapperVersion}.jar")); + entries.FirstOrDefault(x => x.Key?.Equals($"launchwrapper-of-{launchWrapperVersion}.jar") ?? false); InvokeStatusChangedEvent("生成版本总成", 40); diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultLaunchArgumentParser.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultLaunchArgumentParser.cs index dbb034d..383b04f 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultLaunchArgumentParser.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultLaunchArgumentParser.cs @@ -162,7 +162,13 @@ public IEnumerable ParseJvmArguments() { foreach (var jvmArg in VersionInfo.JvmArguments) { - yield return StringHelper.ReplaceByDic(jvmArg, jvmArgumentsDic); + var arg = jvmArg; + + // Patch for PCL2 + if (jvmArg?.Equals("-DFabricMcEmu= net.minecraft.client.main.Main ", StringComparison.OrdinalIgnoreCase) ?? false) + arg = "-DFabricMcEmu=net.minecraft.client.main.Main"; + + yield return StringHelper.ReplaceByDic(arg, jvmArgumentsDic); } yield break; diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultVersionLocator.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultVersionLocator.cs index f0777f0..d557834 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultVersionLocator.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Launch/DefaultVersionLocator.cs @@ -23,6 +23,8 @@ public sealed class DefaultVersionLocator : VersionLocatorBase { public NativeReplacementPolicy NativeReplacementPolicy { get; init; } = NativeReplacementPolicy.LegacyOnly; + readonly object _lock = new(); + /// /// 构造函数。 /// Constructor. @@ -587,26 +589,29 @@ void ProcessProfile(VersionInfo result, string id) var gameId = id.ToGuidHash().ToString("N"); var gamePath = Path.Combine(RootPath, GamePathHelper.GetGamePath(id)); - if (LauncherProfileParser.LauncherProfile.Profiles!.TryGetValue(gameId, out var oldProfileModel)) + lock (_lock) { - result.Name = oldProfileModel.Name!; - oldProfileModel.GameDir = gamePath; - oldProfileModel.LastVersionId = id; - LauncherProfileParser.LauncherProfile.Profiles![gameId] = oldProfileModel; - LauncherProfileParser.SaveProfile(); + if (LauncherProfileParser.LauncherProfile.Profiles!.TryGetValue(gameId, out var oldProfileModel)) + { + result.Name = oldProfileModel.Name!; + oldProfileModel.GameDir = gamePath; + oldProfileModel.LastVersionId = id; + LauncherProfileParser.LauncherProfile.Profiles![gameId] = oldProfileModel; + LauncherProfileParser.SaveProfile(); - return; - } + return; + } - var gameProfile = new GameProfileModel - { - GameDir = gamePath, - LastVersionId = id, - Name = id, - Created = DateTime.Now - }; + var gameProfile = new GameProfileModel + { + GameDir = gamePath, + LastVersionId = id, + Name = id, + Created = DateTime.Now + }; - LauncherProfileParser.LauncherProfile.Profiles!.Add(gameId, gameProfile); - LauncherProfileParser.SaveProfile(); + LauncherProfileParser.LauncherProfile.Profiles!.Add(gameId, gameProfile); + LauncherProfileParser.SaveProfile(); + } } } diff --git a/ProjBobcat/ProjBobcat/DefaultComponent/Launch/GameCore/DefaultGameCore.cs b/ProjBobcat/ProjBobcat/DefaultComponent/Launch/GameCore/DefaultGameCore.cs index 83d011e..4cc7dc1 100644 --- a/ProjBobcat/ProjBobcat/DefaultComponent/Launch/GameCore/DefaultGameCore.cs +++ b/ProjBobcat/ProjBobcat/DefaultComponent/Launch/GameCore/DefaultGameCore.cs @@ -230,6 +230,7 @@ public override async Task LaunchTaskAsync(LaunchSettings settings using var archive = ArchiveFactory.Open(path); foreach (var entry in archive.Entries) { + if (string.IsNullOrEmpty(entry.Key)) continue; if (n.Extract?.Exclude?.Any(entry.Key.StartsWith) ?? false) continue; var extractPath = Path.Combine(nativeRootPath, entry.Key); diff --git a/ProjBobcat/ProjBobcat/Platforms/Windows/SystemInfoHelper.Windows.cs b/ProjBobcat/ProjBobcat/Platforms/Windows/SystemInfoHelper.Windows.cs index 46535af..a4ecd0f 100644 --- a/ProjBobcat/ProjBobcat/Platforms/Windows/SystemInfoHelper.Windows.cs +++ b/ProjBobcat/ProjBobcat/Platforms/Windows/SystemInfoHelper.Windows.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Frozen; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -9,6 +10,8 @@ using Windows.Win32.System.SystemInformation; using Microsoft.Win32; using ProjBobcat.Class.Model; +using System.IO; +using System.Security; namespace ProjBobcat.Platforms.Windows; @@ -148,8 +151,18 @@ static AppxPackageInfo SetAppxPackageInfoProperty(AppxPackageInfo appxPackageInf return appxPackageInfo; } + static readonly FrozenSet PossibleJavaDirs = new [] + { + "java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "soft", "cache", "temp", "corretto", "roaming", + "users", "craft", "program", "世界", "net", "游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", + "client", "整合", "应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot", "runtime", "x86", + "x64", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "高清", "download", "launch", "程序", "path", + "version", "baka", "pcl", "zulu", "local", "packages", "4297127d64ec6", "国服", "网易", "ext", "netease", "1.", "启动", + "jdks" + }.ToFrozenSet(); + /// - /// 从注册表中查找可能的 javaw.exe 的路径。 + /// 查找可能的 javaw.exe 的路径。 /// /// 可能的 Java 路径构成的列表。 public static IEnumerable FindJavaWindows() @@ -166,6 +179,15 @@ public static IEnumerable FindJavaWindows() .Union(FindJavaInternal(wow64Reg)) .ToHashSet(); + var drives = DriveInfo.GetDrives(); + + foreach (var drive in drives) + FindJavaBlur(drive.RootDirectory, javas); + + FindJavaBlur(new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)), javas); + FindJavaBlur(new DirectoryInfo(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)), javas); + FindJavaBlur(new DirectoryInfo(Environment.CurrentDirectory), javas); + return javas; } catch @@ -174,6 +196,54 @@ public static IEnumerable FindJavaWindows() } } + static void FindJavaBlur(DirectoryInfo di, HashSet javas, int maxDepth = 24) + { + if (!di.Exists) return; + + var stack = new Stack<(DirectoryInfo, int)>(); + + stack.Push((di, 0)); + + while (stack.Count > 0) + { + var (current, currentDepth) = stack.Pop(); + + var javaPath = Path.Combine(current.FullName, "javaw.exe"); + + if (File.Exists(javaPath)) + { + javas.Add(javaPath); + continue; + } + + if (currentDepth >= maxDepth) continue; + + try + { + foreach (var subDi in current.EnumerateDirectories()) + { + if (subDi.Attributes.HasFlag(FileAttributes.ReparsePoint)) continue; + + var dirName = subDi.Name.ToLowerInvariant(); + + if (dirName == "bin") + { + stack.Push((subDi, currentDepth - 1)); + continue; + } + + if (PossibleJavaDirs.Any(possibleName => dirName.Contains(possibleName, StringComparison.OrdinalIgnoreCase))) + { + stack.Push((subDi, currentDepth + 1)); + } + } + } + catch(SecurityException) { } + catch (UnauthorizedAccessException) { } + catch (AccessViolationException) { } + } + } + public static IEnumerable FindJavaInternal(RegistryKey? registry) { if (registry == null) return []; @@ -205,7 +275,7 @@ public static IEnumerable FindJavaInternal(RegistryKey? registry) } catch { - return Enumerable.Empty(); + return []; } } diff --git a/ProjBobcat/ProjBobcat/ProjBobcat.csproj b/ProjBobcat/ProjBobcat/ProjBobcat.csproj index 2e969ac..6303809 100644 --- a/ProjBobcat/ProjBobcat/ProjBobcat.csproj +++ b/ProjBobcat/ProjBobcat/ProjBobcat.csproj @@ -64,16 +64,16 @@ resolved the issue that LaunchWrapper may not return the correct exit code - + - 0.36.0 + 0.37.2 - + all