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 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(
|
private static async Task TryImageIdentifier(ContextMenuItem item, string imageIdentifier) => await Task.Run(
|
||||||
async () =>
|
async () =>
|
||||||
{
|
{
|
||||||
|
@ -101,36 +127,10 @@ internal class ContextMenuItem : ToolStripMenuItem
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
private readonly EventHandler OnClickEvent;
|
|
||||||
|
|
||||||
protected override void OnClick(EventArgs e)
|
protected override void OnClick(EventArgs e)
|
||||||
{
|
{
|
||||||
base.OnClick(e);
|
base.OnClick(e);
|
||||||
if (OnClickEvent is null) return;
|
if (OnClickEvent is null) return;
|
||||||
OnClickEvent.Invoke(this, e);
|
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_NOMOVE = 0x0002;
|
||||||
internal const short SWP_NOSIZE = 0x0001;
|
internal const short SWP_NOSIZE = 0x0001;
|
||||||
|
|
||||||
internal static readonly IntPtr HWND_NOTOPMOST = new(-2);
|
internal static readonly nint HWND_NOTOPMOST = new(-2);
|
||||||
internal static readonly IntPtr HWND_TOPMOST = new(-1);
|
internal static readonly nint HWND_TOPMOST = new(-1);
|
||||||
|
|
||||||
internal CustomForm()
|
internal CustomForm()
|
||||||
{
|
{
|
||||||
|
@ -96,7 +96,7 @@ internal class CustomForm : Form
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
|
[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);
|
uint uFlags);
|
||||||
|
|
||||||
internal void BringToFrontWithoutActivation()
|
internal void BringToFrontWithoutActivation()
|
||||||
|
|
|
@ -8,15 +8,15 @@ namespace CreamInstaller.Components;
|
||||||
internal static class PlatformIdComparer
|
internal static class PlatformIdComparer
|
||||||
{
|
{
|
||||||
private static StringComparer stringComparer;
|
private static StringComparer stringComparer;
|
||||||
internal static StringComparer String => stringComparer ??= new StringComparer();
|
|
||||||
|
|
||||||
private static NodeComparer nodeComparer;
|
private static NodeComparer nodeComparer;
|
||||||
internal static NodeComparer Node => nodeComparer ??= new NodeComparer();
|
|
||||||
|
|
||||||
private static NodeNameComparer nodeNameComparer;
|
private static NodeNameComparer nodeNameComparer;
|
||||||
internal static NodeNameComparer NodeName => nodeNameComparer ??= new NodeNameComparer();
|
|
||||||
|
|
||||||
private static NodeTextComparer nodeTextComparer;
|
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();
|
internal static NodeTextComparer NodeText => nodeTextComparer ??= new NodeTextComparer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>True</UseWindowsForms>
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
<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>
|
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||||
<Company>CreamInstaller</Company>
|
<Company>CreamInstaller</Company>
|
||||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||||
|
|
|
@ -9,6 +9,8 @@ namespace CreamInstaller.Platforms.Epic.GraphQL;
|
||||||
|
|
||||||
internal class Request
|
internal class Request
|
||||||
{
|
{
|
||||||
|
internal Request(string @namespace) => Vars = new Variables(@namespace);
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "query")]
|
[JsonProperty(PropertyName = "query")]
|
||||||
private string Query => @"query searchOffers($namespace: String!) {
|
private string Query => @"query searchOffers($namespace: String!) {
|
||||||
Catalog {
|
Catalog {
|
||||||
|
@ -58,8 +60,6 @@ internal class Request
|
||||||
[JsonProperty(PropertyName = "variables")]
|
[JsonProperty(PropertyName = "variables")]
|
||||||
private Variables Vars { get; set; }
|
private Variables Vars { get; set; }
|
||||||
|
|
||||||
internal Request(string @namespace) => Vars = new Variables(@namespace);
|
|
||||||
|
|
||||||
private class Headers
|
private class Headers
|
||||||
{
|
{
|
||||||
[JsonProperty(PropertyName = "Content-Type")]
|
[JsonProperty(PropertyName = "Content-Type")]
|
||||||
|
@ -68,9 +68,9 @@ internal class Request
|
||||||
|
|
||||||
private class Variables
|
private class Variables
|
||||||
{
|
{
|
||||||
|
internal Variables(string @namespace) => Namespace = @namespace;
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "namespace")]
|
[JsonProperty(PropertyName = "namespace")]
|
||||||
private string Namespace { get; set; }
|
private string Namespace { get; set; }
|
||||||
|
|
||||||
internal Variables(string @namespace) => Namespace = @namespace;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -217,7 +217,7 @@ internal static class SteamCMD
|
||||||
goto restart;
|
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)
|
if (!ValveDataFile.TryDeserialize(output, out VProperty appInfo) || appInfo.Value is VValue)
|
||||||
{
|
{
|
||||||
File.Delete(appUpdateFile);
|
File.Delete(appUpdateFile);
|
||||||
|
@ -225,62 +225,61 @@ internal static class SteamCMD
|
||||||
}
|
}
|
||||||
if (appInfo is null || appInfo.Value?.Children()?.ToList()?.Count == 0) return appInfo;
|
if (appInfo is null || appInfo.Value?.Children()?.ToList()?.Count == 0) return appInfo;
|
||||||
VToken type = appInfo.Value?.GetChild("common")?.GetChild("type");
|
VToken type = appInfo.Value?.GetChild("common")?.GetChild("type");
|
||||||
if (type is null || type.ToString() == "Game")
|
if (type is not null && type.ToString() != "Game")
|
||||||
{
|
return appInfo;
|
||||||
string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch)
|
string buildid = appInfo.Value?.GetChild("depots")?.GetChild("branches")?.GetChild(branch)
|
||||||
?.GetChild("buildid")?.ToString();
|
?.GetChild("buildid")?.ToString();
|
||||||
if (buildid is null && type is not null) return appInfo;
|
if (buildid is null && type is not null) return appInfo;
|
||||||
if (type is null || (int.TryParse(buildid, out int gamebuildId) && gamebuildId < buildId))
|
if (type is not null && (!int.TryParse(buildid, out int gamebuildId) || gamebuildId >= buildId))
|
||||||
{
|
return appInfo;
|
||||||
List<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
List<string> dlcAppIds = await ParseDlcAppIds(appInfo);
|
||||||
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
foreach (string dlcAppUpdateFile in dlcAppIds.Select(id => $@"{AppInfoPath}\{id}.vdf"))
|
||||||
if (File.Exists(dlcAppUpdateFile))
|
if (File.Exists(dlcAppUpdateFile))
|
||||||
File.Delete(dlcAppUpdateFile);
|
File.Delete(dlcAppUpdateFile);
|
||||||
if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile);
|
if (File.Exists(appUpdateFile)) File.Delete(appUpdateFile);
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
|
||||||
}
|
|
||||||
return appInfo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
|
internal static async Task<List<string>> ParseDlcAppIds(VProperty appInfo) => await Task.Run(() =>
|
||||||
{
|
{
|
||||||
List<string> dlcIds = new();
|
List<string> dlcIds = new();
|
||||||
#pragma warning disable IDE0150 // Prefer 'null' check over type check
|
if (Program.Canceled || appInfo is null) return dlcIds;
|
||||||
if (Program.Canceled || appInfo is not VProperty) return dlcIds;
|
|
||||||
#pragma warning restore IDE0150 // Prefer 'null' check over type check
|
|
||||||
VToken extended = appInfo.Value.GetChild("extended");
|
VToken extended = appInfo.Value.GetChild("extended");
|
||||||
if (extended is not null)
|
if (extended is not null)
|
||||||
#pragma warning disable IDE0220 // Add explicit cast
|
foreach (VToken vToken in extended.Where(p => p is VProperty { Key: "listofdlc" }))
|
||||||
foreach (VProperty property in extended.Where(p => p is VProperty && (p as VProperty).Key == "listofdlc"))
|
{
|
||||||
|
VProperty property = (VProperty)vToken;
|
||||||
foreach (string id in property.Value.ToString().Split(","))
|
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);
|
dlcIds.Add("" + appId);
|
||||||
|
}
|
||||||
VToken depots = appInfo.Value.GetChild("depots");
|
VToken depots = appInfo.Value.GetChild("depots");
|
||||||
if (depots is not null)
|
if (depots is null)
|
||||||
foreach (VProperty property in depots.Where(
|
return dlcIds;
|
||||||
p => p is VProperty && int.TryParse((p as VProperty).Key, out int _)))
|
foreach (VToken vToken in depots.Where(p => p is VProperty property && int.TryParse(property.Key, out int _)))
|
||||||
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId)
|
{
|
||||||
&& !dlcIds.Contains("" + appId))
|
VProperty property = (VProperty)vToken;
|
||||||
dlcIds.Add("" + appId);
|
if (int.TryParse(property.Value.GetChild("dlcappid")?.ToString(), out int appId) && appId > 0
|
||||||
#pragma warning restore IDE0220 // Add explicit cast
|
&& !dlcIds.Contains("" + appId))
|
||||||
|
dlcIds.Add("" + appId);
|
||||||
|
}
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static async Task Kill()
|
private static async Task Kill()
|
||||||
{
|
{
|
||||||
List<Task> tasks = new();
|
List<Task> tasks = Process.GetProcessesByName("steamcmd")
|
||||||
foreach (Process process in Process.GetProcessesByName("steamcmd"))
|
.Select(process => Task.Run(() =>
|
||||||
tasks.Add(Task.Run(() =>
|
{
|
||||||
{
|
try
|
||||||
try
|
{
|
||||||
{
|
process.Kill(true);
|
||||||
process.Kill(true);
|
process.WaitForExit();
|
||||||
process.WaitForExit();
|
process.Close();
|
||||||
process.Close();
|
}
|
||||||
}
|
catch { }
|
||||||
catch { }
|
}))
|
||||||
}));
|
.ToList();
|
||||||
foreach (Task task in tasks) await task;
|
foreach (Task task in tasks) await task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CreamInstaller.Forms;
|
using CreamInstaller.Forms;
|
||||||
|
@ -21,8 +22,7 @@ internal static class SteamStore
|
||||||
{
|
{
|
||||||
List<string> dlcIds = new();
|
List<string> dlcIds = new();
|
||||||
if (appData.dlc is null) return dlcIds;
|
if (appData.dlc is null) return dlcIds;
|
||||||
foreach (int appId in appData.dlc)
|
dlcIds.AddRange(from appId in appData.dlc where appId > 0 select appId.ToString());
|
||||||
dlcIds.Add(appId.ToString());
|
|
||||||
return dlcIds;
|
return dlcIds;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,39 +21,44 @@ public enum DlcType
|
||||||
|
|
||||||
internal class ProgramSelection
|
internal class ProgramSelection
|
||||||
{
|
{
|
||||||
internal bool Enabled;
|
|
||||||
internal bool Koaloader;
|
|
||||||
internal const string DefaultKoaloaderProxy = "version";
|
internal const string DefaultKoaloaderProxy = "version";
|
||||||
internal string KoaloaderProxy;
|
|
||||||
|
|
||||||
internal Platform Platform;
|
internal static readonly List<ProgramSelection> All = new();
|
||||||
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 readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc
|
internal readonly SortedList<string, (DlcType type, string name, string icon)> AllDlc
|
||||||
= new(PlatformIdComparer.String);
|
= 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)>
|
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
||||||
ExtraDlc = new(); // for Paradox Launcher
|
ExtraDlc = new(); // for Paradox Launcher
|
||||||
|
|
||||||
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
internal readonly List<(string id, string name, SortedList<string, (DlcType type, string name, string icon)> dlc)>
|
||||||
ExtraSelectedDlc = new(); // for Paradox Launcher
|
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
|
internal bool AreDllsLocked
|
||||||
{
|
{
|
||||||
get
|
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)
|
private void Toggle(string dlcAppId, (DlcType type, string name, string icon) dlcApp, bool enabled)
|
||||||
{
|
{
|
||||||
if (enabled) SelectedDlc[dlcAppId] = dlcApp;
|
if (enabled) SelectedDlc[dlcAppId] = dlcApp;
|
||||||
|
@ -138,8 +147,6 @@ internal class ProgramSelection
|
||||||
Enabled = SelectedDlc.Any() || ExtraSelectedDlc.Any();
|
Enabled = SelectedDlc.Any() || ExtraSelectedDlc.Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ProgramSelection() => All.Add(this);
|
|
||||||
|
|
||||||
internal void Validate()
|
internal void Validate()
|
||||||
{
|
{
|
||||||
if (Program.IsGameBlocked(Name, RootDirectory))
|
if (Program.IsGameBlocked(Name, RootDirectory))
|
||||||
|
@ -171,12 +178,6 @@ internal class ProgramSelection
|
||||||
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
|
internal static void ValidateAll(List<(Platform platform, string id, string name)> programsToScan)
|
||||||
=> AllSafe.ForEach(selection => selection.Validate(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)
|
internal static ProgramSelection FromPlatformId(Platform platform, string gameId)
|
||||||
=> AllSafe.Find(s => s.Platform == platform && s.Id == 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;
|
||||||
|
|
||||||
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()
|
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)
|
internal static string ComputeMD5(this string filePath)
|
||||||
{
|
{
|
||||||
if (!File.Exists(filePath)) return null;
|
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
|
internal static bool IsResourceFile(this string filePath) => filePath.ComputeMD5() is string hash
|
||||||
&& ResourceMD5s.Values.Any(
|
&& ResourceMD5s.Values.Any(
|
||||||
hashes => hashes.Contains(hash));
|
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 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)
|
internal static Icon ToIcon(this Image image)
|
||||||
{
|
{
|
||||||
using Bitmap dialogIconBitmap = new(image, new Size(image.Width, image.Height));
|
using Bitmap dialogIconBitmap = new(image, new Size(image.Width, image.Height));
|
||||||
return Icon.FromHandle(dialogIconBitmap.GetHicon());
|
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)
|
internal static string GetDomainFaviconUrl(string domain, int size = 16)
|
||||||
=> GoogleFaviconsApiUrl + $"?domain={domain}&sz={size}";
|
=> GoogleFaviconsApiUrl + $"?domain={domain}&sz={size}";
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue