Massive code refactoring
This commit is contained in:
parent
d4b62c2068
commit
38f721b125
10 changed files with 300 additions and 259 deletions
65
CreamInstaller/Classes/FileGrabber.cs
Normal file
65
CreamInstaller/Classes/FileGrabber.cs
Normal 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
|
||||
});
|
||||
}
|
48
CreamInstaller/Classes/HttpClientManager.cs
Normal file
48
CreamInstaller/Classes/HttpClientManager.cs
Normal 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();
|
||||
}
|
27
CreamInstaller/Classes/IconGrabber.cs
Normal file
27
CreamInstaller/Classes/IconGrabber.cs
Normal 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");
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
96
CreamInstaller/Classes/SteamLibrary.cs
Normal file
96
CreamInstaller/Classes/SteamLibrary.cs
Normal 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;
|
||||
});
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -22,7 +22,6 @@ internal partial class InstallForm : CustomForm
|
|||
{
|
||||
InitializeComponent();
|
||||
Text = Program.ApplicationName;
|
||||
Program.InstallForm = this;
|
||||
logTextBox.BackColor = InstallationLog.Background;
|
||||
Uninstalling = uninstall;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue