diff --git a/CreamInstaller/Components/CustomTreeView.cs b/CreamInstaller/Components/CustomTreeView.cs index 954e318..28a037b 100644 --- a/CreamInstaller/Components/CustomTreeView.cs +++ b/CreamInstaller/Components/CustomTreeView.cs @@ -8,6 +8,8 @@ using System.Linq; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; +using static CreamInstaller.Resources.Resources; + using TreeView = System.Windows.Forms.TreeView; namespace CreamInstaller.Components; @@ -157,7 +159,7 @@ internal class CustomTreeView : TreeView comboBoxFont ??= new(font.FontFamily, 6, font.Style, font.Unit, font.GdiCharSet, font.GdiVerticalFont); ComboBoxState comboBoxState = Enabled ? ComboBoxState.Normal : ComboBoxState.Disabled; - text = selection.KoaloaderProxy.GetKoaloaderProxyDisplay(); + text = selection.KoaloaderProxy + ".dll"; size = TextRenderer.MeasureText(graphics, text, comboBoxFont) + new Size(6, 0); int padding = 2; bounds = new(bounds.X + bounds.Width, bounds.Y + padding / 2, size.Width, bounds.Height - padding); @@ -210,50 +212,25 @@ internal class CustomTreeView : TreeView _ = comboBoxBounds.Remove(pair.Key); else if (pair.Value.Contains(clickPoint)) { - List proxies = Resources.Resources.EmbeddedResources.FindAll(r => r.StartsWith("Koaloader")); + List proxies = EmbeddedResources.FindAll(r => r.StartsWith("Koaloader")) + .Select(p => + { + p.GetProxyInfoFromIdentifier(out string proxyName, out _); + return proxyName; + }).Distinct().ToList(); comboBoxDropDown ??= new(); comboBoxDropDown.ShowItemToolTips = false; comboBoxDropDown.Items.Clear(); - _ = comboBoxDropDown.Items.Add(new ToolStripButton("32-bit", null, (s, e) => + foreach (string proxy in proxies) { - comboBoxDropDown.Items.Clear(); - foreach (string proxy in proxies) + _ = comboBoxDropDown.Items.Add(new ToolStripButton(proxy + ".dll", null, (s, e) => { - string text = proxy.GetKoaloaderProxyDisplay(); - if (text.Contains("32-bit")) - { - _ = comboBoxDropDown.Items.Add(new ToolStripButton(text, null, new EventHandler((sender, e) => - { - pair.Key.KoaloaderProxy = proxy; - ProgramData.UpdateKoaloaderProxyChoices(); - Invalidate(); - })) - { Font = comboBoxFont }); - } - } - comboBoxDropDown.Show(new(comboBoxDropDown.Left, comboBoxDropDown.Top)); - }) - { Font = comboBoxFont }); - _ = comboBoxDropDown.Items.Add(new ToolStripButton("64-bit", null, (s, e) => - { - comboBoxDropDown.Items.Clear(); - foreach (string proxy in proxies) - { - string text = proxy.GetKoaloaderProxyDisplay(); - if (text.Contains("64-bit")) - { - _ = comboBoxDropDown.Items.Add(new ToolStripButton(text, null, new EventHandler((sender, e) => - { - pair.Key.KoaloaderProxy = proxy; - ProgramData.UpdateKoaloaderProxyChoices(); - Invalidate(); - })) - { Font = comboBoxFont }); - } - } - comboBoxDropDown.Show(new(comboBoxDropDown.Left, comboBoxDropDown.Top)); - }) - { Font = comboBoxFont }); + pair.Key.KoaloaderProxy = proxy; + ProgramData.UpdateKoaloaderProxyChoices(); + Invalidate(); + }) + { Font = comboBoxFont }); + } comboBoxDropDown.Show(this, PointToScreen(new(pair.Value.Left, pair.Value.Bottom - 1))); invalidate = true; break; diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj index 5cd82c8..21e81fc 100644 --- a/CreamInstaller/CreamInstaller.csproj +++ b/CreamInstaller/CreamInstaller.csproj @@ -5,7 +5,7 @@ True Resources\ini.ico true - 4.0.2.1 + 4.1.0.0 Resources\ini.ico LICENSE 2021, pointfeev (https://github.com/pointfeev) @@ -151,6 +151,7 @@ + diff --git a/CreamInstaller/Epic/EpicLibrary.cs b/CreamInstaller/Epic/EpicLibrary.cs index 1415c0b..5a08064 100644 --- a/CreamInstaller/Epic/EpicLibrary.cs +++ b/CreamInstaller/Epic/EpicLibrary.cs @@ -9,6 +9,8 @@ using System.Linq; using System.Text.Json; using System.Threading.Tasks; +using static CreamInstaller.Resources.Resources; + namespace CreamInstaller.Epic; internal static class EpicLibrary @@ -27,7 +29,7 @@ internal static class EpicLibrary } } - internal static async Task> GetExecutableDirectories(string gameDirectory) => + internal static async Task> GetExecutableDirectories(string gameDirectory) => await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true)); internal static async Task> GetGames() => await Task.Run(() => diff --git a/CreamInstaller/Forms/InstallForm.cs b/CreamInstaller/Forms/InstallForm.cs index b5355b5..e746fff 100644 --- a/CreamInstaller/Forms/InstallForm.cs +++ b/CreamInstaller/Forms/InstallForm.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using static CreamInstaller.Paradox.ParadoxLauncher; +using static CreamInstaller.Resources.Resources; namespace CreamInstaller; @@ -64,13 +65,16 @@ internal partial class InstallForm : CustomForm UpdateUser($"Repairing Paradox Launcher . . . ", InstallationLog.Operation); _ = await Repair(this, selection); } - IEnumerable invalidDirectories = (await selection.RootDirectory.GetExecutables()).Where(d => !selection.ExecutableDirectories.Contains(d)); - if (!selection.ExecutableDirectories.Contains(selection.RootDirectory)) invalidDirectories = invalidDirectories.Append(selection.RootDirectory); + IEnumerable invalidDirectories = (await selection.RootDirectory.GetExecutables()) + .Where(d => !selection.ExecutableDirectories.Any(s => d.path.Contains(s.directory))) + .Select(d => Path.GetDirectoryName(d.path)); + if (!selection.ExecutableDirectories.Any(s => s.directory == selection.RootDirectory)) + invalidDirectories = invalidDirectories.Append(selection.RootDirectory); invalidDirectories = invalidDirectories.Distinct(); foreach (string directory in invalidDirectories) { directory.GetKoaloaderComponents(out List proxies, out string config); - if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(Resources.Resources.ResourceIdentifier.Koaloader)) + if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader)) || Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll)) || File.Exists(config)) { @@ -81,10 +85,10 @@ internal partial class InstallForm : CustomForm } if (Uninstalling || !selection.Koaloader) { - foreach (string directory in selection.ExecutableDirectories) + foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories) { directory.GetKoaloaderComponents(out List proxies, out string config); - if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(Resources.Resources.ResourceIdentifier.Koaloader)) + if (proxies.Any(proxy => File.Exists(proxy) && proxy.IsResourceFile(ResourceIdentifier.Koaloader)) || Koaloader.AutoLoadDlls.Any(pair => File.Exists(directory + @"\" + pair.dll)) || File.Exists(config)) { @@ -162,10 +166,10 @@ internal partial class InstallForm : CustomForm } if (selection.Koaloader && !Uninstalling) { - foreach (string directory in selection.ExecutableDirectories) + foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories) { UpdateUser("Installing Koaloader to " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation); - await Koaloader.Install(directory, selection, this); + await Koaloader.Install(directory, binaryType, selection, this); } } UpdateProgress(100); diff --git a/CreamInstaller/Forms/SelectForm.cs b/CreamInstaller/Forms/SelectForm.cs index a3a1b29..1b8b4f2 100644 --- a/CreamInstaller/Forms/SelectForm.cs +++ b/CreamInstaller/Forms/SelectForm.cs @@ -21,6 +21,8 @@ using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; +using static CreamInstaller.Resources.Resources; + namespace CreamInstaller; internal partial class SelectForm : CustomForm @@ -728,14 +730,13 @@ internal partial class SelectForm : CustomForm contextMenuStrip.Items.Add(new ToolStripSeparator()); contextMenuStrip.Items.Add(new ContextMenuItem("Open Root Directory", "File Explorer", new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(selection.RootDirectory)))); - List directories = selection.ExecutableDirectories.ToList(); int executables = 0; - foreach (string directory in directories) + foreach ((string directory, BinaryType binaryType) in selection.ExecutableDirectories.ToList()) { - contextMenuStrip.Items.Add(new ContextMenuItem($"Open Executable Directory #{++executables}", "File Explorer", + contextMenuStrip.Items.Add(new ContextMenuItem($"Open Executable Directory #{++executables} ({(binaryType == BinaryType.BIT32 ? "32" : "64")}-bit)", "File Explorer", new EventHandler((sender, e) => Diagnostics.OpenDirectoryInFileExplorer(directory)))); } - directories = selection.DllDirectories.ToList(); + List directories = selection.DllDirectories.ToList(); int steam = 0, epic = 0, r1 = 0, r2 = 0; if (selection.Platform is Platform.Steam or Platform.Paradox) foreach (string directory in directories) diff --git a/CreamInstaller/Paradox/ParadoxLauncher.cs b/CreamInstaller/Paradox/ParadoxLauncher.cs index a2f64a6..392d843 100644 --- a/CreamInstaller/Paradox/ParadoxLauncher.cs +++ b/CreamInstaller/Paradox/ParadoxLauncher.cs @@ -27,8 +27,8 @@ internal static class ParadoxLauncher } } - internal static async Task> GetExecutableDirectories(string gameDirectory) => - await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: d => !Path.GetFileName(d).Contains("bootstrapper"))); + internal static async Task> GetExecutableDirectories(string gameDirectory) => + await Task.Run(async () => await gameDirectory.GetExecutableDirectories(validFunc: path => !Path.GetFileName(path).Contains("bootstrapper"))); private static void PopulateDlc(ProgramSelection paradoxLauncher = null) { diff --git a/CreamInstaller/ProgramSelection.cs b/CreamInstaller/ProgramSelection.cs index f2669f4..04e2c32 100644 --- a/CreamInstaller/ProgramSelection.cs +++ b/CreamInstaller/ProgramSelection.cs @@ -5,6 +5,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using static CreamInstaller.Resources.Resources; + namespace CreamInstaller; public enum Platform @@ -43,7 +45,7 @@ internal class ProgramSelection internal string WebsiteUrl; internal string RootDirectory; - internal List ExecutableDirectories; + internal List<(string directory, BinaryType binaryType)> ExecutableDirectories; internal List DllDirectories; internal readonly SortedList AllDlc = new(PlatformIdComparer.String); diff --git a/CreamInstaller/Resources/Koaloader.cs b/CreamInstaller/Resources/Koaloader.cs index d37e188..1a5847e 100644 --- a/CreamInstaller/Resources/Koaloader.cs +++ b/CreamInstaller/Resources/Koaloader.cs @@ -7,6 +7,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using static CreamInstaller.Resources.Resources; + namespace CreamInstaller.Resources; internal static class Koaloader @@ -18,7 +20,7 @@ internal static class Koaloader ) { proxies = new(); - foreach (string proxy in Resources.EmbeddedResources.Select(proxy => + foreach (string proxy in EmbeddedResources.Select(proxy => { proxy = proxy[(proxy.IndexOf('.') + 1)..]; return proxy[(proxy.IndexOf('.') + 1)..]; @@ -26,13 +28,26 @@ internal static class Koaloader config = directory + @"\Koaloader.json"; } - internal static string GetKoaloaderProxyDisplay(this string proxy) + internal static void WriteProxy(this string path, string proxyName, BinaryType binaryType) { - string proxyDisplay = proxy[(proxy.IndexOf('.') + 1)..]; - proxyDisplay = proxyDisplay[..proxyDisplay.IndexOf('.')]; - string name = proxyDisplay[..proxyDisplay.LastIndexOf('_')]; - string bitness = proxyDisplay[(proxyDisplay.LastIndexOf('_') + 1)..]; - return $"{name}.dll ({bitness}-bit)"; + foreach (string resourceIdentifier in EmbeddedResources.FindAll(r => r.StartsWith("Koaloader"))) + { + resourceIdentifier.GetProxyInfoFromIdentifier(out string _proxyName, out BinaryType _binaryType); + if (_proxyName == proxyName && _binaryType == binaryType) + { + resourceIdentifier.Write(path); + break; + } + } + } + + internal static void GetProxyInfoFromIdentifier(this string resourceIdentifier, out string proxyName, out BinaryType binaryType) + { + string baseIdentifier = resourceIdentifier[(resourceIdentifier.IndexOf('.') + 1)..]; + baseIdentifier = baseIdentifier[..baseIdentifier.IndexOf('.')]; + proxyName = baseIdentifier[..baseIdentifier.LastIndexOf('_')]; + string bitness = baseIdentifier[(baseIdentifier.LastIndexOf('_') + 1)..]; + binaryType = bitness == "32" ? BinaryType.BIT32 : bitness == "64" ? BinaryType.BIT64 : BinaryType.Unknown; } internal static readonly List<(string unlocker, string dll)> AutoLoadDlls = new() @@ -137,22 +152,19 @@ internal static class Koaloader await UplayR2.Uninstall(directory, installForm, deleteConfig); }); - internal static async Task Install(string directory, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() => + internal static async Task Install(string directory, BinaryType binaryType, ProgramSelection selection, InstallForm installForm = null, bool generateConfig = true) => await Task.Run(() => { directory.GetKoaloaderComponents(out List proxies, out string config); - string proxy = selection.KoaloaderProxy; - proxy = proxy[(proxy.IndexOf('.') + 1)..]; - proxy = proxy[(proxy.IndexOf('.') + 1)..]; - string path = directory + @"\" + proxy; - foreach (string proxyPath in proxies.Where(proxyPath => proxyPath != path && File.Exists(proxyPath) && proxyPath.IsResourceFile(Resources.ResourceIdentifier.Koaloader))) + string path = directory + @"\" + selection.KoaloaderProxy + ".dll"; + foreach (string _path in proxies.Where(p => p != path && File.Exists(p) && p.IsResourceFile(ResourceIdentifier.Koaloader))) { - File.Delete(proxyPath); + File.Delete(_path); if (installForm is not null) - installForm.UpdateUser($"Deleted Koaloader: {Path.GetFileName(proxyPath)}", InstallationLog.Action, info: false); + installForm.UpdateUser($"Deleted Koaloader: {Path.GetFileName(_path)}", InstallationLog.Action, info: false); } - selection.KoaloaderProxy.Write(path); + path.WriteProxy(selection.KoaloaderProxy, binaryType); if (installForm is not null) - installForm.UpdateUser($"Wrote Koaloader: {Path.GetFileName(path)}", InstallationLog.Action, info: false); + installForm.UpdateUser($"Wrote {(binaryType == BinaryType.BIT32 ? "32-bit" : "64-bit")} Koaloader: {Path.GetFileName(path)}", InstallationLog.Action, info: false); if (selection.Platform is Platform.Steam or Platform.Paradox) { bool did32 = false, did64 = false; diff --git a/CreamInstaller/Resources/Resources.cs b/CreamInstaller/Resources/Resources.cs index 2ea11ab..84fa11f 100644 --- a/CreamInstaller/Resources/Resources.cs +++ b/CreamInstaller/Resources/Resources.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; @@ -29,9 +30,9 @@ internal static class Resources } } - internal static void Write(this string resourceName, string filePath) + internal static void Write(this string resourceIdentifier, string filePath) { - using Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("CreamInstaller.Resources." + resourceName); + using Stream resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("CreamInstaller.Resources." + resourceIdentifier); using FileStream file = new(filePath, FileMode.Create, FileAccess.Write); resource.CopyTo(file); } @@ -59,6 +60,23 @@ internal static class Resources return false; } + internal enum BinaryType + { + Unknown = -1, + BIT32 = 0, + DOS = 1, + WOW = 2, + PIF = 3, + POSIX = 4, + OS216 = 5, + BIT64 = 6, + } + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static extern bool GetBinaryType(string lpApplicationName, out BinaryType lpBinaryType); + internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) => GetBinaryType(path, out binaryType); + internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path) { string subPath = path[rootDirectory.Length..].ToUpperInvariant().BeautifyPath(); @@ -66,35 +84,53 @@ internal static class Resources || subPath.Contains("CRASH") && (subPath.Contains("PAD") || subPath.Contains("REPORT")); } - internal static async Task> GetExecutables(this string rootDirectory, string subDirectory = null, bool filterCommon = false, Func validFunc = null) => await Task.Run(async () => - { - List executables = new(); - if (Program.Canceled || !Directory.Exists(subDirectory ?? rootDirectory)) return null; - Thread.Sleep(0); - foreach (string path in Directory.GetFiles(subDirectory ?? rootDirectory, "*.exe")) + internal static async Task> GetExecutables(this string rootDirectory, string subDirectory = null, bool filterCommon = false, Func validFunc = null) => + await Task.Run(async () => { + List<(string path, BinaryType binaryType)> executables = new(); + if (Program.Canceled || !Directory.Exists(subDirectory ?? rootDirectory)) return null; Thread.Sleep(0); - if ((!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) && (validFunc is null || validFunc(path))) - executables.Add(path); - } - string[] directories = Directory.GetDirectories(subDirectory ?? rootDirectory); - foreach (string directory in directories) - { - if (Program.Canceled) return null; - Thread.Sleep(0); - try + string[] files = Directory.GetFiles(subDirectory ?? rootDirectory, "*.exe"); + foreach (string path in files) { - List moreExecutables = await rootDirectory.GetExecutables(directory, filterCommon, validFunc); - if (moreExecutables is not null) - executables.AddRange(moreExecutables); + Thread.Sleep(0); + if (!executables.Any(e => e.path == path) + && (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) + && (validFunc is null || validFunc(path)) + && path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64) + executables.Add((path, binaryType)); } - catch { } - } - return !executables.Any() ? null : executables; - }); + foreach (string path in files) + { + Thread.Sleep(0); + if (!executables.Any(e => e.path == path) + && (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) + && (validFunc is null || validFunc(path)) + && path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT32) + executables.Add((path, binaryType)); + } + string[] directories = Directory.GetDirectories(subDirectory ?? rootDirectory); + foreach (string directory in directories) + { + if (Program.Canceled) return null; + Thread.Sleep(0); + try + { + List<(string path, BinaryType binaryType)> moreExecutables = await rootDirectory.GetExecutables(directory, filterCommon, validFunc); + if (moreExecutables is not null) + executables.AddRange(moreExecutables); + } + catch { } + } + return !executables.Any() ? null : executables; + }); - internal static async Task> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false, Func validFunc = null) => await Task.Run(async () => - (await rootDirectory.GetExecutables(filterCommon: filterCommon, validFunc: validFunc) ?? await rootDirectory.GetExecutables()).Select(e => e = Path.GetDirectoryName(e)).Distinct().ToList()); + internal static async Task> GetExecutableDirectories(this string rootDirectory, bool filterCommon = false, Func validFunc = null) => + await Task.Run(async () => (await rootDirectory.GetExecutables(filterCommon: filterCommon, validFunc: validFunc) ?? await rootDirectory.GetExecutables()).Select(e => + { + e.path = Path.GetDirectoryName(e.path); + return e; + }).DistinctBy(e => e.path).ToList()); internal static void GetCreamApiComponents( this string directory, diff --git a/CreamInstaller/Steam/SteamLibrary.cs b/CreamInstaller/Steam/SteamLibrary.cs index 8bedd00..296773e 100644 --- a/CreamInstaller/Steam/SteamLibrary.cs +++ b/CreamInstaller/Steam/SteamLibrary.cs @@ -11,6 +11,8 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using static CreamInstaller.Resources.Resources; + namespace CreamInstaller.Steam; internal static class SteamLibrary @@ -26,7 +28,7 @@ internal static class SteamLibrary } } - internal static async Task> GetExecutableDirectories(string gameDirectory) => + internal static async Task> GetExecutableDirectories(string gameDirectory) => await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true)); internal static async Task> GetGames() => await Task.Run(async () => diff --git a/CreamInstaller/Ubisoft/UbisoftLibrary.cs b/CreamInstaller/Ubisoft/UbisoftLibrary.cs index 9173a94..74dcf61 100644 --- a/CreamInstaller/Ubisoft/UbisoftLibrary.cs +++ b/CreamInstaller/Ubisoft/UbisoftLibrary.cs @@ -8,6 +8,8 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using static CreamInstaller.Resources.Resources; + namespace CreamInstaller.Ubisoft; internal static class UbisoftLibrary @@ -23,7 +25,7 @@ internal static class UbisoftLibrary } } - internal static async Task> GetExecutableDirectories(string gameDirectory) => + internal static async Task> GetExecutableDirectories(string gameDirectory) => await Task.Run(async () => await gameDirectory.GetExecutableDirectories(filterCommon: true)); internal static async Task> GetGames() => await Task.Run(() => diff --git a/CreamInstaller/Utility/ProgramData.cs b/CreamInstaller/Utility/ProgramData.cs index 9e89bdf..9bc6e2c 100644 --- a/CreamInstaller/Utility/ProgramData.cs +++ b/CreamInstaller/Utility/ProgramData.cs @@ -1,4 +1,6 @@ -using Newtonsoft.Json; +using CreamInstaller.Resources; + +using Newtonsoft.Json; using System; using System.Collections.Generic; @@ -132,14 +134,17 @@ internal static class ProgramData internal static void UpdateKoaloaderProxyChoices() { - string defaultProxy = Resources.Resources.EmbeddedResources.Find(r => r.Contains("version_64")); + string defaultProxy = "version"; List<(Platform platform, string id, string proxy)> choices = ReadKoaloaderProxyChoices() ?? new(); foreach ((Platform platform, string id, string proxy) choice in choices.ToList()) if (ProgramSelection.FromPlatformId(choice.platform, choice.id) is ProgramSelection selection) { + string proxy = choice.proxy; + if (proxy.Contains('.')) // convert pre-v4.1.0.0 choices + proxy.GetProxyInfoFromIdentifier(out proxy, out _); if (selection.KoaloaderProxy is null) - selection.KoaloaderProxy = choice.proxy; - else if (selection.KoaloaderProxy != choice.proxy && choices.Remove(choice)) + selection.KoaloaderProxy = proxy; + else if (selection.KoaloaderProxy != proxy && choices.Remove(choice)) choices.Add((selection.Platform, selection.Id, selection.KoaloaderProxy)); } foreach (ProgramSelection selection in ProgramSelection.AllSafe)