Massive code refactoring

This commit is contained in:
pointfeev 2022-02-24 23:12:48 -05:00
parent d4b62c2068
commit 38f721b125
10 changed files with 300 additions and 259 deletions

View file

@ -0,0 +1,65 @@
using System.Diagnostics;
using System.IO;
using Microsoft.Win32;
namespace CreamInstaller.Classes;
internal static class FileGrabber
{
internal static string steamInstallPath = null;
internal static string SteamInstallPath
{
get
{
steamInstallPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Valve\Steam", "InstallPath", null) as string;
steamInstallPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Wow6432Node\Valve\Steam", "InstallPath", null) as string;
return steamInstallPath;
}
}
internal static string paradoxLauncherInstallPath = null;
internal static string ParadoxLauncherInstallPath
{
get
{
paradoxLauncherInstallPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
return paradoxLauncherInstallPath;
}
}
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 IsFilePathLocked(this string filePath)
{
try { File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None).Close(); }
catch (FileNotFoundException) { return false; }
catch (IOException) { return true; }
return false;
}
internal static void OpenFileInNotepad(string path) => Process.Start(new ProcessStartInfo
{
FileName = "notepad.exe",
Arguments = path
});
internal static void OpenDirectoryInFileExplorer(string path) => Process.Start(new ProcessStartInfo
{
FileName = "explorer.exe",
Arguments = path
});
internal static void OpenUrlInInternetBrowser(string url) => Process.Start(new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
}

View file

@ -0,0 +1,48 @@
using System;
using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using HtmlAgilityPack;
namespace CreamInstaller.Classes;
internal static class HttpClientManager
{
private static HttpClient httpClient;
internal static void Setup()
{
httpClient = new();
httpClient.DefaultRequestHeaders.Add("user-agent", "CreamInstaller");
}
internal static async Task<HtmlNodeCollection> GetDocumentNodes(string url, string xpath)
{
try
{
using HttpRequestMessage request = new(HttpMethod.Get, url);
using HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using Stream stream = await response.Content.ReadAsStreamAsync();
using StreamReader reader = new(stream, Encoding.UTF8);
HtmlDocument document = new();
document.LoadHtml(reader.ReadToEnd());
return document.DocumentNode.SelectNodes(xpath);
}
catch { return null; }
}
internal static async Task<Image> GetImageFromUrl(string url)
{
try
{
return new Bitmap(await httpClient.GetStreamAsync(url));
}
catch { }
return null;
}
internal static void Cleanup() => httpClient.Dispose();
}

View file

