From 8572c5f03b9e7a09b3172137815d411dbe41a40a Mon Sep 17 00:00:00 2001 From: pointfeev Date: Tue, 20 Dec 2022 19:25:08 -0500 Subject: [PATCH] v4.3.0.1 - Fixed parsing of DLC appid 0 --- CreamInstaller/Components/ContextMenuItem.cs | 52 +-- CreamInstaller/Components/CustomForm.cs | 6 +- .../Components/PlatformIdComparer.cs | 6 +- CreamInstaller/CreamInstaller.csproj | 2 +- .../Platforms/Epic/GraphQL/Request.cs | 8 +- CreamInstaller/Platforms/Steam/SteamCMD.cs | 85 ++-- CreamInstaller/Platforms/Steam/SteamStore.cs | 4 +- CreamInstaller/ProgramSelection.cs | 59 +-- CreamInstaller/Resources/Resources.cs | 412 +++++++++--------- CreamInstaller/Utility/IconGrabber.cs | 10 +- 10 files changed, 322 insertions(+), 322 deletions(-) diff --git a/CreamInstaller/Components/ContextMenuItem.cs b/CreamInstaller/Components/ContextMenuItem.cs index 4247867..67e0cf9 100644 --- a/CreamInstaller/Components/ContextMenuItem.cs +++ b/CreamInstaller/Components/ContextMenuItem.cs @@ -13,6 +13,32 @@ internal class ContextMenuItem : ToolStripMenuItem { private static readonly ConcurrentDictionary images = new(); + private readonly EventHandler OnClickEvent; + + internal ContextMenuItem(string text, EventHandler onClick = null) + { + Text = text; + OnClickEvent = onClick; + } + + internal ContextMenuItem(string text, string imageIdentifier, EventHandler onClick = null) + : this(text, onClick) => _ = TryImageIdentifier(this, imageIdentifier); + + internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, EventHandler onClick = null) + : this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo); + + internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, + string imageIdentifierFallback, EventHandler onClick = null) + : this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, + async () => await TryImageIdentifier( + this, imageIdentifierFallback)); + + internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, + (string id, string iconUrl) imageIdentifierInfoFallback, EventHandler onClick = null) + : this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, + async () => await TryImageIdentifierInfo( + this, imageIdentifierInfoFallback)); + private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier) => await Task.Run( async () => { @@ -101,36 +127,10 @@ internal class ContextMenuItem : ToolStripMenuItem } }); - private readonly EventHandler OnClickEvent; - protected override void OnClick(EventArgs e) { base.OnClick(e); if (OnClickEvent is null) return; OnClickEvent.Invoke(this, e); } - - internal ContextMenuItem(string text, EventHandler onClick = null) - { - Text = text; - OnClickEvent = onClick; - } - - internal ContextMenuItem(string text, string imageIdentifier, EventHandler onClick = null) - : this(text, onClick) => _ = TryImageIdentifier(this, imageIdentifier); - - internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, EventHandler onClick = null) - : this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo); - - internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, - string imageIdentifierFallback, EventHandler onClick = null) - : this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, - async () => await TryImageIdentifier( - this, imageIdentifierFallback)); - - internal ContextMenuItem(string text, (string id, string iconUrl) imageIdentifierInfo, - (string id, string iconUrl) imageIdentifierInfoFallback, EventHandler onClick = null) - : this(text, onClick) => _ = TryImageIdentifierInfo(this, imageIdentifierInfo, - async () => await TryImageIdentifierInfo( - this, imageIdentifierInfoFallback)); } \ No newline at end of file diff --git a/CreamInstaller/Components/CustomForm.cs b/CreamInstaller/Components/CustomForm.cs index 549b7db..4a95650 100644 --- a/CreamInstaller/Components/CustomForm.cs +++ b/CreamInstaller/Components/CustomForm.cs @@ -15,8 +15,8 @@ internal class CustomForm : Form internal const short SWP_NOMOVE = 0x0002; internal const short SWP_NOSIZE = 0x0001; - internal static readonly IntPtr HWND_NOTOPMOST = new(-2); - internal static readonly IntPtr HWND_TOPMOST = new(-1); + internal static readonly nint HWND_NOTOPMOST = new(-2); + internal static readonly nint HWND_TOPMOST = new(-1); internal CustomForm() { @@ -96,7 +96,7 @@ internal class CustomForm : Form [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)] [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, + internal static extern void SetWindowPos(nint hWnd, nint hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags); internal void BringToFrontWithoutActivation() diff --git a/CreamInstaller/Components/PlatformIdComparer.cs b/CreamInstaller/Components/PlatformIdComparer.cs index f2b15cd..c6cfb92 100644 --- a/CreamInstaller/Components/PlatformIdComparer.cs +++ b/CreamInstaller/Components/PlatformIdComparer.cs @@ -8,15 +8,15 @@ namespace CreamInstaller.Components; internal static class PlatformIdComparer { private static StringComparer stringComparer; - internal static StringComparer String => stringComparer ??= new StringComparer(); private static NodeComparer nodeComparer; - internal static NodeComparer Node => nodeComparer ??= new NodeComparer(); private static NodeNameComparer nodeNameComparer; - internal static NodeNameComparer NodeName => nodeNameComparer ??= new NodeNameComparer(); private static NodeTextComparer nodeTextComparer; + internal static StringComparer String => stringComparer ??= new StringComparer(); + internal static NodeComparer Node => nodeComparer ??= new NodeComparer(); + internal static NodeNameComparer NodeName => nodeNameComparer ??= new NodeNameComparer(); internal static NodeTextComparer NodeText => nodeTextComparer ??= new NodeTextComparer(); } diff --git a/CreamInstaller/CreamInstaller.csproj b/CreamInstaller/CreamInstaller.csproj index 1e75f35..fc9e8c4 100644 --- a/CreamInstaller/CreamInstaller.csproj +++ b/CreamInstaller/CreamInstaller.csproj @@ -4,7 +4,7 @@ net7.0-windows True Resources\ini.ico - 4.3.0.0 + 4.3.0.1 2021, pointfeev (https://github.com/pointfeev) CreamInstaller Automatic DLC Unlocker Installer & Configuration Generator diff --git a/CreamInstaller/Platforms/Epic/GraphQL/Request.cs b/CreamInstaller/Platforms/Epic/GraphQL/Request.cs index c4e2e4d..d33af00 100644 --- a/CreamInstaller/Platforms/Epic/GraphQL/Request.cs +++ b/CreamInstaller/Platforms/Epic/GraphQL/Request.cs @@ -9,6 +9,8 @@ namespace CreamInstaller.Platforms.Epic.GraphQL; internal class Request { + internal Request(string @namespace) => Vars = new Variables(@namespace); + [JsonProperty(PropertyName = "query")] private string Query => @"query searchOffers($namespace: String!) { Catalog { @@ -58,8 +60,6 @@ internal class Request [JsonProperty(PropertyName = "variables")] private Variables Vars { get; set; } - internal Request(string @namespace) => Vars = new Variables(@namespace); - private class Headers { [JsonProperty(PropertyName = "Content-Type")] @@ -68,9 +68,9 @@ internal class Request private class Variables { + internal Variables(string @namespace) => Namespace = @namespace; + [JsonProperty(PropertyName = "namespace")] private string Namespace { get; set; } - - internal Variables(string @namespace) => Namespace = @namespace; } } \ No newline at end of file diff --git a/CreamInstaller/Platforms/Steam/SteamCMD.cs b/CreamInstaller/Platforms/Steam/SteamCMD.cs index 12fc237..16a0628 100644 --- a/CreamInstaller/Platforms/Steam/SteamCMD.cs +++ b/CreamInstaller/Platforms/Steam/SteamCMD.cs @@ -217,7 +217,7 @@ internal static class SteamCMD goto restart; } } - if (Program.Canceled || output is null) return null; + if (Program.Canceled) return null; if (!ValveDataFile.TryDeserialize(output, out VProperty appInfo) || appInfo.Value is VValue) { File.Delete(appUpdateFile); @@ -225,62 +225,61 @@ internal static class SteamCMD } if (appInfo is null || appInfo.Value?.Children()?.ToList()?.Count == 0) return appInfo; VToken type = appInfo.Value?.GetChild("common")?.GetChild("type"); - if (type is null || type.ToString() == "Game") - { - string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch) - ?.GetChild("buildid")?.ToString(); - if (buildid is null && type is not null) return appInfo; - if (type is null || (int.TryParse(buildid, out int gamebuildId) && gamebuildId < buildId)) - { - List dlcAppIds = await ParseDlcAppIds(appInfo); - foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf")) - if (File.Exists(dlcAppUpdateFile)) - File.Delete(dlcAppUpdateFile); - if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile); - goto restart; - } - } - return appInfo; + if (type is not null && type.ToString() != "Game") + return appInfo; + string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch) + ?.GetChild("buildid")?.ToString(); + if (buildid is null && type is not null) return appInfo; + if (type is not null && (!int.TryParse(buildid, out int gamebuildId) || gamebuildId >= buildId)) + return appInfo; + List dlcAppIds = await ParseDlcAppIds(appInfo); + foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf")) + if (File.Exists(dlcAppUpdateFile)) + File.Delete(dlcAppUpdateFile); + if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile); + goto restart; } internal static async Task> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() => { List dlcIds = new(); -#pragma warning disable IDE0150 // Prefer 'null' check over type check - if (Program.Canceled || appInfo is not VProperty) return dlcIds; -#pragma warning restore IDE0150 // Prefer 'null' check over type check + if (Program.Canceled || appInfo is null) return dlcIds; VToken extended = appInfo.Value.GetChild("extended"); if (extended is not null) -#pragma warning disable IDE0220 // Add explicit cast - foreach (VProperty property in extended.Where(p => p is VProperty && (p as VProperty).Key == "listofdlc")) + foreach (VToken vToken in extended.Where(p => p is VProperty { Key: "listofdlc" })) + { + VProperty property = (VProperty)vToken; foreach (string id in property.Value.ToString().Split(",")) - if (int.TryParse(id, out int appId) && !dlcIds.Contains("" + appId)) + if (int.TryParse(id, out int appId) && appId > 0 && !dlcIds.Contains("" + appId)) dlcIds.Add("" + appId); + } VToken depots = appInfo.Value.GetChild("depots"); - if (depots is not null) - foreach (VProperty property in depots.Where( - p => p is VProperty && int.TryParse((p as VProperty).Key, out int _))) - if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) - && !dlcIds.Contains("" + appId)) - dlcIds.Add("" + appId); -#pragma warning restore IDE0220 // Add explicit cast + if (depots is null) + return dlcIds; + foreach (VToken vToken in depots.Where(p => p is VProperty property && int.TryParse(property.Key, out int _))) + { + VProperty property = (VProperty)vToken; + if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0 + && !dlcIds.Contains("" + appId)) + dlcIds.Add("" + appId); + } return dlcIds; }); - internal static async Task Kill() + private static async Task Kill() { - List tasks = new(); - foreach (Process process in Process.GetProcessesByName("steamcmd")) - tasks.Add(Task.Run(() => - { - try - { - process.Kill(true); - process.WaitForExit(); - process.Close(); - } - catch { } - })); + List tasks = Process.GetProcessesByName("steamcmd") + .Select(process => Task.Run(() => + { + try + { + process.Kill(true); + process.WaitForExit(); + process.Close(); + } + catch { } + })) + .ToList(); foreach (Task task in tasks) await task; } diff --git a/CreamInstaller/Platforms/Steam/SteamStore.cs b/CreamInstaller/Platforms/Steam/SteamStore.cs index ae6d11e..b2dee78 100644 --- a/CreamInstaller/Platforms/Steam/SteamStore.cs +++ b/CreamInstaller/Platforms/Steam/SteamStore.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using CreamInstaller.Forms; @@ -21,8 +22,7 @@ internal static class SteamStore { List dlcIds = new(); if (appData.dlc is null) return dlcIds; - foreach (int appId in appData.dlc) - dlcIds.Add(appId.ToString()); + dlcIds.AddRange(from appId in appData.dlc where appId > 0 select appId.ToString()); return dlcIds; }); diff --git a/CreamInstaller/ProgramSelection.cs b/CreamInstaller/ProgramSelection.cs index caa38d1..86507b0 100644 --- a/CreamInstaller/ProgramSelection.cs +++ b/CreamInstaller/ProgramSelection.cs @@ -21,39 +21,44 @@ public enum DlcType internal class ProgramSelection { - internal bool Enabled; - internal bool Koaloader; internal const string DefaultKoaloaderProxy = "version"; - internal string KoaloaderProxy; - internal Platform Platform; - internal string Id = "0"; - internal string Name = "Program"; - - internal string ProductUrl; - internal string IconUrl; - internal string SubIconUrl; - - internal string Publisher; - - internal string WebsiteUrl; - - internal string RootDirectory; - internal List<(string directory, BinaryType binaryType)> ExecutableDirectories; - internal List DllDirectories; + internal static readonly List All = new(); internal readonly SortedList AllDlc = new(PlatformIdComparer.String); - internal readonly SortedList SelectedDlc - = new(PlatformIdComparer.String); - internal readonly List<(string id, string name, SortedList dlc)> ExtraDlc = new(); // for Paradox Launcher internal readonly List<(string id, string name, SortedList dlc)> ExtraSelectedDlc = new(); // for Paradox Launcher + internal readonly SortedList SelectedDlc + = new(PlatformIdComparer.String); + + internal List DllDirectories; + internal bool Enabled; + internal List<(string directory, BinaryType binaryType)> ExecutableDirectories; + internal string IconUrl; + internal string Id = "0"; + internal bool Koaloader; + internal string KoaloaderProxy; + internal string Name = "Program"; + + internal Platform Platform; + + internal string ProductUrl; + + internal string Publisher; + + internal string RootDirectory; + internal string SubIconUrl; + + internal string WebsiteUrl; + + internal ProgramSelection() => All.Add(this); + internal bool AreDllsLocked { get @@ -117,6 +122,10 @@ internal class ProgramSelection } } + internal static List AllSafe => All.ToList(); + + internal static List AllEnabled => AllSafe.FindAll(s => s.Enabled); + private void Toggle(string dlcAppId, (DlcType type, string name, string icon) dlcApp, bool enabled) { if (enabled) SelectedDlc[dlcAppId] = dlcApp; @@ -138,8 +147,6 @@ internal class ProgramSelection Enabled = SelectedDlc.Any() || ExtraSelectedDlc.Any(); } - internal ProgramSelection() => All.Add(this); - internal void Validate() { if (Program.IsGameBlocked(Name, RootDirectory)) @@ -171,12 +178,6 @@ internal class ProgramSelection internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan) => AllSafe.ForEach(selection => selection.Validate(programsToScan)); - internal static readonly List All = new(); - - internal static List AllSafe => All.ToList(); - - internal static List AllEnabled => AllSafe.FindAll(s => s.Enabled); - internal static ProgramSelection FromPlatformId(Platform platform, string gameId) => AllSafe.Find(s => s.Platform == platform && s.Id == gameId); diff --git a/CreamInstaller/Resources/Resources.cs b/CreamInstaller/Resources/Resources.cs index 085e4d7..e9441bb 100644 --- a/CreamInstaller/Resources/Resources.cs +++ b/CreamInstaller/Resources/Resources.cs @@ -15,212 +15,6 @@ internal static class Resources { internal static List embeddedResources; - internal static List EmbeddedResources - { - get - { - if (embeddedResources is null) - { - string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); - embeddedResources = new List(); - foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources."))) - embeddedResources.Add(resourceName[25..]); - } - return embeddedResources; - } - } - - internal static void Write(this string resourceIdentifier, string filePath) - { - using Stream resource = Assembly.GetExecutingAssembly() - .GetManifestResourceStream("CreamInstaller.Resources." + resourceIdentifier); - using FileStream file = new(filePath, FileMode.Create, FileAccess.Write); - resource.CopyTo(file); - } - - internal static void Write(this byte[] resource, string filePath) - { - using FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write); - fileStream.Write(resource); - } - - 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 enum BinaryType - { - Unknown = -1, BIT32 = 0, DOS = 1, - WOW = 2, PIF = 3, POSIX = 4, - OS216 = 5, BIT64 = 6 - } - - [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern bool GetBinaryType(string lpApplicationName, out BinaryType lpBinaryType); - - internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) - => GetBinaryType(path, out binaryType); - - internal static async Task> GetExecutableDirectories( - this string rootDirectory, bool filterCommon = false, Func validFunc = null) => - await Task.Run(async () => (await rootDirectory.GetExecutables(filterCommon, validFunc) - ?? (filterCommon || validFunc is not null - ? await rootDirectory.GetExecutables() - : null))?.Select(e => - { - e.path = Path.GetDirectoryName(e.path); - return e; - })?.DistinctBy(e => e.path).ToList()); - - internal static async Task> GetExecutables( - this string rootDirectory, bool filterCommon = false, Func validFunc = null) => await Task.Run( - () => - { - List<(string path, BinaryType binaryType)> executables = new(); - if (Program.Canceled || !Directory.Exists(rootDirectory)) return null; - foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", - new EnumerationOptions { RecurseSubdirectories = true })) - { - if (Program.Canceled) return null; - if (!executables.Any(e => e.path == path) - && (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) - && (validFunc is null || validFunc(path)) - && path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64) - executables.Add((path, binaryType)); - Thread.Sleep(1); - } - foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", - new EnumerationOptions { RecurseSubdirectories = true })) - { - if (Program.Canceled) return null; - if (!executables.Any(e => e.path == path) - && (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) - && (validFunc is null || validFunc(path)) - && path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT32) - executables.Add((path, binaryType)); - Thread.Sleep(1); - } - return !executables.Any() ? null : executables; - }); - - internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path) - { - string subPath = path[rootDirectory.Length..].ToUpperInvariant().BeautifyPath(); - return subPath.Contains("SETUP") - || subPath.Contains("REDIST") - || subPath.Contains("SUPPORT") - || (subPath.Contains("CRASH") && (subPath.Contains("PAD") || subPath.Contains("REPORT"))) - || subPath.Contains("HELPER") - || subPath.Contains("CEFPROCESS") - || subPath.Contains("ZFGAMEBROWSER") - || subPath.Contains("MONO") - || subPath.Contains("PLUGINS") - || subPath.Contains("MODDING") - || (subPath.Contains("MOD") && subPath.Contains("MANAGER")) - || subPath.Contains("BATTLEYE") - || subPath.Contains("ANTICHEAT"); - } - - internal static async Task> GetDllDirectoriesFromGameDirectory( - this string gameDirectory, Platform platform) => await Task.Run(() => - { - List dllDirectories = new(); - if (Program.Canceled || !Directory.Exists(gameDirectory)) return null; - foreach (string directory in Directory - .EnumerateDirectories(gameDirectory, "*", - new EnumerationOptions { RecurseSubdirectories = true }) - .Append(gameDirectory)) - { - if (Program.Canceled) return null; - string subDirectory = directory.BeautifyPath(); - if (!dllDirectories.Contains(subDirectory)) - { - bool koaloaderInstalled = Koaloader.AutoLoadDlls - .Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll)) - .Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile()); - if (platform is Platform.Steam or Platform.Paradox) - { - subDirectory.GetSmokeApiComponents(out string api, out string api_o, out string api64, - out string api64_o, out string config, out string cache); - if (File.Exists(api) - || File.Exists(api_o) - || File.Exists(api64) - || File.Exists(api64_o) - || (File.Exists(config) && !koaloaderInstalled) - || (File.Exists(cache) && !koaloaderInstalled)) - dllDirectories.Add(subDirectory); - } - if (platform is Platform.Epic or Platform.Paradox) - { - subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, - out string api64_o, out string config); - if (File.Exists(api32) - || File.Exists(api32_o) - || File.Exists(api64) - || File.Exists(api64_o) - || (File.Exists(config) && !koaloaderInstalled)) - dllDirectories.Add(subDirectory); - } - if (platform is Platform.Ubisoft) - { - subDirectory.GetUplayR1Components(out string api32, out string api32_o, out string api64, - out string api64_o, out string config); - if (File.Exists(api32) - || File.Exists(api32_o) - || File.Exists(api64) - || File.Exists(api64_o) - || (File.Exists(config) && !koaloaderInstalled)) - dllDirectories.Add(subDirectory); - subDirectory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, - out api32_o, out api64, out api64_o, out config); - if (File.Exists(old_api32) - || File.Exists(old_api64) - || File.Exists(api32) - || File.Exists(api32_o) - || File.Exists(api64) - || File.Exists(api64_o) - || (File.Exists(config) && !koaloaderInstalled)) - dllDirectories.Add(subDirectory); - } - } - } - return !dllDirectories.Any() ? null : dllDirectories; - }); - - internal static void GetCreamApiComponents( - this string directory, - out string api32, out string api32_o, - out string api64, out string api64_o, - out string config) - { - api32 = directory + @"\steam_api.dll"; - api32_o = directory + @"\steam_api_o.dll"; - api64 = directory + @"\steam_api64.dll"; - api64_o = directory + @"\steam_api64_o.dll"; - config = directory + @"\cream_api.ini"; - } - - internal enum ResourceIdentifier - { - Koaloader, Steamworks32, Steamworks64, - EpicOnlineServices32, EpicOnlineServices64, Uplay32, - Uplay64, Upc32, Upc64 - } - internal static readonly Dictionary> ResourceMD5s = new() { { @@ -534,6 +328,198 @@ internal static class Resources } }; + internal static List EmbeddedResources + { + get + { + if (embeddedResources is null) + { + string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + embeddedResources = new List(); + foreach (string resourceName in names.Where(n => n.StartsWith("CreamInstaller.Resources."))) + embeddedResources.Add(resourceName[25..]); + } + return embeddedResources; + } + } + + internal static void Write(this string resourceIdentifier, string filePath) + { + using Stream resource = Assembly.GetExecutingAssembly() + .GetManifestResourceStream("CreamInstaller.Resources." + resourceIdentifier); + using FileStream file = new(filePath, FileMode.Create, FileAccess.Write); + resource.CopyTo(file); + } + + internal static void Write(this byte[] resource, string filePath) + { + using FileStream fileStream = new(filePath, FileMode.Create, FileAccess.Write); + fileStream.Write(resource); + } + + 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; + } + + [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static extern bool GetBinaryType(string lpApplicationName, out BinaryType lpBinaryType); + + internal static bool TryGetFileBinaryType(this string path, out BinaryType binaryType) + => GetBinaryType(path, out binaryType); + + internal static async Task> GetExecutableDirectories( + this string rootDirectory, bool filterCommon = false, Func validFunc = null) => + await Task.Run(async () => (await rootDirectory.GetExecutables(filterCommon, validFunc) + ?? (filterCommon || validFunc is not null + ? await rootDirectory.GetExecutables() + : null))?.Select(e => + { + e.path = Path.GetDirectoryName(e.path); + return e; + })?.DistinctBy(e => e.path).ToList()); + + internal static async Task> GetExecutables( + this string rootDirectory, bool filterCommon = false, Func validFunc = null) => await Task.Run( + () => + { + List<(string path, BinaryType binaryType)> executables = new(); + if (Program.Canceled || !Directory.Exists(rootDirectory)) return null; + foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", + new EnumerationOptions { RecurseSubdirectories = true })) + { + if (Program.Canceled) return null; + if (executables.All(e => e.path != path) + && (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) + && (validFunc is null || validFunc(path)) + && path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT64) + executables.Add((path, binaryType)); + Thread.Sleep(1); + } + foreach (string path in Directory.EnumerateFiles(rootDirectory, "*.exe", + new EnumerationOptions { RecurseSubdirectories = true })) + { + if (Program.Canceled) return null; + if (executables.All(e => e.path != path) + && (!filterCommon || !rootDirectory.IsCommonIncorrectExecutable(path)) + && (validFunc is null || validFunc(path)) + && path.TryGetFileBinaryType(out BinaryType binaryType) && binaryType is BinaryType.BIT32) + executables.Add((path, binaryType)); + Thread.Sleep(1); + } + return !executables.Any() ? null : executables; + }); + + internal static bool IsCommonIncorrectExecutable(this string rootDirectory, string path) + { + string subPath = path[rootDirectory.Length..].ToUpperInvariant().BeautifyPath(); + return subPath.Contains("SETUP") + || subPath.Contains("REDIST") + || subPath.Contains("SUPPORT") + || (subPath.Contains("CRASH") && (subPath.Contains("PAD") || subPath.Contains("REPORT"))) + || subPath.Contains("HELPER") + || subPath.Contains("CEFPROCESS") + || subPath.Contains("ZFGAMEBROWSER") + || subPath.Contains("MONO") + || subPath.Contains("PLUGINS") + || subPath.Contains("MODDING") + || (subPath.Contains("MOD") && subPath.Contains("MANAGER")) + || subPath.Contains("BATTLEYE") + || subPath.Contains("ANTICHEAT"); + } + + internal static async Task> GetDllDirectoriesFromGameDirectory( + this string gameDirectory, Platform platform) => await Task.Run(() => + { + List dllDirectories = new(); + if (Program.Canceled || !Directory.Exists(gameDirectory)) return null; + foreach (string directory in Directory + .EnumerateDirectories(gameDirectory, "*", + new EnumerationOptions { RecurseSubdirectories = true }) + .Append(gameDirectory)) + { + if (Program.Canceled) return null; + string subDirectory = directory.BeautifyPath(); + if (!dllDirectories.Contains(subDirectory)) + { + bool koaloaderInstalled = Koaloader.AutoLoadDlls + .Select(pair => (pair.unlocker, path: directory + @"\" + pair.dll)) + .Any(pair => File.Exists(pair.path) && pair.path.IsResourceFile()); + if (platform is Platform.Steam or Platform.Paradox) + { + subDirectory.GetSmokeApiComponents(out string api, out string api_o, out string api64, + out string api64_o, out string config, out string cache); + if (File.Exists(api) + || File.Exists(api_o) + || File.Exists(api64) + || File.Exists(api64_o) + || (File.Exists(config) && !koaloaderInstalled) + || (File.Exists(cache) && !koaloaderInstalled)) + dllDirectories.Add(subDirectory); + } + if (platform is Platform.Epic or Platform.Paradox) + { + subDirectory.GetScreamApiComponents(out string api32, out string api32_o, out string api64, + out string api64_o, out string config); + if (File.Exists(api32) + || File.Exists(api32_o) + || File.Exists(api64) + || File.Exists(api64_o) + || (File.Exists(config) && !koaloaderInstalled)) + dllDirectories.Add(subDirectory); + } + if (platform is Platform.Ubisoft) + { + subDirectory.GetUplayR1Components(out string api32, out string api32_o, out string api64, + out string api64_o, out string config); + if (File.Exists(api32) + || File.Exists(api32_o) + || File.Exists(api64) + || File.Exists(api64_o) + || (File.Exists(config) && !koaloaderInstalled)) + dllDirectories.Add(subDirectory); + subDirectory.GetUplayR2Components(out string old_api32, out string old_api64, out api32, + out api32_o, out api64, out api64_o, out config); + if (File.Exists(old_api32) + || File.Exists(old_api64) + || File.Exists(api32) + || File.Exists(api32_o) + || File.Exists(api64) + || File.Exists(api64_o) + || (File.Exists(config) && !koaloaderInstalled)) + dllDirectories.Add(subDirectory); + } + } + } + return !dllDirectories.Any() ? null : dllDirectories; + }); + + internal static void GetCreamApiComponents( + this string directory, + out string api32, out string api32_o, + out string api64, out string api64_o, + out string config) + { + api32 = directory + @"\steam_api.dll"; + api32_o = directory + @"\steam_api_o.dll"; + api64 = directory + @"\steam_api64.dll"; + api64_o = directory + @"\steam_api64_o.dll"; + config = directory + @"\cream_api.ini"; + } + internal static string ComputeMD5(this string filePath) { if (!File.Exists(filePath)) return null; @@ -551,4 +537,18 @@ internal static class Resources internal static bool IsResourceFile(this string filePath) => filePath.ComputeMD5() is string hash && ResourceMD5s.Values.Any( hashes => hashes.Contains(hash)); + + internal enum BinaryType + { + Unknown = -1, BIT32 = 0, DOS = 1, + WOW = 2, PIF = 3, POSIX = 4, + OS216 = 5, BIT64 = 6 + } + + internal enum ResourceIdentifier + { + Koaloader, Steamworks32, Steamworks64, + EpicOnlineServices32, EpicOnlineServices64, Uplay32, + Uplay64, Upc32, Upc64 + } } diff --git a/CreamInstaller/Utility/IconGrabber.cs b/CreamInstaller/Utility/IconGrabber.cs index 7cceb2c..e9951fa 100644 --- a/CreamInstaller/Utility/IconGrabber.cs +++ b/CreamInstaller/Utility/IconGrabber.cs @@ -6,17 +6,17 @@ namespace CreamInstaller.Utility; internal static class IconGrabber { + internal const string SteamAppImagesPath + = "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/"; + + internal const string GoogleFaviconsApiUrl = "https://www.google.com/s2/favicons"; + internal static Icon ToIcon(this Image image) { using Bitmap dialogIconBitmap = new(image, new Size(image.Width, image.Height)); return Icon.FromHandle(dialogIconBitmap.GetHicon()); } - internal const string SteamAppImagesPath - = "https://cdn.cloudflare.steamstatic.com/steamcommunity/public/images/apps/"; - - internal const string GoogleFaviconsApiUrl = "https://www.google.com/s2/favicons"; - internal static string GetDomainFaviconUrl(string domain, int size = 16) => GoogleFaviconsApiUrl + $"?domain={domain}&sz={size}";