Update 1.0.5

- Fixed unhandled exception when Paradox Launcher is not installed.
- Added better exception handling and file backups during installation.
- Added an explanation for when no CreamAPI-applicable programs or games are found.
- Increased the minimum size of the installation window.
- Added program/game reselection from the installation window.
- Added error dialogs for when selected programs are currently running.
- Multiple other aesthetic changes.
This commit is contained in:
pointfeev 2021-08-06 21:29:43 -05:00
parent 52aa22ad99
commit f4491ee8f2
8 changed files with 282 additions and 103 deletions

View file

@ -6,7 +6,7 @@
<UseWindowsForms>true</UseWindowsForms>
<ApplicationIcon>ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>1.0.4</Version>
<Version>1.0.5</Version>
<PackageIcon>ini.ico</PackageIcon>
<PackageIconUrl />
<Description>Automatically downloads and installs CreamAPI files for programs/games.</Description>

View file

@ -36,6 +36,7 @@ namespace CreamInstaller
this.retryButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.logTextBox = new System.Windows.Forms.RichTextBox();
this.reselectButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// userProgressBar
@ -44,7 +45,7 @@ namespace CreamInstaller
| System.Windows.Forms.AnchorStyles.Right)));
this.userProgressBar.Location = new System.Drawing.Point(12, 27);
this.userProgressBar.Name = "userProgressBar";
this.userProgressBar.Size = new System.Drawing.Size(460, 23);
this.userProgressBar.Size = new System.Drawing.Size(500, 23);
this.userProgressBar.TabIndex = 1;
//
// userInfoLabel
@ -53,7 +54,7 @@ namespace CreamInstaller
| System.Windows.Forms.AnchorStyles.Right)));
this.userInfoLabel.Location = new System.Drawing.Point(12, 9);
this.userInfoLabel.Name = "userInfoLabel";
this.userInfoLabel.Size = new System.Drawing.Size(460, 15);
this.userInfoLabel.Size = new System.Drawing.Size(500, 15);
this.userInfoLabel.TabIndex = 2;
this.userInfoLabel.Text = "Loading . . . ";
//
@ -61,7 +62,7 @@ namespace CreamInstaller
//
this.acceptButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.acceptButton.Enabled = false;
this.acceptButton.Location = new System.Drawing.Point(397, 226);
this.acceptButton.Location = new System.Drawing.Point(437, 286);
this.acceptButton.Name = "acceptButton";
this.acceptButton.Size = new System.Drawing.Size(75, 23);
this.acceptButton.TabIndex = 3;
@ -73,7 +74,7 @@ namespace CreamInstaller
//
this.retryButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.retryButton.Enabled = false;
this.retryButton.Location = new System.Drawing.Point(316, 226);
this.retryButton.Location = new System.Drawing.Point(356, 286);
this.retryButton.Name = "retryButton";
this.retryButton.Size = new System.Drawing.Size(75, 23);
this.retryButton.TabIndex = 2;
@ -84,7 +85,7 @@ namespace CreamInstaller
// cancelButton
//
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.cancelButton.Location = new System.Drawing.Point(12, 226);
this.cancelButton.Location = new System.Drawing.Point(12, 286);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(75, 23);
this.cancelButton.TabIndex = 1;
@ -102,17 +103,29 @@ namespace CreamInstaller
this.logTextBox.Name = "logTextBox";
this.logTextBox.ReadOnly = true;
this.logTextBox.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.ForcedBoth;
this.logTextBox.Size = new System.Drawing.Size(460, 164);
this.logTextBox.Size = new System.Drawing.Size(500, 224);
this.logTextBox.TabIndex = 4;
this.logTextBox.TabStop = false;
this.logTextBox.Text = "";
this.logTextBox.WordWrap = false;
//
// reselectButton
//
this.reselectButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
this.reselectButton.Location = new System.Drawing.Point(135, 286);
this.reselectButton.Name = "reselectButton";
this.reselectButton.Size = new System.Drawing.Size(175, 23);
this.reselectButton.TabIndex = 5;
this.reselectButton.Text = "Reselect Programs / Games";
this.reselectButton.UseVisualStyleBackColor = true;
this.reselectButton.Click += new System.EventHandler(this.OnReselect);
//
// InstallForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(484, 261);
this.ClientSize = new System.Drawing.Size(524, 321);
this.Controls.Add(this.reselectButton);
this.Controls.Add(this.logTextBox);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.retryButton);
@ -123,7 +136,7 @@ namespace CreamInstaller
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.MaximizeBox = false;
this.MinimizeBox = false;
this.MinimumSize = new System.Drawing.Size(500, 300);
this.MinimumSize = new System.Drawing.Size(540, 360);
this.Name = "InstallForm";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
@ -141,6 +154,7 @@ namespace CreamInstaller
private System.Windows.Forms.Button retryButton;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.RichTextBox logTextBox;
private System.Windows.Forms.Button reselectButton;
}
}

View file

@ -12,6 +12,8 @@ namespace CreamInstaller
{
public partial class InstallForm : Form
{
public bool Reselecting = false;
public InstallForm(IWin32Window owner)
{
Owner = owner as Form;
@ -37,15 +39,8 @@ namespace CreamInstaller
}
}
private async Task Install()
private async Task OperateFor(ProgramSelection selection)
{
foreach (ProgramSelection selection in Program.ProgramSelections.ToList())
{
if (Program.Canceled)
break;
Program.Cleanup(cancel: false, logout: false);
UpdateProgress(0);
UpdateUser("Downloading CreamAPI files for " + selection.ProgramName + " . . . ", LogColor.Operation);
Program.OutputFile = selection.ProgramDirectory + "\\" + selection.DownloadNode.Name;
@ -57,7 +52,7 @@ namespace CreamInstaller
}
catch
{
throw new Exception("Unable to delete old archive file for " + selection.ProgramName);
throw new Exception($"Unable to delete old archive file: {Program.OutputFile}");
}
}
Progress<double> progress = new Progress<double>(delegate (double progress)
@ -71,6 +66,7 @@ namespace CreamInstaller
Program.CancellationTokenSource = new CancellationTokenSource();
Program.OutputTask = Program.MegaApiClient.DownloadFileAsync(selection.DownloadNode, Program.OutputFile, progress, Program.CancellationTokenSource.Token);
await Program.OutputTask;
UpdateUser($"Downloaded file: {Program.OutputFile}", LogColor.Resource);
UpdateProgress(100);
UpdateProgress(0);
@ -101,7 +97,7 @@ namespace CreamInstaller
}
if (resources.Count < 1)
{
throw new Exception("Unable to find CreamAPI files in downloaded archive for " + selection.ProgramName);
throw new Exception($"Unable to find CreamAPI files in downloaded archive: {Program.OutputFile}");
}
UpdateProgress(100);
@ -110,30 +106,114 @@ namespace CreamInstaller
int currentFileCount = 0;
foreach (string directory in selection.SteamApiDllDirectories)
{
Dictionary<string, string> changesToRevert = new();
foreach (ZipArchiveEntry entry in resources)
{
currentFileCount++;
string file = directory + "\\" + entry.Name;
UpdateUser(file, LogColor.Resource);
if (File.Exists(file))
{
string backup = file + Program.BackupFileExtension;
File.Copy(file, backup, true);
changesToRevert.Add(file, backup);
}
else
{
changesToRevert.Add(file, string.Empty);
}
try
{
File.Delete(file);
entry.ExtractToFile(file, true);
}
catch
{
throw new Exception("Unable to delete Steam API files for " + selection.ProgramName);
foreach (KeyValuePair<string, string> keyValuePair in changesToRevert)
{
file = keyValuePair.Key;
string backup = keyValuePair.Value;
if (string.IsNullOrEmpty(backup))
{
File.Delete(file);
UpdateUser("Deleted CreamAPI file: " + file, LogColor.Warning);
}
else if (file.IsFilePathLocked())
{
File.Delete(backup);
}
else
{
File.Move(backup, file, true);
UpdateUser("Reversed changes to Steam API file: " + file, LogColor.Warning);
}
}
entry.ExtractToFile(file);
throw new Exception($"Unable to overwrite Steam API file: {file}");
}
UpdateUser("Installed file: " + file, LogColor.Resource);
UpdateProgress((currentFileCount / (resources.Count * selection.SteamApiDllDirectories.Count)) * 100);
}
foreach (KeyValuePair<string, string> keyValuePair in changesToRevert)
{
string file = keyValuePair.Key;
string backup = keyValuePair.Value;
if (!string.IsNullOrEmpty(backup))
File.Delete(backup);
}
}
UpdateProgress(100);
}
UpdateUser("CreamAPI successfully downloaded and installed for " + selection.ProgramName, LogColor.Success);
Program.ProgramSelections.Remove(selection);
private async Task Operate()
{
foreach (ProgramSelection selection in Program.ProgramSelections.ToList())
{
if (Program.Canceled)
break;
Program.Cleanup(cancel: false, logout: false);
bool Check()
{
if (selection.ProgramIsRunning)
{
if (new DialogForm(this).Show(Program.ApplicationName, SystemIcons.Error,
$"ERROR: {selection.ProgramName} is currently running!" +
"\n\nPlease close the program/game to continue . . .",
"Retry", "Cancel") == DialogResult.OK)
return Check();
}
else
{
return true;
}
return false;
}
if (!Check())
{
throw new Exception("The operation was canceled.");
}
try
{
await OperateFor(selection);
UpdateUser($"Operation succeeded for {selection.ProgramName}.", LogColor.Success);
selection.Remove();
}
catch (Exception exception)
{
UpdateUser($"Operation failed for {selection.ProgramName}: " + exception.Message, LogColor.Error);
}
}
Program.Cleanup(logout: false);
if (Program.ProgramSelections.Count == 1)
{
throw new Exception($"Operation failed for {Program.ProgramSelections.First().ProgramName}.");
}
else if (Program.ProgramSelections.Count > 1)
{
throw new Exception($"Operation failed for {Program.ProgramSelections.Count} programs.");
}
}
@ -145,20 +225,20 @@ namespace CreamInstaller
acceptButton.Enabled = false;
retryButton.Enabled = false;
cancelButton.Enabled = true;
reselectButton.Enabled = false;
try
{
await Install();
Program.Cleanup();
UpdateUser("CreamAPI successfully downloaded and installed for " + ProgramCount + " program(s)", LogColor.Success);
await Operate();
UpdateUser("CreamAPI successfully downloaded and installed for " + ProgramCount + " program(s).", LogColor.Success);
}
catch (Exception exception)
{
Program.Cleanup(logout: false);
UpdateUser("Operation failed: " + exception.Message, LogColor.Error);
UpdateUser("CreamAPI download and/or installation failed: " + exception.Message, LogColor.Error);
retryButton.Enabled = true;
}
acceptButton.Enabled = true;
cancelButton.Enabled = false;
reselectButton.Enabled = true;
}
private void OnLoad(object sender, EventArgs e)
@ -170,6 +250,7 @@ namespace CreamInstaller
private void OnAccept(object sender, EventArgs e)
{
Program.Cleanup(logout: false);
Close();
}
@ -183,5 +264,12 @@ namespace CreamInstaller
{
Program.Cleanup(logout: false);
}
private void OnReselect(object sender, EventArgs e)
{
Program.Cleanup(logout: false);
Reselecting = true;
Close();
}
}
}

View file

@ -104,7 +104,7 @@ namespace CreamInstaller
}
catch (ApiException)
{
if (new DialogForm(this).Show(Program.ApplicationName, SystemIcons.Warning,
if (new DialogForm(this).Show(Program.ApplicationName, SystemIcons.Error,
$"ERROR: Failed logging into MEGA!" +
"\n\nMEGA is likely offline, please try again later. . .",
"Retry", "Cancel") == DialogResult.OK)

View file

@ -28,6 +28,8 @@ namespace CreamInstaller
public static string CurrentProcessFilePath = CurrentProcess.MainModule.FileName;
public static string CurrentProcessDirectory = CurrentProcessFilePath.Substring(0, CurrentProcessFilePath.LastIndexOf("\\"));
public static string BackupFileExtension = ".creaminstaller.backup";
[STAThread]
static void Main()
{

View file

@ -10,6 +10,20 @@ namespace CreamInstaller
public List<string> SteamApiDllDirectories;
public INode DownloadNode;
public bool ProgramIsRunning
{
get
{
foreach (string directory in SteamApiDllDirectories)
{
string file = directory + "\\steam_api64.dll";
if (file.IsFilePathLocked())
return true;
}
return false;
}
}
public ProgramSelection()
{
Program.ProgramSelections.Add(this);

View file

@ -38,6 +38,7 @@ namespace CreamInstaller
this.label1 = new System.Windows.Forms.Label();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.allCheckBox = new System.Windows.Forms.CheckBox();
this.noneFoundLabel = new System.Windows.Forms.Label();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.label2 = new System.Windows.Forms.Label();
@ -80,6 +81,7 @@ namespace CreamInstaller
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox1.Controls.Add(this.allCheckBox);
this.groupBox1.Controls.Add(this.noneFoundLabel);
this.groupBox1.Controls.Add(this.flowLayoutPanel1);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
@ -103,6 +105,18 @@ namespace CreamInstaller
this.allCheckBox.UseVisualStyleBackColor = true;
this.allCheckBox.CheckedChanged += new System.EventHandler(this.OnAllCheckBoxChanged);
//
// noneFoundLabel
//
this.noneFoundLabel.Dock = System.Windows.Forms.DockStyle.Fill;
this.noneFoundLabel.Enabled = false;
this.noneFoundLabel.Location = new System.Drawing.Point(3, 19);
this.noneFoundLabel.Name = "noneFoundLabel";
this.noneFoundLabel.Size = new System.Drawing.Size(454, 170);
this.noneFoundLabel.TabIndex = 0;
this.noneFoundLabel.Text = "No CreamAPI-applicable programs or games were found on your computer!";
this.noneFoundLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
this.noneFoundLabel.Visible = false;
//
// flowLayoutPanel1
//
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
@ -169,6 +183,7 @@ namespace CreamInstaller
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label label2;
private System.Windows.Forms.CheckBox allCheckBox;
private Label noneFoundLabel;
}
}

View file

@ -8,6 +8,7 @@ using Gameloop.Vdf;
using Gameloop.Vdf.Linq;
using System.Threading.Tasks;
using System.Drawing;
using System.Linq;
namespace CreamInstaller
{
@ -60,14 +61,14 @@ namespace CreamInstaller
if (steamApiDllDirectories is null)
steamApiDllDirectories = new();
string file = gameDirectory + "\\steam_api64.dll";
if (File.Exists(file) && !file.IsFilePathLocked())
{
if (File.Exists(file))
steamApiDllDirectories.Add(gameDirectory);
}
foreach (string _directory in Directory.GetDirectories(gameDirectory))
{
GetSteamApiDllDirectoriesFromGameDirectory(_directory, steamApiDllDirectories);
}
if (!steamApiDllDirectories.Any())
return null;
return steamApiDllDirectories;
}
@ -113,11 +114,13 @@ namespace CreamInstaller
{
progress.Report(++curProgress);
string rootDirectory;
List<string> directories;
List<string> directories = null;
if (node.Name == "Paradox Launcher")
{
rootDirectory = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
directories = GetSteamApiDllDirectoriesFromGameDirectory(rootDirectory + "\\Programs\\Paradox Interactive");
string launcherDirectory = rootDirectory + "\\Programs\\Paradox Interactive";
if (Directory.Exists(launcherDirectory))
directories = GetSteamApiDllDirectoriesFromGameDirectory(launcherDirectory);
}
else
{
@ -211,20 +214,63 @@ namespace CreamInstaller
label2.Hide();
progressBar1.Hide();
if (Program.ProgramSelections.Any())
{
allCheckBox.Enabled = true;
foreach (CheckBox checkBox in checkBoxes)
checkBox.Enabled = true;
acceptButton.Enabled = true;
}
else
{
noneFoundLabel.Visible = true;
}
}
private void OnAccept(object sender, EventArgs e)
{
if (Program.ProgramSelections.Count > 0)
{
foreach (ProgramSelection selection in Program.ProgramSelections)
{
bool Check()
{
if (selection.ProgramIsRunning)
{
if (new DialogForm(this).Show(Program.ApplicationName, SystemIcons.Error,
$"ERROR: {selection.ProgramName} is currently running!" +
"\n\nPlease close the program/game to continue . . .",
"Retry", "Cancel") == DialogResult.OK)
return Check();
}
else
{
return true;
}
return false;
}
if (!Check())
return;
}
Hide();
new InstallForm(this).ShowDialog();
Close();
InstallForm installForm = new InstallForm(this);
installForm.ShowDialog();
if (installForm.Reselecting)
{
foreach (CheckBox checkBox in checkBoxes)
{
checkBox.Checked = !checkBox.Checked;
checkBox.Checked = !checkBox.Checked; // to fire CheckChanged
}
int X = (installForm.Location.X + installForm.Size.Width / 2) - Size.Width / 2;
int Y = (installForm.Location.Y + installForm.Size.Height / 2) - Size.Height / 2;
Location = new Point(X, Y);
Show();
}
else Close();
}
}