@ -0,0 +1,27 @@
using System;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
namespace CreamInstaller.Classes;
internal static class IconGrabber
{
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 HttpClientManager.GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{iconStaticId}.jpg");
internal static async Task<Image> GetSteamClientIcon(int steamAppId, string clientIconStaticId) => await HttpClientManager.GetImageFromUrl(SteamAppImagesPath + $"/{steamAppId}/{clientIconStaticId}.ico");
internal static Image GetFileIconImage(string path) => File.Exists(path) ? Icon.ExtractAssociatedIcon(path).ToBitmap() : null;
internal static Image GetNotepadImage() => GetFileIconImage(Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\notepad.exe");
internal static Image GetCommandPromptImage() => GetFileIconImage(Environment.SystemDirectory + @"\cmd.exe");
internal static Image GetFileExplorerImage() => GetFileIconImage(Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\explorer.exe");
}

View file

@ -98,7 +98,7 @@ internal class ProgramSelection
internal static void ValidateAll() => AllSafe.ForEach(selection => selection.Validate());
internal static List<ProgramSelection> All => Program.ProgramSelections;
internal static List<ProgramSelection> All => new();
internal static List<ProgramSelection> AllSafe => All.ToList();

View file

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Gameloop.Vdf.Linq;
namespace CreamInstaller.Classes;
internal static class SteamLibrary
{
internal static async Task<List<string>> GetLibraryDirectories() => await Task.Run(() =>
{
List<string> gameDirectories = new();
if (Program.Canceled) return gameDirectories;
string steamInstallPath = FileGrabber.SteamInstallPath;
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
{
string libraryFolder = steamInstallPath + @"\steamapps";
if (Directory.Exists(libraryFolder))
{
gameDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
if (File.Exists(libraryFolders) && ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
{
foreach (VProperty property in result.Value)
if (int.TryParse(property.Key, out int _))
{
string path = property.Value.GetChild("path")?.ToString();
if (string.IsNullOrWhiteSpace(path)) continue;
path += @"\steamapps";
if (Directory.Exists(path) && !gameDirectories.Contains(path)) gameDirectories.Add(path);
}
}
}
}
return gameDirectories;
});
internal static async Task<List<Tuple<int, string, string, int, string>>> GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
{
List<Tuple<int, string, string, int, string>> games = new();
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return null;
string[] files = Directory.GetFiles(libraryDirectory);
foreach (string file in files)
{
if (Program.Canceled) return null;
if (Path.GetExtension(file) == ".acf" && ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
{
string appId = result.Value.GetChild("appid")?.ToString();
string installdir = result.Value.GetChild("installdir")?.ToString();
string name = result.Value.GetChild("name")?.ToString();
string buildId = result.Value.GetChild("buildid")?.ToString();
if (string.IsNullOrWhiteSpace(appId)
|| string.IsNullOrWhiteSpace(installdir)
|| string.IsNullOrWhiteSpace(name)
|| string.IsNullOrWhiteSpace(buildId))
continue;
string branch = result.Value.GetChild("UserConfig")?.GetChild("betakey")?.ToString();
if (string.IsNullOrWhiteSpace(branch)) branch = "public";
string gameDirectory = libraryDirectory + @"\common\" + installdir;
if (!int.TryParse(appId, out int appIdInt)) continue;
if (!int.TryParse(buildId, out int buildIdInt)) continue;
games.Add(new(appIdInt, name, branch, buildIdInt, gameDirectory));
}
}
return !games.Any() ? null : games;
});
internal static async Task<List<string>> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
{
List<string> dllDirectories = new();
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
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)
{
if (Program.Canceled) return null;
try
{
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
}
catch { }
}
return !dllDirectories.Any() ? null : dllDirectories;
});
}

View file

@ -5,7 +5,7 @@
<UseWindowsForms>True</UseWindowsForms>
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<Version>2.4.3.1</Version>
<Version>2.5.0.0</Version>
<PackageIcon>Resources\ini.ico</PackageIcon>
<PackageIconUrl />
<Description>Automatically generates and installs CreamAPI files for Steam games on the user's computer. It can also generate and install CreamAPI for the Paradox Launcher should the user select a Paradox Interactive game.</Description>
@ -43,7 +43,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Gameloop.Vdf" Version="0.6.1" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.40" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.42" />
<PackageReference Include="Onova" Version="2.6.2" />
</ItemGroup>
<ItemGroup>

View file

@ -22,7 +22,6 @@ internal partial class InstallForm : CustomForm
{
InitializeComponent();
Text = Program.ApplicationName;
Program.InstallForm = this;
logTextBox.BackColor = InstallationLog.Background;
Uninstalling = uninstall;
}

View file

@ -2,8 +2,6 @@
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
@ -43,7 +41,6 @@ internal partial class MainForm : CustomForm
Close();
}
private static readonly HttpClient httpClient = new();
private static UpdateManager updateManager = null;
private static Version latestVersion = null;
private static IReadOnlyList<Version> versions;
@ -104,17 +101,11 @@ internal partial class MainForm : CustomForm
changelogTreeView.Nodes.Add(root);
_ = Task.Run(async () =>
{
try
{
string url = $"https://github.com/pointfeev/CreamInstaller/releases/tag/v{version}";
using HttpRequestMessage request = new(HttpMethod.Get, url);
using HttpResponseMessage response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using Stream stream = await response.Content.ReadAsStreamAsync();
using StreamReader reader = new(stream, Encoding.UTF8);
HtmlAgilityPack.HtmlDocument document = new();
document.LoadHtml(reader.ReadToEnd());
foreach (HtmlNode node in document.DocumentNode.SelectNodes("//div[@data-test-selector='body-content']/ul/li"))
HtmlNodeCollection nodes = await HttpClientManager.GetDocumentNodes(
$"https://github.com/pointfeev/CreamInstaller/releases/tag/v{version}",
"//div[@data-test-selector='body-content']/ul/li");
if (nodes is null) changelogTreeView.Nodes.Remove(root);
else foreach (HtmlNode node in nodes)
{
Program.Invoke(changelogTreeView, delegate
{
@ -124,11 +115,6 @@ internal partial class MainForm : CustomForm
root.Expand();
});
}
}
catch
{
changelogTreeView.Nodes.Remove(root);
}
});
}
}

