- Minor code refactoring
- Added a Paradox Launcher Repair feature to the right-click context menu
This commit is contained in:
pointfeev 2022-02-21 16:30:10 -05:00
parent cbf614c04d
commit b9d84c0c34
6 changed files with 196 additions and 88 deletions

View file

@ -33,9 +33,13 @@ internal class ProgramSelection
{
foreach (string directory in SteamApiDllDirectories)
{
string api = directory + @"\steam_api.dll";
string api64 = directory + @"\steam_api64.dll";
if (api.IsFilePathLocked() || api64.IsFilePathLocked()) return true;
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
if (api.IsFilePathLocked()
|| api_o.IsFilePathLocked()
|| api64.IsFilePathLocked()
|| api64_o.IsFilePathLocked()
|| cApi.IsFilePathLocked())
return true;
}
return false;
}

View file

@ -9,8 +9,10 @@ internal partial class DialogForm : CustomForm
{
internal DialogForm(IWin32Window owner) : base(owner) => InitializeComponent();
internal DialogResult Show(string formName, Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null)
internal DialogResult Show(string formName, Icon descriptionIcon, string descriptionText, string acceptButtonText, string cancelButtonText = null, Icon customFormIcon = null)
{
if (customFormIcon is not null)
Icon = customFormIcon;
icon.Image = descriptionIcon.ToBitmap();
Text = formName;
descriptionLabel.Text = descriptionText;

View file

@ -4,7 +4,6 @@ using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -32,24 +31,30 @@ internal partial class InstallForm : CustomForm
private int CompleteOperationsCount;
internal void UpdateProgress(int progress)
{
if (!userProgressBar.Disposing && !userProgressBar.IsDisposed)
userProgressBar.Invoke(() =>
{
int value = (int)((float)(CompleteOperationsCount / (float)OperationsCount) * 100) + progress / OperationsCount;
if (value < userProgressBar.Value) return;
userProgressBar.Value = value;
});
}
internal async Task UpdateUser(string text, Color color, bool info = true, bool log = true)
internal void UpdateUser(string text, Color color, bool info = true, bool log = true)
{
if (info) userInfoLabel.Text = text;
if (log && !logTextBox.IsDisposed)
if (info) userInfoLabel.Invoke(() => userInfoLabel.Text = text);
if (log && !logTextBox.Disposing && !logTextBox.IsDisposed)
{
logTextBox.Invoke(() =>
{
if (logTextBox.Text.Length > 0) logTextBox.AppendText(Environment.NewLine, color);
logTextBox.AppendText(text, color);
});
}
await Task.Run(() => Thread.Sleep(0)); // to keep the text box control from glitching
}
internal async Task WriteConfiguration(StreamWriter writer, int steamAppId, string name, SortedList<int, (string name, string iconStaticId)> steamDlcApps)
internal static void WriteConfiguration(StreamWriter writer, int steamAppId, string name, SortedList<int, (string name, string iconStaticId)> steamDlcApps, InstallForm installForm = null)
{
writer.WriteLine();
writer.WriteLine($"; {name}");
@ -57,16 +62,93 @@ internal partial class InstallForm : CustomForm
writer.WriteLine($"appid = {steamAppId}");
writer.WriteLine();
writer.WriteLine("[dlc]");
await UpdateUser($"Added game to cream_api.ini with appid {steamAppId} ({name})", InstallationLog.Resource, info: false);
if (installForm is not null)
installForm.UpdateUser($"Added game to cream_api.ini with appid {steamAppId} ({name})", InstallationLog.Resource, info: false);
foreach (KeyValuePair<int, (string name, string iconStaticId)> pair in steamDlcApps)
{
int appId = pair.Key;
(string name, string iconStaticId) dlcApp = pair.Value;
writer.WriteLine($"{appId} = {dlcApp.name}");
await UpdateUser($"Added DLC to cream_api.ini with appid {appId} ({dlcApp.name})", InstallationLog.Resource, info: false);
if (installForm is not null)
installForm.UpdateUser($"Added DLC to cream_api.ini with appid {appId} ({dlcApp.name})", InstallationLog.Resource, info: false);
}
}
internal static async Task UninstallCreamAPI(string directory, InstallForm installForm = null) => await Task.Run(() =>
{
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
if (File.Exists(api_o))
{
if (File.Exists(api))
{
File.Delete(api);
if (installForm is not null)
installForm.UpdateUser($"Deleted file: {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
}
File.Move(api_o, api);
if (installForm is not null)
installForm.UpdateUser($"Renamed file: {Path.GetFileName(api_o)} -> {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api64_o))
{
if (File.Exists(api64))
{
File.Delete(api64);
if (installForm is not null)
installForm.UpdateUser($"Deleted file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
}
File.Move(api64_o, api64);
if (installForm is not null)
installForm.UpdateUser($"Renamed file: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
}
if (File.Exists(cApi))
{
File.Delete(cApi);
if (installForm is not null)
installForm.UpdateUser($"Deleted file: {Path.GetFileName(cApi)}", InstallationLog.Resource, info: false);
}
});
internal static async Task InstallCreamAPI(string directory, ProgramSelection selection, InstallForm installForm = null) => await Task.Run(() =>
{
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
if (File.Exists(api) && !File.Exists(api_o))
{
File.Move(api, api_o);
if (installForm is not null)
installForm.UpdateUser($"Renamed file: {Path.GetFileName(api)} -> {Path.GetFileName(api_o)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api_o))
{
Properties.Resources.API.Write(api);
if (installForm is not null)
installForm.UpdateUser($"Wrote resource to file: {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
if (installForm is not null)
installForm.UpdateUser($"Renamed file: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api64_o))
{
Properties.Resources.API64.Write(api64);
if (installForm is not null)
installForm.UpdateUser($"Wrote resource to file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
}
if (installForm is not null)
installForm.UpdateUser("Generating CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
File.Create(cApi).Close();
StreamWriter writer = new(cApi, true, Encoding.UTF8);
writer.WriteLine("; " + Application.CompanyName + " v" + Application.ProductVersion);
if (selection.SteamAppId > 0)
WriteConfiguration(writer, selection.SteamAppId, selection.Name, selection.SelectedSteamDlc, installForm);
foreach (Tuple<int, string, SortedList<int, (string name, string iconStaticId)>> extraAppDlc in selection.ExtraSteamAppIdDlc)
WriteConfiguration(writer, extraAppDlc.Item1, extraAppDlc.Item2, extraAppDlc.Item3, installForm);
writer.Flush();
writer.Close();
});
private async Task OperateFor(ProgramSelection selection)
{
UpdateProgress(0);
@ -74,73 +156,12 @@ internal partial class InstallForm : CustomForm
int cur = 0;
foreach (string directory in selection.SteamApiDllDirectories)
{
await UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
UpdateUser($"{(Uninstalling ? "Uninstalling" : "Installing")} CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
if (!Program.IsProgramRunningDialog(this, selection)) throw new OperationCanceledException();
string api = directory + @"\steam_api.dll";
string api_o = directory + @"\steam_api_o.dll";
string api64 = directory + @"\steam_api64.dll";
string api64_o = directory + @"\steam_api64_o.dll";
string cApi = directory + @"\cream_api.ini";
if (Uninstalling)
{
if (File.Exists(api_o))
{
if (File.Exists(api))
{
File.Delete(api);
await UpdateUser($"Deleted file: {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
}
File.Move(api_o, api);
await UpdateUser($"Renamed file: {Path.GetFileName(api_o)} -> {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api64_o))
{
if (File.Exists(api64))
{
File.Delete(api64);
await UpdateUser($"Deleted file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
}
File.Move(api64_o, api64);
await UpdateUser($"Renamed file: {Path.GetFileName(api64_o)} -> {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
}
if (File.Exists(cApi))
{
File.Delete(cApi);
await UpdateUser($"Deleted file: {Path.GetFileName(cApi)}", InstallationLog.Resource, info: false);
}
}
await UninstallCreamAPI(directory, this);
else
{
if (File.Exists(api) && !File.Exists(api_o))
{
File.Move(api, api_o);
await UpdateUser($"Renamed file: {Path.GetFileName(api)} -> {Path.GetFileName(api_o)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api_o))
{
Properties.Resources.API.Write(api);
await UpdateUser($"Wrote resource to file: {Path.GetFileName(api)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api64) && !File.Exists(api64_o))
{
File.Move(api64, api64_o);
await UpdateUser($"Renamed file: {Path.GetFileName(api64)} -> {Path.GetFileName(api64_o)}", InstallationLog.Resource, info: false);
}
if (File.Exists(api64_o))
{
Properties.Resources.API64.Write(api64);
await UpdateUser($"Wrote resource to file: {Path.GetFileName(api64)}", InstallationLog.Resource, info: false);
}
await UpdateUser("Generating CreamAPI for " + selection.Name + $" in directory \"{directory}\" . . . ", InstallationLog.Operation);
File.Create(cApi).Close();
StreamWriter writer = new(cApi, true, Encoding.UTF8);
writer.WriteLine("; " + Application.CompanyName + " v" + Application.ProductVersion);
if (selection.SteamAppId > 0) await WriteConfiguration(writer, selection.SteamAppId, selection.Name, selection.SelectedSteamDlc);
foreach (Tuple<int, string, SortedList<int, (string name, string iconStaticId)>> extraAppDlc in selection.ExtraSteamAppIdDlc)
await WriteConfiguration(writer, extraAppDlc.Item1, extraAppDlc.Item2, extraAppDlc.Item3);
writer.Flush();
writer.Close();
}
await InstallCreamAPI(directory, selection, this);
UpdateProgress(++cur / count * 100);
}
UpdateProgress(100);
@ -158,13 +179,13 @@ internal partial class InstallForm : CustomForm
try
{
await OperateFor(selection);
await UpdateUser($"Operation succeeded for {selection.Name}.", InstallationLog.Success);
UpdateUser($"Operation succeeded for {selection.Name}.", InstallationLog.Success);
selection.Enabled = false;
disabledSelections.Add(selection);
}
catch (Exception exception)
{
await UpdateUser($"Operation failed for {selection.Name}: " + exception.ToString(), InstallationLog.Error);
UpdateUser($"Operation failed for {selection.Name}: " + exception.ToString(), InstallationLog.Error);
}
++CompleteOperationsCount;
}
@ -188,11 +209,11 @@ internal partial class InstallForm : CustomForm
try
{
await Operate();
await UpdateUser($"CreamAPI successfully {(Uninstalling ? "uninstalled" : "installed and generated")} for " + ProgramCount + " program(s).", InstallationLog.Success);
UpdateUser($"CreamAPI successfully {(Uninstalling ? "uninstalled" : "installed and generated")} for " + ProgramCount + " program(s).", InstallationLog.Success);
}
catch (Exception exception)
{
await UpdateUser($"CreamAPI {(Uninstalling ? "uninstallation" : "installation and/or generation")} failed: " + exception.ToString(), InstallationLog.Error);
UpdateUser($"CreamAPI {(Uninstalling ? "uninstallation" : "installation and/or generation")} failed: " + exception.ToString(), InstallationLog.Error);
retryButton.Enabled = true;
}
userProgressBar.Value = userProgressBar.Maximum;

View file

@ -12,6 +12,7 @@ using System.Windows.Forms;
using CreamInstaller.Classes;
using CreamInstaller.Forms.Components;
using CreamInstaller.Resources;
using Gameloop.Vdf.Linq;
@ -58,9 +59,13 @@ internal partial class SelectForm : CustomForm
{
List<string> dllDirectories = new();
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
string api = gameDirectory + @"\steam_api.dll";
string api64 = gameDirectory + @"\steam_api64.dll";
if (File.Exists(api) || File.Exists(api64)) dllDirectories.Add(gameDirectory);
gameDirectory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
if (File.Exists(api)
|| File.Exists(api_o)
|| File.Exists(api64)
|| File.Exists(api64_o)
|| File.Exists(cApi))
dllDirectories.Add(gameDirectory);
string[] directories = Directory.GetDirectories(gameDirectory);
foreach (string _directory in directories)
{
@ -549,6 +554,56 @@ internal partial class SelectForm : CustomForm
}
if (selection is not null)
{
if (appId == 0)
{
nodeContextMenu.Items.Add(new ToolStripSeparator());
nodeContextMenu.Items.Add(new ToolStripMenuItem("Repair", Image("Command Prompt"),
new EventHandler(async (sender, e) =>
{
if (!Program.IsProgramRunningDialog(this, selection)) return;
bool shouldReinstall = false;
byte[] properApi = null;
byte[] properApi64 = null;
foreach (string directory in selection.SteamApiDllDirectories)
{
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
shouldReinstall = File.Exists(cApi);
await InstallForm.UninstallCreamAPI(directory);
if (properApi is null && File.Exists(api) && !FileResourceExtensions.Equals(Properties.Resources.API, api))
properApi = File.ReadAllBytes(api);
if (properApi64 is null && File.Exists(api64) && !FileResourceExtensions.Equals(Properties.Resources.API64, api64))
properApi64 = File.ReadAllBytes(api64);
}
if (properApi is not null || properApi64 is not null)
{
bool neededRepair = false;
foreach (string directory in selection.SteamApiDllDirectories)
{
directory.GetApiComponents(out string api, out string api_o, out string api64, out string api64_o, out string cApi);
if (properApi is not null && FileResourceExtensions.Equals(Properties.Resources.API, api))
{
properApi.Write(api);
neededRepair = true;
}
if (properApi64 is not null && FileResourceExtensions.Equals(Properties.Resources.API64, api64))
{
properApi64.Write(api64);
neededRepair = true;
}
if (shouldReinstall)
await InstallForm.InstallCreamAPI(directory, selection);
}
if (neededRepair)
new DialogForm(this).Show("Paradox Launcher Repair", Icon, "Paradox Launcher successfully repaired!", "OK");
else
new DialogForm(this).Show("Paradox Launcher Repair", SystemIcons.Information, "Paradox Launcher does not need to be repaired.", "OK");
}
else
new DialogForm(this).Show("Paradox Launcher Repair", SystemIcons.Error, "Paradox Launcher repair failed!"
+ "\n\nAn original Steamworks API file could not be found."
+ "\nYou must reinstall Paradox Launcher to fix this issue.", "OK");
})));
}
nodeContextMenu.Items.Add(new ToolStripSeparator());
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open Root Directory", Image("File Explorer"),
new EventHandler((sender, e) => Program.OpenDirectoryInFileExplorer(selection.RootDirectory))));

View file

@ -51,6 +51,15 @@ internal static class Program
}
}
internal static void GetApiComponents(this string directory, out string api, out string api_o, out string api64, out string api64_o, out string cApi)
{
api = directory + @"\steam_api.dll";
api_o = directory + @"\steam_api_o.dll";
api64 = directory + @"\steam_api64.dll";
api64_o = directory + @"\steam_api64_o.dll";
cApi = directory + @"\cream_api.ini";
}
internal static bool IsGameBlocked(string name, string directory)
{
if (!BlockProtectedGames) return false;
@ -86,6 +95,12 @@ internal static class Program
mutex.Close();
}
internal static Icon ToIcon(this Image image)
{
Bitmap dialogIconBitmap = new(image, new Size(image.Width, image.Height));
return Icon.FromHandle(dialogIconBitmap.GetHicon());
}
private static readonly string SteamAppImagesPath = "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/";
internal static async Task<Image> GetSteamIcon(int steamAppId, string iconStaticId) => await GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{iconStaticId}.jpg");
internal static async Task<Image> GetSteamClientIcon(int steamAppId, string clientIconStaticId) => await GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{clientIconStaticId}.ico");

View file

@ -9,4 +9,15 @@ internal static class FileResourceExtensions
using FileStream file = new(filePath, FileMode.Create, FileAccess.Write);
file.Write(resource);
}
internal static bool Equals(byte[] resource, string filePath)
{
byte[] file = File.ReadAllBytes(filePath);
if (resource.Length != file.Length)
return false;
for (int i = 0; i < resource.Length; i++)
if (resource[i] != file[i])
return false;
return true;
}
}