v4.3.0.1
- Fixed parsing of DLC appid 0
This commit is contained in:
parent
99bd3e2425
commit
8572c5f03b
10 changed files with 322 additions and 322 deletions
|
@ -13,6 +13,32 @@ internal class ContextMenuItem : ToolStripMenuItem
|
|||
{
|
||||
private static readonly ConcurrentDictionary<string, Image> 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));
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||
<Version>4.3.0.0</Version>
|
||||
<Version>4.3.0.1</Version>
|
||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||
<Company>CreamInstaller</Company>
|
||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<string> 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<string> 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<List<string>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
|
||||
{
|
||||
List<string> 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<Task> tasks = new();
|
||||
foreach (Process process in Process.GetProcessesByName("steamcmd"))
|
||||
tasks.Add(Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
process.Kill(true);
|
||||
process.WaitForExit();
|
||||
process.Close();
|
||||
}
|
||||
catch { }
|
||||
}));
|
||||
List<Task> 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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<string> 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;
|
||||
});
|
||||
|
||||
|
|
|
@ -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<string> DllDirectories;
|
||||
internal static readonly List<ProgramSelection> All = new();
|
||||
|
||||
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc
|
||||
= new(PlatformIdComparer.String);
|
||||
|
||||
internal readonly SortedList<string, (DlcType type, string name, string icon)> SelectedDlc
|
||||
= new(PlatformIdComparer.String);
|
||||
|
||||
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
||||
ExtraDlc = new(); // for Paradox Launcher
|
||||
|
||||
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
||||
ExtraSelectedDlc = new(); // for Paradox Launcher
|
||||
|
||||
internal readonly SortedList<string, (DlcType type, string name, string icon)> SelectedDlc
|
||||
= new(PlatformIdComparer.String);
|
||||
|
||||
internal List<string> 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<ProgramSelection> AllSafe => All.ToList();
|
||||
|
||||
internal static List<ProgramSelection> 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<ProgramSelection> All = new();
|
||||
|
||||
internal static List<ProgramSelection> AllSafe => All.ToList();
|
||||
|
||||
internal static List<ProgramSelection> AllEnabled => AllSafe.FindAll(s => s.Enabled);
|
||||
|
||||
internal static ProgramSelection FromPlatformId(Platform platform, string gameId)
|
||||
=> AllSafe.Find(s => s.Platform == platform && s.Id == gameId);
|
||||
|
||||
|
|
|
@ -15,212 +15,6 @@ internal static class Resources
|
|||
{
|
||||
internal static List<string> embeddedResources;
|
||||
|
||||
internal static List<string> EmbeddedResources
|
||||
{
|
||||
get
|
||||
{
|
||||
if (embeddedResources is null)
|
||||
{
|
||||
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
embeddedResources = new List<string>();
|
||||
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<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||
this string rootDirectory, bool filterCommon = false, Func<string, bool> 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<List<(string path, BinaryType binaryType)>> GetExecutables(
|
||||
this string rootDirectory, bool filterCommon = false, Func<string, bool> 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<List<string>> GetDllDirectoriesFromGameDirectory(
|
||||
this string gameDirectory, Platform platform) => await Task.Run(() =>
|
||||
{
|
||||
List<string> 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<ResourceIdentifier, IReadOnlyList<string>> ResourceMD5s = new()
|
||||
{
|
||||
{
|
||||
|
@ -534,6 +328,198 @@ internal static class Resources
|
|||
}
|
||||
};
|
||||
|
||||
internal static List<string> EmbeddedResources
|
||||
{
|
||||
get
|
||||
{
|
||||
if (embeddedResources is null)
|
||||
{
|
||||
string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames();
|
||||
embeddedResources = new List<string>();
|
||||
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<List<(string directory, BinaryType binaryType)>> GetExecutableDirectories(
|
||||
this string rootDirectory, bool filterCommon = false, Func<string, bool> 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<List<(string path, BinaryType binaryType)>> GetExecutables(
|
||||
this string rootDirectory, bool filterCommon = false, Func<string, bool> 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<List<string>> GetDllDirectoriesFromGameDirectory(
|
||||
this string gameDirectory, Platform platform) => await Task.Run(() =>
|
||||
{
|
||||
List<string> 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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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}";
|
||||
|
||||
|
|
Loading…
Reference in a new issue