View file

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
@ -24,102 +23,6 @@ internal partial class SelectForm : CustomForm
{
InitializeComponent();
Text = Program.ApplicationName;
Program.SelectForm = this;
}
private static async Task<List<string>> GameLibraryDirectories() => await Task.Run(() =>
{
List<string> gameDirectories = new();
if (Program.Canceled) return gameDirectories;
string steamInstallPath = Program.SteamInstallPath;
if (steamInstallPath != null && Directory.Exists(steamInstallPath))
{
string libraryFolder = steamInstallPath + @"\steamapps";
if (Directory.Exists(libraryFolder))
{
gameDirectories.Add(libraryFolder);
string libraryFolders = libraryFolder + @"\libraryfolders.vdf";
if (File.Exists(libraryFolders) && ValveDataFile.TryDeserialize(File.ReadAllText(libraryFolders, Encoding.UTF8), out VProperty result))
{
foreach (VProperty property in result.Value)
if (int.TryParse(property.Key, out int _))
{
string path = property.Value.GetChild("path")?.ToString();
if (string.IsNullOrWhiteSpace(path)) continue;
path += @"\steamapps";
if (Directory.Exists(path) && !gameDirectories.Contains(path)) gameDirectories.Add(path);
}
}
}
}
return gameDirectories;
});
private static async Task<List<string>> GetDllDirectoriesFromGameDirectory(string gameDirectory) => await Task.Run(async () =>
{
List<string> dllDirectories = new();
if (Program.Canceled || !Directory.Exists(gameDirectory)) return null;
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)
{
if (Program.Canceled) return null;
try
{
List<string> moreDllDirectories = await GetDllDirectoriesFromGameDirectory(_directory);
if (moreDllDirectories is not null) dllDirectories.AddRange(moreDllDirectories);
}
catch { }
}
return !dllDirectories.Any() ? null : dllDirectories;
});
private static async Task<List<Tuple<int, string, string, int, string>>> GetGamesFromLibraryDirectory(string libraryDirectory) => await Task.Run(() =>
{
List<Tuple<int, string, string, int, string>> games = new();
if (Program.Canceled || !Directory.Exists(libraryDirectory)) return null;
string[] files = Directory.GetFiles(libraryDirectory);
foreach (string file in files)
{
if (Program.Canceled) return null;
if (Path.GetExtension(file) == ".acf" && ValveDataFile.TryDeserialize(File.ReadAllText(file, Encoding.UTF8), out VProperty result))
{
string appId = result.Value.GetChild("appid")?.ToString();
string installdir = result.Value.GetChild("installdir")?.ToString();
string name = result.Value.GetChild("name")?.ToString();
string buildId = result.Value.GetChild("buildid")?.ToString();
if (string.IsNullOrWhiteSpace(appId)
|| string.IsNullOrWhiteSpace(installdir)
|| string.IsNullOrWhiteSpace(name)
|| string.IsNullOrWhiteSpace(buildId))
continue;
string branch = result.Value.GetChild("UserConfig")?.GetChild("betakey")?.ToString();
if (string.IsNullOrWhiteSpace(branch)) branch = "public";
string gameDirectory = libraryDirectory + @"\common\" + installdir;
if (!int.TryParse(appId, out int appIdInt)) continue;
if (!int.TryParse(buildId, out int buildIdInt)) continue;
games.Add(new(appIdInt, name, branch, buildIdInt, gameDirectory));
}
}
return !games.Any() ? null : games;
});
internal List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
private List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
{
List<TreeNode> treeNodes = new();
foreach (TreeNode rootNode in nodeCollection)
{
treeNodes.Add(rootNode);
treeNodes.AddRange(GatherTreeNodes(rootNode.Nodes));
}
return treeNodes;
}
private static void UpdateRemaining(Label label, List<string> list, string descriptor) =>
@ -180,12 +83,12 @@ internal partial class SelectForm : CustomForm
{
if (Program.Canceled) return;
List<Tuple<int, string, string, int, string>> applicablePrograms = new();
if (Directory.Exists(Program.ParadoxLauncherInstallPath))
applicablePrograms.Add(new(0, "Paradox Launcher", "", 0, Program.ParadoxLauncherInstallPath));
List<string> gameLibraryDirectories = await GameLibraryDirectories();
if (Directory.Exists(FileGrabber.ParadoxLauncherInstallPath))
applicablePrograms.Add(new(0, "Paradox Launcher", "", 0, FileGrabber.ParadoxLauncherInstallPath));
List<string> gameLibraryDirectories = await SteamLibrary.GetLibraryDirectories();
foreach (string libraryDirectory in gameLibraryDirectories)
{
List<Tuple<int, string, string, int, string>> games = await GetGamesFromLibraryDirectory(libraryDirectory);
List<Tuple<int, string, string, int, string>> games = await SteamLibrary.GetGamesFromLibraryDirectory(libraryDirectory);
if (games is not null)
foreach (Tuple<int, string, string, int, string> game in games)
if (!applicablePrograms.Any(_game => _game.Item1 == game.Item1))
@ -211,7 +114,7 @@ internal partial class SelectForm : CustomForm
Task task = Task.Run(async () =>
{
if (Program.Canceled) return;
List<string> dllDirectories = await GetDllDirectoriesFromGameDirectory(directory);
List<string> dllDirectories = await SteamLibrary.GetDllDirectoriesFromGameDirectory(directory);
if (dllDirectories is null)
{
RemoveFromRemainingGames(name);
@ -436,14 +339,24 @@ internal partial class SelectForm : CustomForm
uninstallButton.Enabled = installButton.Enabled;
}
internal List<TreeNode> TreeNodes => GatherTreeNodes(selectionTreeView.Nodes);
private List<TreeNode> GatherTreeNodes(TreeNodeCollection nodeCollection)
{
List<TreeNode> treeNodes = new();
foreach (TreeNode rootNode in nodeCollection)
{
treeNodes.Add(rootNode);
treeNodes.AddRange(GatherTreeNodes(rootNode.Nodes));
}
return treeNodes;
}
private class TreeNodeSorter : IComparer
{
public int Compare(object a, object b)
{
if (!int.TryParse((a as TreeNode).Name, out int A)) return 1;
if (!int.TryParse((b as TreeNode).Name, out int B)) return 0;
return A > B ? 1 : 0;
}
public int Compare(object a, object b) =>
!int.TryParse((a as TreeNode).Name, out int A) ? 1
: !int.TryParse((b as TreeNode).Name, out int B) ? 0
: A > B ? 1 : 0;
}
private void ShowProgressBar()
@ -484,26 +397,26 @@ internal partial class SelectForm : CustomForm
Dictionary<string, Image> images = new();
Task.Run(async () =>
{
if (Directory.Exists(Program.ParadoxLauncherInstallPath))
if (Directory.Exists(FileGrabber.ParadoxLauncherInstallPath))
{
foreach (string file in Directory.GetFiles(Program.ParadoxLauncherInstallPath, "*.exe"))
foreach (string file in Directory.GetFiles(FileGrabber.ParadoxLauncherInstallPath, "*.exe"))
{
images["Paradox Launcher"] = Program.GetFileIconImage(file);
images["Paradox Launcher"] = IconGrabber.GetFileIconImage(file);
break;
}
}
images["Notepad"] = Program.GetNotepadImage();
images["Command Prompt"] = Program.GetCommandPromptImage();
images["File Explorer"] = Program.GetFileExplorerImage();
images["SteamDB"] = await Program.GetImageFromUrl("https://steamdb.info/favicon.ico");
images["Steam Store"] = await Program.GetImageFromUrl("https://store.steampowered.com/favicon.ico");
images["Steam Community"] = await Program.GetImageFromUrl("https://steamcommunity.com/favicon.ico");
images["Notepad"] = IconGrabber.GetNotepadImage();
images["Command Prompt"] = IconGrabber.GetCommandPromptImage();
images["File Explorer"] = IconGrabber.GetFileExplorerImage();
images["SteamDB"] = await HttpClientManager.GetImageFromUrl("https://steamdb.info/favicon.ico");
images["Steam Store"] = await HttpClientManager.GetImageFromUrl("https://store.steampowered.com/favicon.ico");
images["Steam Community"] = await HttpClientManager.GetImageFromUrl("https://steamcommunity.com/favicon.ico");
});
Image Image(string identifier) => images.GetValueOrDefault(identifier, null);
void TrySetImageAsync(ToolStripMenuItem menuItem, int appId, string iconStaticId, bool client = false) =>
Task.Run(async () =>
{
menuItem.Image = client ? await Program.GetSteamClientIcon(appId, iconStaticId) : await Program.GetSteamIcon(appId, iconStaticId);
menuItem.Image = client ? await IconGrabber.GetSteamClientIcon(appId, iconStaticId) : await IconGrabber.GetSteamIcon(appId, iconStaticId);
images[client ? "ClientIcon_" + appId : "Icon_" + appId] = menuItem.Image;
});
selectionTreeView.NodeMouseClick += (sender, e) =>
@ -540,7 +453,7 @@ internal partial class SelectForm : CustomForm
{
nodeContextMenu.Items.Add(new ToolStripSeparator());
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open AppInfo", Image("Notepad"),
new EventHandler((sender, e) => Program.OpenFileInNotepad(appInfo))));
new EventHandler((sender, e) => FileGrabber.OpenFileInNotepad(appInfo))));
nodeContextMenu.Items.Add(new ToolStripMenuItem("Refresh AppInfo", Image("Command Prompt"),
new EventHandler((sender, e) =>
{
@ -610,25 +523,25 @@ internal partial class SelectForm : CustomForm
}
nodeContextMenu.Items.Add(new ToolStripSeparator());
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open Root Directory", Image("File Explorer"),
new EventHandler((sender, e) => Program.OpenDirectoryInFileExplorer(selection.RootDirectory))));
new EventHandler((sender, e) => FileGrabber.OpenDirectoryInFileExplorer(selection.RootDirectory))));
for (int i = 0; i < selection.SteamApiDllDirectories.Count; i++)
{
string directory = selection.SteamApiDllDirectories[i];
nodeContextMenu.Items.Add(new ToolStripMenuItem($"Open Steamworks Directory ({i + 1})", Image("File Explorer"),
new EventHandler((sender, e) => Program.OpenDirectoryInFileExplorer(directory))));
new EventHandler((sender, e) => FileGrabber.OpenDirectoryInFileExplorer(directory))));
}
}
if (appId != 0)
{
nodeContextMenu.Items.Add(new ToolStripSeparator());
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open SteamDB", Image("SteamDB"),
new EventHandler((sender, e) => Program.OpenUrlInInternetBrowser("https://steamdb.info/app/" + appId))));
new EventHandler((sender, e) => FileGrabber.OpenUrlInInternetBrowser("https://steamdb.info/app/" + appId))));
nodeContextMenu.Items.Add(new ToolStripMenuItem("Open Steam Store", Image("Steam Store"),
new EventHandler((sender, e) => Program.OpenUrlInInternetBrowser("https://store.steampowered.com/app/" + appId))));
new EventHandler((sender, e) => FileGrabber.OpenUrlInInternetBrowser("https://store.steampowered.com/app/" + appId))));
if (selection is not null)
{
ToolStripMenuItem steamCommunity = new("Open Steam Community", Image("ClientIcon_" + node.Name),
new EventHandler((sender, e) => Program.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + appId)));
new EventHandler((sender, e) => FileGrabber.OpenUrlInInternetBrowser("https://steamcommunity.com/app/" + appId)));
nodeContextMenu.Items.Add(steamCommunity);
if (steamCommunity.Image is null)
{
@ -703,7 +616,9 @@ internal partial class SelectForm : CustomForm
}
private void OnInstall(object sender, EventArgs e) => OnAccept(false);
private void OnUninstall(object sender, EventArgs e) => OnAccept(true);
private void OnScan(object sender, EventArgs e) => OnLoad();
private void OnCancel(object sender, EventArgs e)

View file

@ -1,65 +1,29 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using CreamInstaller.Classes;
using Microsoft.Win32;
namespace CreamInstaller;
internal static class Program
{
internal static readonly string ApplicationName = Application.CompanyName + " v" + Application.ProductVersion + ": " + Application.ProductName;
internal static readonly Assembly EntryAssembly = Assembly.GetEntryAssembly();
internal static readonly Process CurrentProcess = Process.GetCurrentProcess();
internal static readonly string CurrentProcessFilePath = CurrentProcess.MainModule.FileName;
internal static readonly string CurrentProcessDirectory = CurrentProcessFilePath[..CurrentProcessFilePath.LastIndexOf("\\")];
internal static readonly string BackupFileExtension = ".creaminstaller.backup";
internal static bool BlockProtectedGames = true;
internal static readonly string[] ProtectedGameNames = { "PAYDAY 2", "Call to Arms" }; // non-functioning CreamAPI or DLL detections
internal static readonly string[] ProtectedGameDirectories = { @"\EasyAntiCheat", @"\BattlEye" }; // DLL detections
internal static readonly string[] ProtectedGameDirectoryExceptions = { "Arma 3" }; // Arma 3's BattlEye doesn't detect DLL changes?
internal static string steamInstallPath = null;
internal static string SteamInstallPath
{
get
{
steamInstallPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Valve\Steam", "InstallPath", null) as string;
steamInstallPath ??= Registry.GetValue(@"HKEY_LOCAL_MACHINE\Software\Wow6432Node\Valve\Steam", "InstallPath", null) as string;
return steamInstallPath;
}
}
internal static string paradoxLauncherInstallPath = null;
internal static string ParadoxLauncherInstallPath
{
get
{
paradoxLauncherInstallPath ??= Registry.GetValue(@"HKEY_CURRENT_USER\Software\Paradox Interactive\Paradox Launcher v2", "LauncherInstallation", null) as string;
return paradoxLauncherInstallPath;
}
}
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;
@ -70,6 +34,20 @@ internal static class Program
return false;
}
internal static bool IsProgramRunningDialog(Form form, ProgramSelection selection)
{
if (selection.AreSteamApiDllsLocked)
{
if (new DialogForm(form).Show(ApplicationName, SystemIcons.Error,
$"ERROR: {selection.Name} is currently running!" +
"\n\nPlease close the program/game to continue . . . ",
"Retry", "Cancel") == DialogResult.OK)
return IsProgramRunningDialog(form, selection);
}
else return true;
return false;
}
[STAThread]
private static void Main()
{
@ -83,6 +61,7 @@ internal static class Program
retry:
try
{
HttpClientManager.Setup();
Application.Run(new MainForm());
}
catch (Exception e)
@ -95,81 +74,8 @@ 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");
internal static async Task<Image> GetImageFromUrl(string url)
{
try
{
HttpClient httpClient = new();
httpClient.DefaultRequestHeaders.Add("user-agent", "CreamInstaller");
return new Bitmap(await httpClient.GetStreamAsync(url));
}
catch { }
return null;
}
internal static void OpenFileInNotepad(string path) => Process.Start(new ProcessStartInfo
{
FileName = "notepad.exe",
Arguments = path
});
internal static void OpenDirectoryInFileExplorer(string path) => Process.Start(new ProcessStartInfo
{
FileName = "explorer.exe",
Arguments = path
});
internal static void OpenUrlInInternetBrowser(string url) => Process.Start(new ProcessStartInfo
{
FileName = url,
UseShellExecute = true
});
internal static Image GetFileIconImage(string path) => File.Exists(path) ? Icon.ExtractAssociatedIcon(path).ToBitmap() : null;
internal static Image GetNotepadImage() => GetFileIconImage(Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\notepad.exe");
internal static Image GetCommandPromptImage() => GetFileIconImage(Environment.SystemDirectory + @"\cmd.exe");
internal static Image GetFileExplorerImage() => GetFileIconImage(Environment.GetFolderPath(Environment.SpecialFolder.Windows) + @"\explorer.exe");
internal static bool IsProgramRunningDialog(Form form, ProgramSelection selection)
{
if (selection.AreSteamApiDllsLocked)
{
if (new DialogForm(form).Show(ApplicationName, SystemIcons.Error,
$"ERROR: {selection.Name} is currently running!" +
"\n\nPlease close the program/game to continue . . . ",
"Retry", "Cancel") == DialogResult.OK)
return IsProgramRunningDialog(form, selection);
}
else return true;
return false;
}
internal static bool IsFilePathLocked(this string filePath)
{
try { File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None).Close(); }
catch (FileNotFoundException) { return false; }
catch (IOException) { return true; }
return false;
}
internal static void Invoke(this Control control, MethodInvoker methodInvoker) => control.Invoke(methodInvoker);
internal static SelectForm SelectForm;
internal static InstallForm InstallForm;
internal static void InheritLocation(this Form form, Form fromForm)
{
int X = fromForm.Location.X + fromForm.Size.Width / 2 - form.Size.Width / 2;
@ -177,12 +83,11 @@ internal static class Program
form.Location = new(X, Y);
}
internal static List<ProgramSelection> ProgramSelections = new();
internal static bool Canceled = false;
internal static async void Cleanup(bool cancel = true)
{
Canceled = cancel;
HttpClientManager.Cleanup();
await SteamCMD.Cleanup();
}