mirror of
https://github.com/terrymacdonald/DisplayMagician.git
synced 2024-08-30 18:32:20 +00:00
[WIP] Created SteamLibrary class to handle library
Pulled out the the library list mgmt from SteamGame and put it in a new SteamLibrary class. This means I can replicate the learnings from the ShortcutRepo amd Profile Repo, and can save separate JSON files in the future if I so desire. There is a little bit outstanding to make the SteamGame Properties to be writeable as well as readable, otherwise the SteamGame.CopyTo function won't work.
This commit is contained in:
parent
c1ce153c68
commit
71928a9b44
@ -30,27 +30,27 @@ namespace HeliosPlus.GameLibraries
|
||||
{
|
||||
public class SteamGame
|
||||
{
|
||||
private static string _steamExe;
|
||||
private static string _steamPath;
|
||||
/*private static string SteamLibrary.SteamExe;
|
||||
private static string SteamLibrary.SteamPath;
|
||||
private static string _steamConfigVdfFile;
|
||||
private static string _registrySteamKey = @"SOFTWARE\\Valve\\Steam";
|
||||
private static string _registryAppsKey = $@"{_registrySteamKey}\\Apps";
|
||||
private static string _registryAppsKey = $@"{_registrySteamKey}\\Apps";*/
|
||||
private string _gameRegistryKey;
|
||||
private uint _steamGameId;
|
||||
private string _steamGameName;
|
||||
private string _steamGamePath;
|
||||
private string _steamGameExe;
|
||||
private string _steamGameIconPath;
|
||||
private static List<SteamGame> _allSteamGames;
|
||||
private static List<SteamGame> _allInstalledSteamGames = null;
|
||||
|
||||
private struct SteamAppInfo
|
||||
/*private struct SteamAppInfo
|
||||
{
|
||||
public uint GameID;
|
||||
public string GameName;
|
||||
public List<string> GameExes;
|
||||
public string GameInstallDir;
|
||||
public string GameSteamIconPath;
|
||||
}
|
||||
}*/
|
||||
|
||||
static SteamGame()
|
||||
{
|
||||
@ -62,27 +62,18 @@ namespace HeliosPlus.GameLibraries
|
||||
public SteamGame(uint steamGameId, string steamGameName, string steamGamePath, string steamGameExe, string steamGameIconPath)
|
||||
{
|
||||
|
||||
_gameRegistryKey = $@"{_registryAppsKey}\\{steamGameId}";
|
||||
_gameRegistryKey = $@"{SteamLibrary.SteamAppsRegistryKey}\\{steamGameId}";
|
||||
_steamGameId = steamGameId;
|
||||
_steamGameName = steamGameName;
|
||||
_steamGamePath = steamGamePath;
|
||||
_steamGameExe = steamGameExe;
|
||||
_steamGameIconPath = steamGameIconPath;
|
||||
|
||||
// Find the SteamExe location, and the SteamPath for later
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(_registrySteamKey, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
_steamExe = (string)key?.GetValue(@"SteamExe", string.Empty) ?? string.Empty;
|
||||
_steamExe = _steamExe.Replace('/', '\\');
|
||||
_steamPath = (string)key?.GetValue(@"SteamPath", string.Empty) ?? string.Empty;
|
||||
_steamPath = _steamPath.Replace('/', '\\');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public uint GameId { get => _steamGameId; }
|
||||
|
||||
public static SupportedGameLibrary GameLibrary { get => SupportedGameLibrary.Steam; }
|
||||
public SupportedGameLibrary GameLibrary { get => SupportedGameLibrary.Steam; }
|
||||
|
||||
public string GameIconPath { get => _steamGameIconPath; }
|
||||
|
||||
@ -158,324 +149,22 @@ namespace HeliosPlus.GameLibraries
|
||||
|
||||
public string GameName { get => _steamGameName; }
|
||||
|
||||
public static string SteamExe { get => _steamExe; }
|
||||
|
||||
public string GamePath { get => _steamGamePath; }
|
||||
|
||||
public static List<SteamGame> AllGames { get => _allSteamGames; }
|
||||
|
||||
public static bool SteamInstalled
|
||||
public bool CopyTo(SteamGame steamGame)
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(SteamGame._steamExe) && File.Exists(SteamGame._steamExe))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!(steamGame is SteamGame))
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
// Copy all the shortcut data over to the other Shortcut
|
||||
steamGame.GameIconPath = GameIconPath;
|
||||
steamGame.GameId = GameId;
|
||||
steamGame.GameName = GameName;
|
||||
steamGame.GamePath = GamePath;
|
||||
steamGame.IsRunning = IsRunning;
|
||||
steamGame.IsUpdating = IsUpdating;
|
||||
|
||||
public static List<SteamGame> GetAllInstalledGames()
|
||||
{
|
||||
List<SteamGame> steamGameList = new List<SteamGame>();
|
||||
_allSteamGames = steamGameList;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Find the SteamExe location, and the SteamPath for later
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(_registrySteamKey, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
_steamExe = (string)key?.GetValue(@"SteamExe", string.Empty) ?? string.Empty;
|
||||
_steamExe = _steamExe.Replace('/','\\');
|
||||
_steamPath = (string)key?.GetValue(@"SteamPath", string.Empty) ?? string.Empty;
|
||||
_steamPath = _steamPath.Replace('/', '\\');
|
||||
}
|
||||
|
||||
if (_steamExe == string.Empty || !File.Exists(_steamExe))
|
||||
{
|
||||
// Steam isn't installed, so we return an empty list.
|
||||
return steamGameList;
|
||||
}
|
||||
|
||||
//Icon _steamIcon = Icon.ExtractAssociatedIcon(_steamExe);
|
||||
//IconExtractor steamIconExtractor = new IconExtractor(_steamExe);
|
||||
//Icon _steamIcon = steamIconExtractor.GetIcon(0);
|
||||
MultiIcon _steamIcon = new MultiIcon();
|
||||
_steamIcon.Load(_steamExe);
|
||||
|
||||
List<uint> steamAppIdsInstalled = new List<uint>();
|
||||
// Now look for what games app id's are actually installed on this computer
|
||||
using (RegistryKey steamAppsKey = Registry.CurrentUser.OpenSubKey(_registryAppsKey, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
if (steamAppsKey != null)
|
||||
{
|
||||
// Loop through the subKeys as they are the Steam Game IDs
|
||||
foreach (string steamGameKeyName in steamAppsKey.GetSubKeyNames())
|
||||
{
|
||||
uint steamAppId = 0;
|
||||
if (uint.TryParse(steamGameKeyName, out steamAppId))
|
||||
{
|
||||
string steamGameKeyFullName = $"{_registryAppsKey}\\{steamGameKeyName}";
|
||||
using (RegistryKey steamGameKey = Registry.CurrentUser.OpenSubKey(steamGameKeyFullName, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
// If the Installed Value is set to 1, then the game is installed
|
||||
// We want to keep track of that for later
|
||||
if ((int)steamGameKey.GetValue(@"Installed", 0) == 1)
|
||||
{
|
||||
// Add this Steam App ID to the list we're keeping for later
|
||||
steamAppIdsInstalled.Add(steamAppId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we parse the steam appinfo.vdf to get access to things like:
|
||||
// - The game name
|
||||
// - THe game installation dir
|
||||
// - Sometimes the game icon
|
||||
// - Sometimes the game executable name (from which we can get the icon)
|
||||
Dictionary<uint, SteamAppInfo> steamAppInfo = new Dictionary<uint, SteamAppInfo>();
|
||||
|
||||
string appInfoVdfFile = Path.Combine(_steamPath, "appcache", "appinfo.vdf");
|
||||
var newAppInfo = new AppInfo();
|
||||
newAppInfo.Read(appInfoVdfFile);
|
||||
|
||||
Console.WriteLine($"{newAppInfo.Apps.Count} apps");
|
||||
|
||||
// Chec through all the apps we've extracted
|
||||
foreach (var app in newAppInfo.Apps)
|
||||
{
|
||||
// We only care about the appIDs we have listed as actual games
|
||||
// (The AppIds include all other DLC and Steam specific stuff too)
|
||||
if ( steamAppIdsInstalled.Contains(app.AppID))
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
SteamAppInfo steamGameAppInfo = new SteamAppInfo();
|
||||
steamGameAppInfo.GameID = app.AppID;
|
||||
steamGameAppInfo.GameExes = new List<string>();
|
||||
|
||||
foreach (KVObject data in app.Data)
|
||||
{
|
||||
//Console.WriteLine($"App: {app.AppID} - Data.Name: {data.Name}");
|
||||
|
||||
if (data.Name == "common")
|
||||
{
|
||||
foreach (KVObject common in data.Children) {
|
||||
|
||||
//Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
|
||||
if (common.Name == "name")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
steamGameAppInfo.GameName = common.Value.ToString();
|
||||
}
|
||||
else if (common.Name == "clienticon")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
steamGameAppInfo.GameSteamIconPath = Path.Combine(_steamPath, @"steam", @"games", String.Concat(common.Value, @".ico"));
|
||||
}
|
||||
else if (common.Name == "type")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.Name == "config")
|
||||
{
|
||||
foreach (KVObject config in data.Children)
|
||||
{
|
||||
//Console.WriteLine($"App: {app.AppID} - Config {config.Name}: {config.Value}");
|
||||
|
||||
if (config.Name == "installdir")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Config {config.Name}: {config.Value}");
|
||||
steamGameAppInfo.GameInstallDir = config.Value.ToString();
|
||||
}
|
||||
else if (config.Name == "launch")
|
||||
{
|
||||
foreach (KVObject launch in config.Children)
|
||||
{
|
||||
foreach (KVObject launch_num in launch.Children)
|
||||
{
|
||||
if (launch_num.Name == "executable")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Config - Launch {launch.Name} - {launch_num.Name}: {launch_num.Value}");
|
||||
steamGameAppInfo.GameExes.Add(launch_num.Value.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
steamAppInfo.Add(app.AppID, steamGameAppInfo);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames exception: {ex.Message}: {ex.InnerException}");
|
||||
//we just want to ignore it if we try to add it twice....
|
||||
}
|
||||
|
||||
Console.WriteLine($"App: {app.AppID} - Token: {app.Token}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Now we access the config.vdf that lives in the Steam Config file, as that lists all
|
||||
// the SteamLibraries. We need to find out where they areso we can interrogate them
|
||||
_steamConfigVdfFile = Path.Combine(_steamPath, "config", "config.vdf");
|
||||
string steamConfigVdfText = File.ReadAllText(_steamConfigVdfFile, Encoding.UTF8);
|
||||
|
||||
List<string> steamLibrariesPaths = new List<string>();
|
||||
// Now we have to parse the config.vdf looking for the location of the SteamLibraries
|
||||
// We look for lines similar to this: "BaseInstallFolder_1" "E:\\SteamLibrary"
|
||||
// There may be multiple so we need to check the whole file
|
||||
Regex steamLibrariesRegex = new Regex(@"""BaseInstallFolder_\d+""\s+""(.*)""", RegexOptions.IgnoreCase);
|
||||
// Try to match all lines against the Regex.
|
||||
Match steamLibrariesMatches = steamLibrariesRegex.Match(steamConfigVdfText);
|
||||
// If at least one of them matched!
|
||||
if (steamLibrariesMatches.Success)
|
||||
{
|
||||
// Loop throug the results and add to an array
|
||||
for (int i = 1; i < steamLibrariesMatches.Groups.Count; i++)
|
||||
{
|
||||
string steamLibraryPath = Regex.Unescape(steamLibrariesMatches.Groups[i].Value);
|
||||
Console.WriteLine($"Found steam library: {steamLibraryPath}");
|
||||
steamLibrariesPaths.Add(steamLibraryPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we go off and find the details for the games in each Steam Library
|
||||
foreach (string steamLibraryPath in steamLibrariesPaths)
|
||||
{
|
||||
// Work out the path to the appmanifests for this steamLibrary
|
||||
string steamLibraryAppManifestPath = Path.Combine(steamLibraryPath, @"steamapps");
|
||||
// Get the names of the App Manifests for the games installed in this SteamLibrary
|
||||
string[] steamLibraryAppManifestFilenames = Directory.GetFiles(steamLibraryAppManifestPath, "appmanifest_*.acf");
|
||||
// Go through each app and extract it's details
|
||||
foreach (string steamLibraryAppManifestFilename in steamLibraryAppManifestFilenames)
|
||||
{
|
||||
// Read in the contents of the file
|
||||
string steamLibraryAppManifestText = File.ReadAllText(steamLibraryAppManifestFilename);
|
||||
// Grab the appid from the file
|
||||
Regex appidRegex = new Regex(@"""appid""\s+""(\d+)""", RegexOptions.IgnoreCase);
|
||||
Match appidMatches = appidRegex.Match(steamLibraryAppManifestText);
|
||||
if (appidMatches.Success)
|
||||
{
|
||||
|
||||
uint steamGameId = 0;
|
||||
if (uint.TryParse(appidMatches.Groups[1].Value, out steamGameId))
|
||||
{
|
||||
// Check if this game is one that was installed
|
||||
if (steamAppInfo.ContainsKey(steamGameId)) {
|
||||
// This game is an installed game! so we start to populate it with data!
|
||||
string steamGameExe = "";
|
||||
|
||||
string steamGameName = steamAppInfo[steamGameId].GameName;
|
||||
|
||||
// Construct the full path to the game dir from the appInfo and libraryAppManifest data
|
||||
string steamGameInstallDir = Path.Combine(steamLibraryPath, @"steamapps", @"common", steamAppInfo[steamGameId].GameInstallDir);
|
||||
|
||||
// Next, we need to get the Icons we want to use, and make sure it's the latest one.
|
||||
string steamGameIconPath = "";
|
||||
// First of all, we attempt to use the Icon that Steam has cached, if it's available, as that will be updated to the latest
|
||||
if (File.Exists(steamAppInfo[steamGameId].GameSteamIconPath))
|
||||
{
|
||||
steamGameIconPath = steamAppInfo[steamGameId].GameSteamIconPath;
|
||||
}
|
||||
// If there isn't an icon for us to use, then we need to extract one from the Game Executables
|
||||
else if (steamAppInfo[steamGameId].GameExes.Count > 0)
|
||||
{
|
||||
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
|
||||
{
|
||||
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
|
||||
// If the game executable exists, then we can proceed
|
||||
if (File.Exists(steamGameExe))
|
||||
{
|
||||
// Now we need to get the Icon from the app if possible if it's not in the games folder
|
||||
steamGameIconPath = steamGameExe;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// The absolute worst case means we don't have an icon to use. SO we use the Steam one.
|
||||
else
|
||||
{
|
||||
// And we have to make do with a Steam Icon
|
||||
steamGameIconPath = _steamPath;
|
||||
|
||||
}
|
||||
|
||||
// And finally we try to populate the 'where', to see what gets run
|
||||
// And so we can extract the process name
|
||||
if (steamAppInfo[steamGameId].GameExes.Count > 0)
|
||||
{
|
||||
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
|
||||
{
|
||||
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
|
||||
// If the game executable exists, then we can proceed
|
||||
if (File.Exists(steamGameExe))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// And we add the Game to the list of games we have!
|
||||
steamGameList.Add(new SteamGame(steamGameId, steamGameName, steamGameInstallDir, steamGameExe, steamGameIconPath));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SecurityException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames securityexception: {ex.Message}: {ex.InnerException}");
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames unauthorizedaccessexception: {ex.Message}: {ex.InnerException}");
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("UnauthorizedAccessException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames objectdisposedexceptions: {ex.Message}: {ex.InnerException}");
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("ObjectDisposedException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames ioexception: {ex.Message}: {ex.InnerException}");
|
||||
// Extract some information from this exception, and then
|
||||
// throw it to the parent method.
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
return steamGameList;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
|
608
HeliosPlus/GameLibraries/SteamLibrary.cs
Normal file
608
HeliosPlus/GameLibraries/SteamLibrary.cs
Normal file
@ -0,0 +1,608 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using ValveKeyValue;
|
||||
using HeliosPlus.GameLibraries.SteamAppInfoParser;
|
||||
using Microsoft.Win32;
|
||||
using System.IO;
|
||||
using System.Drawing.IconLib;
|
||||
using System.Security;
|
||||
|
||||
namespace HeliosPlus.GameLibraries
|
||||
{
|
||||
public static class SteamLibrary
|
||||
{
|
||||
#region Class Variables
|
||||
// Common items to the class
|
||||
private static List<SteamGame> _allSteamGames = null;
|
||||
private static string steamAppIdRegex = @"/^[0-9A-F]{1,10}$";
|
||||
private static string _steamExe;
|
||||
private static string _steamPath;
|
||||
private static string _steamConfigVdfFile;
|
||||
private static string _registrySteamKey = @"SOFTWARE\\Valve\\Steam";
|
||||
private static string _registryAppsKey = $@"{_registrySteamKey}\\Apps";
|
||||
// Other constants that are useful
|
||||
#endregion
|
||||
|
||||
private struct SteamAppInfo
|
||||
{
|
||||
public uint GameID;
|
||||
public string GameName;
|
||||
public List<string> GameExes;
|
||||
public string GameInstallDir;
|
||||
public string GameSteamIconPath;
|
||||
}
|
||||
|
||||
#region Class Constructors
|
||||
static SteamLibrary()
|
||||
{
|
||||
// Find the SteamExe location, and the SteamPath for later
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(SteamLibrary.SteamRegistryKey, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
_steamExe = (string)key?.GetValue(@"SteamExe", string.Empty) ?? string.Empty;
|
||||
_steamExe = _steamExe.Replace('/', '\\');
|
||||
_steamPath = (string)key?.GetValue(@"SteamPath", string.Empty) ?? string.Empty;
|
||||
_steamPath = _steamPath.Replace('/', '\\');
|
||||
}
|
||||
|
||||
// Load the Shortcuts from storage
|
||||
LoadInstalledSteamGames();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Class Properties
|
||||
public static List<SteamGame> AllInstalledGames
|
||||
{
|
||||
get
|
||||
{
|
||||
// Load the Steam Games from Steam Client if needed
|
||||
if (_allSteamGames == null)
|
||||
LoadInstalledSteamGames();
|
||||
return _allSteamGames;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static int InstalledSteamGameCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _allSteamGames.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SteamRegistryKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _registrySteamKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SteamAppsRegistryKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return _registryAppsKey;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SteamExe
|
||||
{
|
||||
get
|
||||
{
|
||||
return _steamExe;
|
||||
}
|
||||
}
|
||||
|
||||
public static string SteamPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _steamPath;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsSteamInstalled
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(SteamExe) && File.Exists(SteamExe))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Class Methods
|
||||
public static bool AddSteamGame(SteamGame steamGame)
|
||||
{
|
||||
if (!(steamGame is SteamGame))
|
||||
return false;
|
||||
|
||||
// Doublecheck if it already exists
|
||||
// Because then we just update the one that already exists
|
||||
if (ContainsSteamGame(steamGame))
|
||||
{
|
||||
// We update the existing Shortcut with the data over
|
||||
SteamGame steamGameToUpdate = GetSteamGame(steamGame.GameId.ToString());
|
||||
steamGame.CopyTo(steamGameToUpdate);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the steamGame to the list of steamGames
|
||||
_allSteamGames.Add(steamGame);
|
||||
}
|
||||
|
||||
//Doublecheck it's been added
|
||||
if (ContainsSteamGame(steamGame))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public static bool RemoveSteamGame(SteamGame steamGame)
|
||||
{
|
||||
if (!(steamGame is SteamGame))
|
||||
return false;
|
||||
|
||||
// Remove the steamGame from the list.
|
||||
int numRemoved = _allSteamGames.RemoveAll(item => item.GameId.Equals(steamGame.GameId));
|
||||
|
||||
if (numRemoved == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (numRemoved == 0)
|
||||
return false;
|
||||
else
|
||||
throw new SteamLibraryException();
|
||||
}
|
||||
|
||||
|
||||
public static bool RemoveSteamGame(string steamGameNameOrUuid)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
|
||||
return false;
|
||||
|
||||
int numRemoved;
|
||||
Match match = Regex.Match(steamGameNameOrUuid, steamAppIdRegex, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrUuid.Equals(Convert.ToUInt32(item.GameId)));
|
||||
else
|
||||
numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrUuid.Equals(item.GameName));
|
||||
|
||||
if (numRemoved == 1)
|
||||
return true;
|
||||
else if (numRemoved == 0)
|
||||
return false;
|
||||
else
|
||||
throw new SteamLibraryException();
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static bool ContainsSteamGame(SteamGame steamGame)
|
||||
{
|
||||
if (!(steamGame is SteamGame))
|
||||
return false;
|
||||
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (testSteamGame.GameId.Equals(steamGame.GameId))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ContainsSteamGame(string steamGameNameOrUuid)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
|
||||
return false;
|
||||
|
||||
|
||||
Match match = Regex.Match(steamGameNameOrUuid, steamAppIdRegex, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (steamGameNameOrUuid.Equals(Convert.ToUInt32(testSteamGame.GameId)))
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (steamGameNameOrUuid.Equals(testSteamGame.GameName))
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
public static bool ContainsSteamGame(uint steamGameId)
|
||||
{
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (steamGameId == testSteamGame.GameId)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static SteamGame GetSteamGame(string steamGameNameOrUuid)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
|
||||
return null;
|
||||
|
||||
Match match = Regex.Match(steamGameNameOrUuid, steamAppIdRegex, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (steamGameNameOrUuid.Equals(Convert.ToUInt32(testSteamGame.GameId)))
|
||||
return testSteamGame;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (steamGameNameOrUuid.Equals(testSteamGame.GameName))
|
||||
return testSteamGame;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
public static SteamGame GetSteamGame(uint steamGameId)
|
||||
{
|
||||
foreach (SteamGame testSteamGame in _allSteamGames)
|
||||
{
|
||||
if (steamGameId == testSteamGame.GameId)
|
||||
return testSteamGame;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
private static bool LoadInstalledSteamGames()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
// Find the SteamExe location, and the SteamPath for later
|
||||
using (var key = Registry.CurrentUser.OpenSubKey(_registrySteamKey, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
_steamExe = (string)key?.GetValue(@"SteamExe", string.Empty) ?? string.Empty;
|
||||
_steamExe = _steamExe.Replace('/', '\\');
|
||||
_steamPath = (string)key?.GetValue(@"SteamPath", string.Empty) ?? string.Empty;
|
||||
_steamPath = _steamPath.Replace('/', '\\');
|
||||
}
|
||||
|
||||
if (_steamExe == string.Empty || !File.Exists(_steamExe))
|
||||
{
|
||||
// Steam isn't installed, so we return an empty list.
|
||||
return false;
|
||||
}
|
||||
|
||||
//Icon _steamIcon = Icon.ExtractAssociatedIcon(_steamExe);
|
||||
//IconExtractor steamIconExtractor = new IconExtractor(_steamExe);
|
||||
//Icon _steamIcon = steamIconExtractor.GetIcon(0);
|
||||
MultiIcon _steamIcon = new MultiIcon();
|
||||
_steamIcon.Load(_steamExe);
|
||||
|
||||
List<uint> steamAppIdsInstalled = new List<uint>();
|
||||
// Now look for what games app id's are actually installed on this computer
|
||||
using (RegistryKey steamAppsKey = Registry.CurrentUser.OpenSubKey(_registryAppsKey, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
if (steamAppsKey != null)
|
||||
{
|
||||
// Loop through the subKeys as they are the Steam Game IDs
|
||||
foreach (string steamGameKeyName in steamAppsKey.GetSubKeyNames())
|
||||
{
|
||||
uint steamAppId = 0;
|
||||
if (uint.TryParse(steamGameKeyName, out steamAppId))
|
||||
{
|
||||
string steamGameKeyFullName = $"{_registryAppsKey}\\{steamGameKeyName}";
|
||||
using (RegistryKey steamGameKey = Registry.CurrentUser.OpenSubKey(steamGameKeyFullName, RegistryKeyPermissionCheck.ReadSubTree))
|
||||
{
|
||||
// If the Installed Value is set to 1, then the game is installed
|
||||
// We want to keep track of that for later
|
||||
if ((int)steamGameKey.GetValue(@"Installed", 0) == 1)
|
||||
{
|
||||
// Add this Steam App ID to the list we're keeping for later
|
||||
steamAppIdsInstalled.Add(steamAppId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we parse the steam appinfo.vdf to get access to things like:
|
||||
// - The game name
|
||||
// - THe game installation dir
|
||||
// - Sometimes the game icon
|
||||
// - Sometimes the game executable name (from which we can get the icon)
|
||||
Dictionary<uint, SteamAppInfo> steamAppInfo = new Dictionary<uint, SteamAppInfo>();
|
||||
|
||||
string appInfoVdfFile = Path.Combine(_steamPath, "appcache", "appinfo.vdf");
|
||||
var newAppInfo = new AppInfo();
|
||||
newAppInfo.Read(appInfoVdfFile);
|
||||
|
||||
Console.WriteLine($"{newAppInfo.Apps.Count} apps");
|
||||
|
||||
// Chec through all the apps we've extracted
|
||||
foreach (var app in newAppInfo.Apps)
|
||||
{
|
||||
// We only care about the appIDs we have listed as actual games
|
||||
// (The AppIds include all other DLC and Steam specific stuff too)
|
||||
if (steamAppIdsInstalled.Contains(app.AppID))
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
SteamAppInfo steamGameAppInfo = new SteamAppInfo();
|
||||
steamGameAppInfo.GameID = app.AppID;
|
||||
steamGameAppInfo.GameExes = new List<string>();
|
||||
|
||||
foreach (KVObject data in app.Data)
|
||||
{
|
||||
//Console.WriteLine($"App: {app.AppID} - Data.Name: {data.Name}");
|
||||
|
||||
if (data.Name == "common")
|
||||
{
|
||||
foreach (KVObject common in data.Children)
|
||||
{
|
||||
|
||||
//Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
|
||||
if (common.Name == "name")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
steamGameAppInfo.GameName = common.Value.ToString();
|
||||
}
|
||||
else if (common.Name == "clienticon")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
steamGameAppInfo.GameSteamIconPath = Path.Combine(_steamPath, @"steam", @"games", String.Concat(common.Value, @".ico"));
|
||||
}
|
||||
else if (common.Name == "type")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (data.Name == "config")
|
||||
{
|
||||
foreach (KVObject config in data.Children)
|
||||
{
|
||||
//Console.WriteLine($"App: {app.AppID} - Config {config.Name}: {config.Value}");
|
||||
|
||||
if (config.Name == "installdir")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Config {config.Name}: {config.Value}");
|
||||
steamGameAppInfo.GameInstallDir = config.Value.ToString();
|
||||
}
|
||||
else if (config.Name == "launch")
|
||||
{
|
||||
foreach (KVObject launch in config.Children)
|
||||
{
|
||||
foreach (KVObject launch_num in launch.Children)
|
||||
{
|
||||
if (launch_num.Name == "executable")
|
||||
{
|
||||
Console.WriteLine($"App: {app.AppID} - Config - Launch {launch.Name} - {launch_num.Name}: {launch_num.Value}");
|
||||
steamGameAppInfo.GameExes.Add(launch_num.Value.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
steamAppInfo.Add(app.AppID, steamGameAppInfo);
|
||||
}
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames exception: {ex.Message}: {ex.InnerException}");
|
||||
//we just want to ignore it if we try to add it twice....
|
||||
}
|
||||
|
||||
Console.WriteLine($"App: {app.AppID} - Token: {app.Token}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Now we access the config.vdf that lives in the Steam Config file, as that lists all
|
||||
// the SteamLibraries. We need to find out where they areso we can interrogate them
|
||||
_steamConfigVdfFile = Path.Combine(_steamPath, "config", "config.vdf");
|
||||
string steamConfigVdfText = File.ReadAllText(_steamConfigVdfFile, Encoding.UTF8);
|
||||
|
||||
List<string> steamLibrariesPaths = new List<string>();
|
||||
// Now we have to parse the config.vdf looking for the location of the SteamLibraries
|
||||
// We look for lines similar to this: "BaseInstallFolder_1" "E:\\SteamLibrary"
|
||||
// There may be multiple so we need to check the whole file
|
||||
Regex steamLibrariesRegex = new Regex(@"""BaseInstallFolder_\d+""\s+""(.*)""", RegexOptions.IgnoreCase);
|
||||
// Try to match all lines against the Regex.
|
||||
Match steamLibrariesMatches = steamLibrariesRegex.Match(steamConfigVdfText);
|
||||
// If at least one of them matched!
|
||||
if (steamLibrariesMatches.Success)
|
||||
{
|
||||
// Loop throug the results and add to an array
|
||||
for (int i = 1; i < steamLibrariesMatches.Groups.Count; i++)
|
||||
{
|
||||
string steamLibraryPath = Regex.Unescape(steamLibrariesMatches.Groups[i].Value);
|
||||
Console.WriteLine($"Found steam library: {steamLibraryPath}");
|
||||
steamLibrariesPaths.Add(steamLibraryPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we go off and find the details for the games in each Steam Library
|
||||
foreach (string steamLibraryPath in steamLibrariesPaths)
|
||||
{
|
||||
// Work out the path to the appmanifests for this steamLibrary
|
||||
string steamLibraryAppManifestPath = Path.Combine(steamLibraryPath, @"steamapps");
|
||||
// Get the names of the App Manifests for the games installed in this SteamLibrary
|
||||
string[] steamLibraryAppManifestFilenames = Directory.GetFiles(steamLibraryAppManifestPath, "appmanifest_*.acf");
|
||||
// Go through each app and extract it's details
|
||||
foreach (string steamLibraryAppManifestFilename in steamLibraryAppManifestFilenames)
|
||||
{
|
||||
// Read in the contents of the file
|
||||
string steamLibraryAppManifestText = File.ReadAllText(steamLibraryAppManifestFilename);
|
||||
// Grab the appid from the file
|
||||
Regex appidRegex = new Regex(@"""appid""\s+""(\d+)""", RegexOptions.IgnoreCase);
|
||||
Match appidMatches = appidRegex.Match(steamLibraryAppManifestText);
|
||||
if (appidMatches.Success)
|
||||
{
|
||||
|
||||
uint steamGameId = 0;
|
||||
if (uint.TryParse(appidMatches.Groups[1].Value, out steamGameId))
|
||||
{
|
||||
// Check if this game is one that was installed
|
||||
if (steamAppInfo.ContainsKey(steamGameId))
|
||||
{
|
||||
// This game is an installed game! so we start to populate it with data!
|
||||
string steamGameExe = "";
|
||||
|
||||
string steamGameName = steamAppInfo[steamGameId].GameName;
|
||||
|
||||
// Construct the full path to the game dir from the appInfo and libraryAppManifest data
|
||||
string steamGameInstallDir = Path.Combine(steamLibraryPath, @"steamapps", @"common", steamAppInfo[steamGameId].GameInstallDir);
|
||||
|
||||
// Next, we need to get the Icons we want to use, and make sure it's the latest one.
|
||||
string steamGameIconPath = "";
|
||||
// First of all, we attempt to use the Icon that Steam has cached, if it's available, as that will be updated to the latest
|
||||
if (File.Exists(steamAppInfo[steamGameId].GameSteamIconPath))
|
||||
{
|
||||
steamGameIconPath = steamAppInfo[steamGameId].GameSteamIconPath;
|
||||
}
|
||||
// If there isn't an icon for us to use, then we need to extract one from the Game Executables
|
||||
else if (steamAppInfo[steamGameId].GameExes.Count > 0)
|
||||
{
|
||||
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
|
||||
{
|
||||
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
|
||||
// If the game executable exists, then we can proceed
|
||||
if (File.Exists(steamGameExe))
|
||||
{
|
||||
// Now we need to get the Icon from the app if possible if it's not in the games folder
|
||||
steamGameIconPath = steamGameExe;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// The absolute worst case means we don't have an icon to use. SO we use the Steam one.
|
||||
else
|
||||
{
|
||||
// And we have to make do with a Steam Icon
|
||||
steamGameIconPath = _steamPath;
|
||||
|
||||
}
|
||||
|
||||
// And finally we try to populate the 'where', to see what gets run
|
||||
// And so we can extract the process name
|
||||
if (steamAppInfo[steamGameId].GameExes.Count > 0)
|
||||
{
|
||||
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
|
||||
{
|
||||
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
|
||||
// If the game executable exists, then we can proceed
|
||||
if (File.Exists(steamGameExe))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// And we add the Game to the list of games we have!
|
||||
_allSteamGames.Add(new SteamGame(steamGameId, steamGameName, steamGameInstallDir, steamGameExe, steamGameIconPath));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SecurityException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames securityexception: {ex.Message}: {ex.InnerException}");
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames unauthorizedaccessexception: {ex.Message}: {ex.InnerException}");
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("UnauthorizedAccessException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
catch (ObjectDisposedException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames objectdisposedexceptions: {ex.Message}: {ex.InnerException}");
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("ObjectDisposedException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
Console.WriteLine($"SteamGame/GetAllInstalledGames ioexception: {ex.Message}: {ex.InnerException}");
|
||||
// Extract some information from this exception, and then
|
||||
// throw it to the parent method.
|
||||
if (ex.Source != null)
|
||||
Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
[global::System.Serializable]
|
||||
public class SteamLibraryException : Exception
|
||||
{
|
||||
public SteamLibraryException() { }
|
||||
public SteamLibraryException(string message) : base(message) { }
|
||||
public SteamLibraryException(string message, Exception inner) : base(message, inner) { }
|
||||
protected SteamLibraryException(
|
||||
System.Runtime.Serialization.SerializationInfo info,
|
||||
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
|
||||
}
|
@ -77,6 +77,7 @@
|
||||
<Compile Include="GameLibraries\SteamAppInfoParser\Package.cs" />
|
||||
<Compile Include="GameLibraries\SteamAppInfoParser\PackageInfo.cs" />
|
||||
<Compile Include="GameLibraries\SteamAppInfoParser\App.cs" />
|
||||
<Compile Include="GameLibraries\SteamLibrary.cs" />
|
||||
<Compile Include="IconUtils.cs" />
|
||||
<Compile Include="ShortcutItem.cs" />
|
||||
<Compile Include="ShortcutRepository.cs" />
|
||||
|
@ -21,6 +21,13 @@ using System.Text.RegularExpressions;
|
||||
using System.Drawing;
|
||||
|
||||
namespace HeliosPlus {
|
||||
public enum SupportedProgramMode
|
||||
{
|
||||
RunShortcut,
|
||||
EditProfile,
|
||||
StartUpNormally
|
||||
}
|
||||
|
||||
public enum SupportedGameLibrary
|
||||
{
|
||||
Unknown,
|
||||
@ -41,75 +48,6 @@ namespace HeliosPlus {
|
||||
//internal static string ShortcutIconCachePath;
|
||||
|
||||
|
||||
internal static ProfileItem GetProfile(string profileName)
|
||||
{
|
||||
// Create an array of display profiles we have
|
||||
var profiles = ProfileRepository.AllProfiles.ToArray();
|
||||
// Check if the user supplied a --profile option using the profiles' ID
|
||||
var profileIndex = profiles.Length > 0 ? Array.FindIndex(profiles, p => p.UUID.Equals(profileName, StringComparison.InvariantCultureIgnoreCase)) : -1;
|
||||
// If the profileID wasn't there, maybe they used the profile name?
|
||||
if (profileIndex == -1)
|
||||
{
|
||||
// Try and lookup the profile in the profiles' Name fields
|
||||
profileIndex = profiles.Length > 0 ? Array.FindIndex(profiles, p => p.Name.StartsWith(profileName, StringComparison.InvariantCultureIgnoreCase)) : -1;
|
||||
}
|
||||
|
||||
return profiles[profileIndex];
|
||||
}
|
||||
|
||||
internal static bool GoProfile(ProfileItem profile)
|
||||
{
|
||||
// If we're already on the wanted profile then no need to change!
|
||||
if (ProfileRepository.IsActiveProfile(profile))
|
||||
return true;
|
||||
|
||||
var instanceStatus = IPCService.GetInstance().Status;
|
||||
|
||||
try
|
||||
{
|
||||
IPCService.GetInstance().Status = InstanceStatus.Busy;
|
||||
var failed = false;
|
||||
|
||||
if (new ApplyingChangesForm(() =>
|
||||
{
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
if (!(ProfileRepository.ApplyProfile(profile)))
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}, 3, 30).ShowDialog() !=
|
||||
DialogResult.Cancel)
|
||||
{
|
||||
if (failed)
|
||||
{
|
||||
throw new Exception(Language.Profile_is_invalid_or_not_possible_to_apply);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IPCService.GetInstance().Status = instanceStatus;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditProfile(ProfileItem profile)
|
||||
{
|
||||
// Get the status of the thing
|
||||
IPCService.GetInstance().Status = InstanceStatus.User;
|
||||
// Load all the profiles from JSON
|
||||
//ProfileRepository.AllProfiles
|
||||
// Start up the DisplayProfileForm directly
|
||||
new DisplayProfileForm(profile).ShowDialog();
|
||||
// Then we close down as we're only here to edit one profile
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point for the application.
|
||||
@ -125,7 +63,7 @@ namespace HeliosPlus {
|
||||
Console.Write("=");
|
||||
}
|
||||
Console.WriteLine("=");
|
||||
Console.WriteLine(@"Copyright © Terry MacDonald 2020-{DateTime.Today.Year}");
|
||||
Console.WriteLine($"Copyright © Terry MacDonald 2020-{DateTime.Today.Year}");
|
||||
Console.WriteLine(@"Based on Helios Display Management - Copyright © Soroush Falahati 2017-2020");
|
||||
|
||||
var app = new CommandLineApplication();
|
||||
@ -144,28 +82,26 @@ namespace HeliosPlus {
|
||||
return string.Format("Version {0}", Assembly.GetExecutingAssembly().GetName().Version);
|
||||
});
|
||||
|
||||
// This is the SwitchProfile command
|
||||
app.Command("RunShortcut", (switchProfileCmd) =>
|
||||
// This is the RunShortcut command
|
||||
app.Command(SupportedProgramMode.RunShortcut.ToString(), (switchProfileCmd) =>
|
||||
{
|
||||
var argumentShortcut = switchProfileCmd.Argument("\"SHORTCUT_NAME\"", "(required) The name of the shortcut to run from those stored in the shortcut library.").IsRequired();
|
||||
var argumentShortcut = switchProfileCmd.Argument("\"SHORTCUT_UUID\"", "(required) The UUID of the shortcut to run from those stored in the shortcut library.").IsRequired();
|
||||
argumentShortcut.Validators.Add(new ShortcutMustExistValidator());
|
||||
|
||||
//description and help text of the command.
|
||||
switchProfileCmd.Description = "Use this command to temporarily change profiles, and load your favourite game or application.";
|
||||
switchProfileCmd.Description = "Use this command to run favourite game or application with a display profile of your choosing.";
|
||||
|
||||
switchProfileCmd.OnExecute(() =>
|
||||
{
|
||||
Console.WriteLine($"Editing profile {argumentShortcut.Value}");
|
||||
|
||||
SwitchToProfile(GetProfile(argumentShortcut.Value));
|
||||
|
||||
//
|
||||
RunShortcut(argumentShortcut.Value);
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// This is the EditProfile command
|
||||
app.Command("EditProfile", (editProfileCmd) =>
|
||||
/*// This is the EditProfile command
|
||||
app.Command(SupportedProgramMode.EditProfile.ToString(), (editProfileCmd) =>
|
||||
{
|
||||
//description and help text of the command.
|
||||
editProfileCmd.Description = "Use this command to edit a HeliosDMPlus profile.";
|
||||
@ -184,7 +120,7 @@ namespace HeliosPlus {
|
||||
return 0;
|
||||
});
|
||||
|
||||
});
|
||||
});*/
|
||||
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
@ -312,15 +248,15 @@ namespace HeliosPlus {
|
||||
|
||||
}
|
||||
|
||||
private static void SwitchToExecutable(ProfileItem profile, string executableToRun, string processToMonitor, uint timeout, string executableArguments)
|
||||
{
|
||||
var rollbackProfile = ProfileRepository.CurrentProfile;
|
||||
|
||||
if (!profile.IsPossible)
|
||||
// ReSharper disable once CyclomaticComplexity
|
||||
private static void RunShortcut(string shortcutUUID)
|
||||
{
|
||||
throw new Exception(Language.Selected_profile_is_not_possible);
|
||||
}
|
||||
ProfileItem rollbackProfile = ProfileRepository.CurrentProfile;
|
||||
ShortcutItem shortcutToRun = null;
|
||||
|
||||
// Check there is only one version of this application so we won't
|
||||
// mess with another monitoring session
|
||||
if (
|
||||
IPCClient.QueryAll()
|
||||
.Any(
|
||||
@ -333,22 +269,67 @@ namespace HeliosPlus {
|
||||
.Another_instance_of_this_program_is_in_working_state_Please_close_other_instances_before_trying_to_switch_profile);
|
||||
}
|
||||
|
||||
if (!GoProfile(profile))
|
||||
// Match the ShortcutName to the actual shortcut listed in the shortcut library
|
||||
// And error if we can't find it.
|
||||
if (ShortcutRepository.ContainsShortcut(shortcutUUID))
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
// make sure we trim the "" if there are any
|
||||
shortcutUUID = shortcutUUID.Trim('"');
|
||||
shortcutToRun = ShortcutRepository.GetShortcut(shortcutUUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception(Language.Cannot_find_shortcut_in_library);
|
||||
}
|
||||
|
||||
var process = System.Diagnostics.Process.Start(executableToRun, executableArguments);
|
||||
var processes = new System.Diagnostics.Process[0];
|
||||
|
||||
var ticks = 0;
|
||||
|
||||
while (ticks < timeout * 1000)
|
||||
// Do some validation to make sure the shortcut is sensible
|
||||
// And that we have enough to try and action within the shortcut
|
||||
// (in other words check everything in the shortcut is still valid)
|
||||
(bool valid, string reason) = shortcutToRun.IsValid();
|
||||
if (!valid)
|
||||
{
|
||||
throw new Exception(string.Format("Unable to run the shortcut '{0}': {1}",shortcutToRun.Name,reason));
|
||||
}
|
||||
|
||||
processes = System.Diagnostics.Process.GetProcessesByName(processToMonitor);
|
||||
// Try to change to the wanted profile
|
||||
if (!SwitchProfile(shortcutToRun.ProfileToUse))
|
||||
{
|
||||
throw new Exception(Language.Cannot_change_active_profile);
|
||||
}
|
||||
|
||||
if (processes.Length > 0)
|
||||
// Now run the pre-start applications
|
||||
// TODO: Add the prestart applications
|
||||
|
||||
// Now start the main game, and wait if we have to
|
||||
if (shortcutToRun.Category.Equals(ShortcutCategory.Application))
|
||||
{
|
||||
// Start the executable
|
||||
Process process = null;
|
||||
if (shortcutToRun.ExecutableArgumentsRequired)
|
||||
process = System.Diagnostics.Process.Start(shortcutToRun.ExecutableNameAndPath, shortcutToRun.ExecutableArguments);
|
||||
else
|
||||
process = System.Diagnostics.Process.Start(shortcutToRun.ExecutableNameAndPath);
|
||||
|
||||
// Create a list of processes to monitor
|
||||
Process[] processesToMonitor = Array.Empty<Process>();
|
||||
|
||||
// Work out if we are monitoring another process other than the main executable
|
||||
if (shortcutToRun.ProcessNameToMonitorUsesExecutable)
|
||||
{
|
||||
// If we are monitoring the same executable we started, then lets do that
|
||||
processesToMonitor = new[] { process };
|
||||
}
|
||||
else
|
||||
{
|
||||
// Now wait a little while for all the processes we want to monitor to start up
|
||||
var ticks = 0;
|
||||
while (ticks < shortcutToRun.ExecutableTimeout * 1000)
|
||||
{
|
||||
// Look for the processes with the ProcessName we want (which in Windows is the filename without the extension)
|
||||
processesToMonitor = System.Diagnostics.Process.GetProcessesByName(Path.GetFileNameWithoutExtension(shortcutToRun.DifferentExecutableToMonitor));
|
||||
|
||||
// TODO: Fix this logic error that will only ever wait for the first process....
|
||||
if (processesToMonitor.Length > 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
@ -357,16 +338,19 @@ namespace HeliosPlus {
|
||||
ticks += 300;
|
||||
}
|
||||
|
||||
|
||||
if (processes.Length == 0)
|
||||
// If none started up before the timeout, then ignore the
|
||||
if (processesToMonitor.Length == 0)
|
||||
{
|
||||
processes = new[] { process };
|
||||
processesToMonitor = new[] { process };
|
||||
}
|
||||
}
|
||||
|
||||
IPCService.GetInstance().HoldProcessId = processes.FirstOrDefault()?.Id ?? 0;
|
||||
// Store the process to monitor for later
|
||||
IPCService.GetInstance().HoldProcessId = processesToMonitor.FirstOrDefault()?.Id ?? 0;
|
||||
IPCService.GetInstance().Status = InstanceStatus.OnHold;
|
||||
NotifyIcon notify = null;
|
||||
|
||||
// Add a status notification icon in the status area
|
||||
NotifyIcon notify = null;
|
||||
try
|
||||
{
|
||||
notify = new NotifyIcon
|
||||
@ -374,7 +358,7 @@ namespace HeliosPlus {
|
||||
Icon = Properties.Resources.HeliosPlus,
|
||||
Text = string.Format(
|
||||
Language.Waiting_for_the_0_to_terminate,
|
||||
processes[0].ProcessName),
|
||||
processesToMonitor[0].ProcessName),
|
||||
Visible = true
|
||||
};
|
||||
Application.DoEvents();
|
||||
@ -385,7 +369,8 @@ namespace HeliosPlus {
|
||||
// ignored
|
||||
}
|
||||
|
||||
foreach (var p in processes)
|
||||
// Wait for the monitored process to exit
|
||||
foreach (var p in processesToMonitor)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -398,6 +383,8 @@ namespace HeliosPlus {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the status notification icon from the status area
|
||||
// once we've existed the game
|
||||
if (notify != null)
|
||||
{
|
||||
notify.Visible = false;
|
||||
@ -405,92 +392,32 @@ namespace HeliosPlus {
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
IPCService.GetInstance().Status = InstanceStatus.Busy;
|
||||
|
||||
// Change back to the original profile if it is different
|
||||
if (!ProfileRepository.IsActiveProfile(rollbackProfile))
|
||||
{
|
||||
if (!GoProfile(rollbackProfile))
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void SwitchToSteamGame(ProfileItem profile, string steamGameIdToRun, uint timeout, string steamGameArguments)
|
||||
else if (shortcutToRun.Category.Equals(ShortcutCategory.Game))
|
||||
{
|
||||
|
||||
// Convert the steamGameIdToRun string to a uint for Steam Games
|
||||
uint steamGameIdUint = 0;
|
||||
if (!uint.TryParse(steamGameIdToRun, out steamGameIdUint))
|
||||
// If the game is a Steam Game we check for that
|
||||
if (shortcutToRun.GameLibrary.Equals(SupportedGameLibrary.Steam))
|
||||
{
|
||||
throw new Exception("ERROR - Couldn't convert the string steamGameIdToRun parameter to steamGameIdUint in SwitchToSteamGame!");
|
||||
}
|
||||
// We now need to get the SteamGame info
|
||||
SteamGame steamGameToRun = SteamLibrary.GetSteamGame(shortcutToRun.GameAppId);
|
||||
|
||||
// Save the profile we're on now
|
||||
var rollbackProfile = ProfileRepository.CurrentProfile;
|
||||
|
||||
// Check that the profile we've been asked to change to will actually work
|
||||
if (!profile.IsPossible)
|
||||
// If the GameAppID matches a Steam game, then lets run it
|
||||
if (steamGameToRun is SteamGame)
|
||||
{
|
||||
throw new Exception(Language.Selected_profile_is_not_possible);
|
||||
}
|
||||
|
||||
//
|
||||
if ( IPCClient.QueryAll().Any(
|
||||
client =>
|
||||
client.Status == InstanceStatus.Busy ||
|
||||
client.Status == InstanceStatus.OnHold))
|
||||
{
|
||||
throw new Exception(
|
||||
Language
|
||||
.Another_instance_of_this_program_is_in_working_state_Please_close_other_instances_before_trying_to_switch_profile);
|
||||
}
|
||||
|
||||
// Create the SteamGame objects so we can use them shortly
|
||||
// Get the game information relevant to the game we're switching to
|
||||
List<SteamGame> allSteamGames = SteamGame.GetAllInstalledGames();
|
||||
|
||||
// Check if Steam is installed and error if it isn't
|
||||
if (!SteamGame.SteamInstalled)
|
||||
{
|
||||
throw new Exception(Language.Steam_is_not_installed);
|
||||
}
|
||||
|
||||
// Otherwise try to find the game we've been asked to run
|
||||
SteamGame steamGameToRun = null;
|
||||
foreach (SteamGame steamGameToCheck in allSteamGames)
|
||||
{
|
||||
if (steamGameToCheck.GameId == steamGameIdUint)
|
||||
{
|
||||
steamGameToRun = steamGameToCheck;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Attempt to change to a different profile if it's needed
|
||||
if (!GoProfile(profile))
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
}
|
||||
|
||||
// Prepare to start the steam game using the URI interface
|
||||
// as used by Steam for it's own desktop shortcuts.
|
||||
var address = $"steam://rungameid/{steamGameToRun.GameId}";
|
||||
if (!string.IsNullOrWhiteSpace(steamGameArguments))
|
||||
if (shortcutToRun.GameArgumentsRequired)
|
||||
{
|
||||
address += "/" + steamGameArguments;
|
||||
address += "/" + shortcutToRun.GameArguments;
|
||||
}
|
||||
|
||||
|
||||
// Start the URI Handler to run Steam
|
||||
var steamProcess = System.Diagnostics.Process.Start(address);
|
||||
// Wait for steam game to update and then run
|
||||
var ticks = 0;
|
||||
|
||||
while (ticks < timeout * 1000)
|
||||
// Wait for Steam game to update if needed
|
||||
var ticks = 0;
|
||||
while (ticks < shortcutToRun.GameTimeout * 1000)
|
||||
{
|
||||
if (steamGameToRun.IsRunning)
|
||||
{
|
||||
@ -505,10 +432,12 @@ namespace HeliosPlus {
|
||||
}
|
||||
}
|
||||
|
||||
// Store the Steam Process ID for later
|
||||
IPCService.GetInstance().HoldProcessId = steamProcess?.Id ?? 0;
|
||||
IPCService.GetInstance().Status = InstanceStatus.OnHold;
|
||||
NotifyIcon notify = null;
|
||||
|
||||
// Add a status notification icon in the status area
|
||||
NotifyIcon notify = null;
|
||||
try
|
||||
{
|
||||
notify = new NotifyIcon
|
||||
@ -541,6 +470,8 @@ namespace HeliosPlus {
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the status notification icon from the status area
|
||||
// once we've existed the game
|
||||
if (notify != null)
|
||||
{
|
||||
notify.Visible = false;
|
||||
@ -548,169 +479,88 @@ namespace HeliosPlus {
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// If the game is a Uplay Game we check for that
|
||||
/*else if (GameLibrary.Equals(SupportedGameLibrary.Uplay))
|
||||
{
|
||||
// We need to look up details about the game
|
||||
if (!UplayGame.IsInstalled(GameAppId))
|
||||
{
|
||||
return (false, string.Format("The Uplay Game with AppID '{0}' is not installed on this computer.", GameAppId));
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
IPCService.GetInstance().Status = InstanceStatus.Busy;
|
||||
|
||||
// Change back to the original profile if it is different
|
||||
if (!ProfileRepository.IsActiveProfile(rollbackProfile))
|
||||
{
|
||||
if (!GoProfile(rollbackProfile))
|
||||
if (!SwitchProfile(rollbackProfile))
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
throw new Exception(Language.Cannot_change_active_profile);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void SwitchToUplayGame(ProfileItem profile, string uplayGameIdToRun, uint timeout, string uplayGameArguments)
|
||||
internal static bool SwitchProfile(ProfileItem profile)
|
||||
{
|
||||
// If we're already on the wanted profile then no need to change!
|
||||
if (ProfileRepository.IsActiveProfile(profile))
|
||||
return true;
|
||||
|
||||
var rollbackProfile = ProfileRepository.CurrentProfile;
|
||||
|
||||
if (!profile.IsPossible)
|
||||
{
|
||||
throw new Exception(Language.Selected_profile_is_not_possible);
|
||||
}
|
||||
|
||||
if (
|
||||
IPCClient.QueryAll()
|
||||
.Any(
|
||||
client =>
|
||||
client.Status == InstanceStatus.Busy ||
|
||||
client.Status == InstanceStatus.OnHold))
|
||||
{
|
||||
throw new Exception(
|
||||
Language
|
||||
.Another_instance_of_this_program_is_in_working_state_Please_close_other_instances_before_trying_to_switch_profile);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*var steamGame = new SteamGame(Convert.ToUInt32(uplayGameIdToRun));
|
||||
|
||||
if (!SteamGame.SteamInstalled)
|
||||
{
|
||||
throw new Exception(Language.Steam_is_not_installed);
|
||||
}
|
||||
|
||||
if (!File.Exists(SteamGame.SteamExe))
|
||||
{
|
||||
throw new Exception(Language.Steam_executable_file_not_found);
|
||||
}
|
||||
|
||||
if (!steamGame.IsInstalled)
|
||||
{
|
||||
throw new Exception(Language.Steam_game_is_not_installed);
|
||||
}
|
||||
|
||||
if (!GoProfile(profile))
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
}
|
||||
|
||||
var address = $"uplay://rungameid/{steamGame.AppId}";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(uplayGameArguments))
|
||||
{
|
||||
address += "/" + uplayGameArguments;
|
||||
}
|
||||
|
||||
var steamProcess = System.Diagnostics.Process.Start(address);
|
||||
// Wait for steam game to update and then run
|
||||
var ticks = 0;
|
||||
|
||||
while (ticks < timeout * 1000)
|
||||
{
|
||||
if (steamGame.IsRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(300);
|
||||
|
||||
if (!steamGame.IsUpdating)
|
||||
{
|
||||
ticks += 300;
|
||||
}
|
||||
}
|
||||
|
||||
IPCService.GetInstance().HoldProcessId = steamProcess?.Id ?? 0;
|
||||
IPCService.GetInstance().Status = InstanceStatus.OnHold;
|
||||
NotifyIcon notify = null;
|
||||
var instanceStatus = IPCService.GetInstance().Status;
|
||||
|
||||
try
|
||||
{
|
||||
notify = new NotifyIcon
|
||||
{
|
||||
Icon = Properties.Resources.Icon,
|
||||
Text = string.Format(
|
||||
Language.Waiting_for_the_0_to_terminate,
|
||||
steamGame.Name),
|
||||
Visible = true
|
||||
};
|
||||
Application.DoEvents();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
// Wait for the game to exit
|
||||
if (steamGame.IsRunning)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!steamGame.IsRunning)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(300);
|
||||
}
|
||||
}
|
||||
|
||||
if (notify != null)
|
||||
{
|
||||
notify.Visible = false;
|
||||
notify.Dispose();
|
||||
Application.DoEvents();
|
||||
}
|
||||
|
||||
IPCService.GetInstance().Status = InstanceStatus.Busy;
|
||||
var failed = false;
|
||||
|
||||
// Change back to the original profile if it is different
|
||||
if (!ProfileRepository.IsActiveProfile(rollbackProfile))
|
||||
if (new ApplyingChangesForm(() =>
|
||||
{
|
||||
if (!GoProfile(rollbackProfile))
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
if (!(ProfileRepository.ApplyProfile(profile)))
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
}*/
|
||||
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
}, 3, 30).ShowDialog() !=
|
||||
DialogResult.Cancel)
|
||||
{
|
||||
if (failed)
|
||||
{
|
||||
throw new Exception(Language.Profile_is_invalid_or_not_possible_to_apply);
|
||||
}
|
||||
|
||||
|
||||
// ReSharper disable once CyclomaticComplexity
|
||||
private static void SwitchToProfile(ProfileItem profile)
|
||||
{
|
||||
var rollbackProfile = ProfileRepository.CurrentProfile;
|
||||
|
||||
if (
|
||||
IPCClient.QueryAll()
|
||||
.Any(
|
||||
client =>
|
||||
client.Status == InstanceStatus.Busy ||
|
||||
client.Status == InstanceStatus.OnHold))
|
||||
{
|
||||
throw new Exception(
|
||||
Language
|
||||
.Another_instance_of_this_program_is_in_working_state_Please_close_other_instances_before_trying_to_switch_profile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!GoProfile(profile))
|
||||
{
|
||||
throw new Exception(Language.Can_not_change_active_profile);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IPCService.GetInstance().Status = instanceStatus;
|
||||
}
|
||||
}
|
||||
|
||||
private static void EditProfile(ProfileItem profile)
|
||||
{
|
||||
// Get the status of the thing
|
||||
IPCService.GetInstance().Status = InstanceStatus.User;
|
||||
// Load all the profiles from JSON
|
||||
//ProfileRepository.AllProfiles
|
||||
// Start up the DisplayProfileForm directly
|
||||
new DisplayProfileForm(profile).ShowDialog();
|
||||
// Then we close down as we're only here to edit one profile
|
||||
Application.Exit();
|
||||
}
|
||||
|
||||
public static bool IsValidFilename(string testName)
|
||||
|
29
HeliosPlus/Resources/Language.Designer.cs
generated
29
HeliosPlus/Resources/Language.Designer.cs
generated
@ -133,15 +133,6 @@ namespace HeliosPlus.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Can not change active profile..
|
||||
/// </summary>
|
||||
internal static string Can_not_change_active_profile {
|
||||
get {
|
||||
return ResourceManager.GetString("Can_not_change_active_profile", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Can not open a named pipe for Inter-process communication..
|
||||
/// </summary>
|
||||
@ -160,6 +151,24 @@ namespace HeliosPlus.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cannot change active profile..
|
||||
/// </summary>
|
||||
internal static string Cannot_change_active_profile {
|
||||
get {
|
||||
return ResourceManager.GetString("Cannot_change_active_profile", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Cannot find the shortcut '{0}' in the Shortcut library..
|
||||
/// </summary>
|
||||
internal static string Cannot_find_shortcut_in_library {
|
||||
get {
|
||||
return ResourceManager.GetString("Cannot_find_shortcut_in_library", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to C&lone.
|
||||
/// </summary>
|
||||
@ -791,7 +800,7 @@ namespace HeliosPlus.Resources {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Waiting for the '{0}' to terminate.
|
||||
/// Looks up a localized string similar to Waiting for the '{0}' process to terminate.
|
||||
/// </summary>
|
||||
internal static string Waiting_for_the_0_to_terminate {
|
||||
get {
|
||||
|
@ -306,7 +306,7 @@
|
||||
<data name="Another_instance_of_this_program_is_in_working_state_Please_close_other_instances_before_trying_to_switch_profile" xml:space="preserve">
|
||||
<value>Another instance of this program is in working state. Please close other instances before trying to switch profile.</value>
|
||||
</data>
|
||||
<data name="Can_not_change_active_profile" xml:space="preserve">
|
||||
<data name="Cannot_change_active_profile" xml:space="preserve">
|
||||
<value>Cannot change active profile.</value>
|
||||
</data>
|
||||
<data name="Steam_executable_file_not_found" xml:space="preserve">
|
||||
@ -358,7 +358,7 @@
|
||||
<value>Saved Profiles</value>
|
||||
</data>
|
||||
<data name="Waiting_for_the_0_to_terminate" xml:space="preserve">
|
||||
<value>Waiting for the '{0}' to terminate</value>
|
||||
<value>Waiting for the '{0}' process to terminate</value>
|
||||
</data>
|
||||
<data name="Apply_Profile" xml:space="preserve">
|
||||
<value>Apply_Profile</value>
|
||||
@ -369,4 +369,7 @@
|
||||
<data name="Press_ESC_to_cancel" xml:space="preserve">
|
||||
<value>Press ESC to cancel</value>
|
||||
</data>
|
||||
<data name="Cannot_find_shortcut_in_library" xml:space="preserve">
|
||||
<value>Cannot find the shortcut '{0}' in the Shortcut library.</value>
|
||||
</data>
|
||||
</root>
|
@ -510,6 +510,66 @@ namespace HeliosPlus
|
||||
return multiIcon;
|
||||
}
|
||||
|
||||
|
||||
public (bool,string) IsValid()
|
||||
{
|
||||
// Do some validation checks to make sure the shortcut is sensible
|
||||
// And that we have enough to try and action within the shortcut
|
||||
// (in other words check everything in the shortcut is still valid)
|
||||
|
||||
// Does the profile we want to Use still exist?
|
||||
// Is the profile still valid right now? i.e. are all the screens available?
|
||||
if (!ProfileToUse.IsPossible)
|
||||
{
|
||||
return (false,string.Format("The profile '{0}' is not valid right now and cannot be used.",ProfileToUse.Name));
|
||||
}
|
||||
// Is the main application still installed?
|
||||
if (Category.Equals(ShortcutCategory.Application))
|
||||
{
|
||||
// We need to check if the Application still exists
|
||||
if (!System.IO.File.Exists(ExecutableNameAndPath))
|
||||
{
|
||||
return (false, string.Format("The application executable '{0}' does not exist, or cannot be accessed by HeliosPlus.", ExecutableNameAndPath));
|
||||
}
|
||||
|
||||
} else if (Category.Equals(ShortcutCategory.Game))
|
||||
{
|
||||
// If the game is a Steam Game we check for that
|
||||
if (GameLibrary.Equals(SupportedGameLibrary.Steam))
|
||||
{
|
||||
|
||||
// First check if Steam is installed
|
||||
// Check if Steam is installed and error if it isn't
|
||||
if (!SteamLibrary.IsSteamInstalled)
|
||||
{
|
||||
return (false, Language.Steam_executable_file_not_found);
|
||||
}
|
||||
|
||||
// We need to look up details about the game
|
||||
if (!SteamLibrary.ContainsSteamGame(GameAppId))
|
||||
{
|
||||
return (false, string.Format("The Steam Game with AppID '{0}' is not installed on this computer.", GameAppId));
|
||||
}
|
||||
}
|
||||
// If the game is a Uplay Game we check for that
|
||||
/*else if (GameLibrary.Equals(SupportedGameLibrary.Uplay))
|
||||
{
|
||||
// We need to look up details about the game
|
||||
if (!UplayGame.IsInstalled(GameAppId))
|
||||
{
|
||||
return (false, string.Format("The Uplay Game with AppID '{0}' is not installed on this computer.", GameAppId));
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
|
||||
}
|
||||
// Do all the specified pre-start apps still exist?
|
||||
|
||||
return (true, "Shortcut is valid");
|
||||
|
||||
}
|
||||
|
||||
// ReSharper disable once FunctionComplexityOverflow
|
||||
// ReSharper disable once CyclomaticComplexity
|
||||
public bool CreateShortcut(string shortcutFileName)
|
||||
@ -522,7 +582,7 @@ namespace HeliosPlus
|
||||
{
|
||||
// Add the SwitchProfile command as the first argument to start to switch to another profile
|
||||
$"{HeliosStartupAction.SwitchProfile}",
|
||||
$"\"{Name}\""
|
||||
$"\"{UUID}\""
|
||||
};
|
||||
|
||||
// Only add the rest of the options if the permanence is temporary
|
||||
|
@ -24,6 +24,7 @@ namespace HeliosPlus
|
||||
// Other constants that are useful
|
||||
private static string _shortcutStorageJsonPath = Path.Combine(Program.AppDataPath, $"Shortcuts");
|
||||
private static string _shortcutStorageJsonFileName = Path.Combine(_shortcutStorageJsonPath, $"Shortcuts_{Version.ToString(2)}.json");
|
||||
private static string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
|
||||
#endregion
|
||||
|
||||
#region Class Constructors
|
||||
@ -147,7 +148,7 @@ namespace HeliosPlus
|
||||
List<ShortcutItem> shortcutsToRemove;
|
||||
int numRemoved;
|
||||
|
||||
string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
|
||||
//string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
|
||||
Match match = Regex.Match(shortcutNameOrUuid, uuidV4Regex, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
@ -207,7 +208,7 @@ namespace HeliosPlus
|
||||
return false;
|
||||
|
||||
|
||||
string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
|
||||
//string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
|
||||
Match match = Regex.Match(shortcutNameOrUuid, uuidV4Regex, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
@ -238,7 +239,7 @@ namespace HeliosPlus
|
||||
if (String.IsNullOrWhiteSpace(shortcutNameOrUuid))
|
||||
return null;
|
||||
|
||||
string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
|
||||
//string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
|
||||
Match match = Regex.Match(shortcutNameOrUuid, uuidV4Regex, RegexOptions.IgnoreCase);
|
||||
if (match.Success)
|
||||
{
|
||||
|
@ -56,7 +56,7 @@ namespace HeliosPlus.UIForms
|
||||
private void MainForm_Load(object sender, EventArgs e)
|
||||
{
|
||||
// Start loading the Steam Games just after the Main form opens
|
||||
SteamGame.GetAllInstalledGames();
|
||||
//SteamGame.GetAllInstalledGames();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -436,12 +436,12 @@ namespace HeliosPlus.UIForms
|
||||
|
||||
if (txt_game_launcher.Text == SupportedGameLibrary.Steam.ToString())
|
||||
{
|
||||
_shortcutToEdit.OriginalIconPath = (from steamGame in SteamGame.AllGames where steamGame.GameId == _shortcutToEdit.GameAppId select steamGame.GameIconPath).First();
|
||||
_shortcutToEdit.OriginalIconPath = (from steamGame in SteamLibrary.AllInstalledGames where steamGame.GameId == _shortcutToEdit.GameAppId select steamGame.GameIconPath).First();
|
||||
_shortcutToEdit.GameLibrary = SupportedGameLibrary.Steam;
|
||||
}
|
||||
else if (txt_game_launcher.Text == SupportedGameLibrary.Uplay.ToString())
|
||||
{
|
||||
_shortcutToEdit.OriginalIconPath = (from uplayGame in UplayGame.AllGames where uplayGame.GameId == _shortcutToEdit.GameAppId select uplayGame.GameIconPath).First();
|
||||
_shortcutToEdit.OriginalIconPath = (from uplayGame in UplayLibrary.AllInstalledGames where uplayGame.GameId == _shortcutToEdit.GameAppId select uplayGame.GameIconPath).First();
|
||||
_shortcutToEdit.GameLibrary = SupportedGameLibrary.Uplay;
|
||||
}
|
||||
else if (rb_standalone.Checked)
|
||||
@ -646,9 +646,7 @@ namespace HeliosPlus.UIForms
|
||||
|
||||
|
||||
// Start finding the games and loading the Games ListView
|
||||
List<SteamGame> allSteamGames = SteamGame.GetAllInstalledGames();
|
||||
_allSteamGames = allSteamGames;
|
||||
foreach (var game in allSteamGames.OrderBy(game => game.GameName))
|
||||
foreach (var game in SteamLibrary.AllInstalledGames.OrderBy(game => game.GameName))
|
||||
{
|
||||
if (File.Exists(game.GameIconPath))
|
||||
{
|
||||
@ -835,7 +833,7 @@ namespace HeliosPlus.UIForms
|
||||
{
|
||||
if (_loadedShortcut)
|
||||
_isUnsaved = true;
|
||||
txt_game_launcher.Text = SteamGame.GameLibrary.ToString();
|
||||
txt_game_launcher.Text = game.GameLibrary.ToString();
|
||||
_gameId = game.GameId;
|
||||
}
|
||||
}
|
||||
|
@ -20,25 +20,16 @@ namespace HeliosPlus
|
||||
{
|
||||
// This validator only runs if there is a value
|
||||
if (!optionProfile.HasValue()) return ValidationResult.Success;
|
||||
var profile = optionProfile.Value();
|
||||
var profileName = (string) optionProfile.Value();
|
||||
|
||||
// Create an array of display profiles we have
|
||||
var profiles = ProfileRepository.AllProfiles.ToArray();
|
||||
// Check if the user supplied a --profile option using the profiles' ID
|
||||
var profileIndex = profiles.Length > 0 ? Array.FindIndex(profiles, p => p.UUID.Equals(profile, StringComparison.InvariantCultureIgnoreCase)) : -1;
|
||||
// If the profileID wasn't there, maybe they used the profile name?
|
||||
if (profileIndex == -1)
|
||||
// Try to find the Profile Name
|
||||
if (!ProfileRepository.ContainsProfile(profileName))
|
||||
{
|
||||
// Try and lookup the profile in the profiles' Name fields
|
||||
profileIndex = profiles.Length > 0 ? Array.FindIndex(profiles, p => p.Name.StartsWith(profile, StringComparison.InvariantCultureIgnoreCase)) : -1;
|
||||
}
|
||||
// If the profileID still isn't there, then raise the alarm
|
||||
if (profileIndex == -1)
|
||||
{
|
||||
return new ValidationResult($"Couldn't find Profile Name or ID supplied via command line: '{optionProfile.LongName}'. Please check the Profile Name or ID you supplied on the command line is correct.");
|
||||
return new ValidationResult($"Couldn't find Profile Name or ID supplied via command line: '{profileName}'. Please check the Profile Name or ID you supplied on the command line is correct.");
|
||||
}
|
||||
|
||||
Console.WriteLine($"Using Profile: '{profiles[profileIndex].Name}' (ID:{profiles[profileIndex].UUID})");
|
||||
ProfileItem profile = ProfileRepository.GetProfile(profileName);
|
||||
Console.WriteLine($"Using Profile: '{profile.Name}' (ID:{profile.UUID})");
|
||||
return ValidationResult.Success;
|
||||
}
|
||||
}
|
||||
@ -49,34 +40,16 @@ namespace HeliosPlus
|
||||
{
|
||||
// This validator only runs if there is a string provided
|
||||
if (argumentShortcutName.Value == "") return ValidationResult.Success;
|
||||
string shortcutNameProvided = (string) argumentShortcutName.Value;
|
||||
string shortcutName = "";
|
||||
string shortcutName = (string) argumentShortcutName.Value;
|
||||
|
||||
// check if the shortcut name is surrounded by speech marks
|
||||
int shortcutNameIndexLeft = shortcutNameProvided.IndexOf('"');
|
||||
int shortcutNameIndexRight = shortcutNameProvided.LastIndexOf('"');
|
||||
if (shortcutNameIndexLeft != -1 && shortcutNameIndexRight != -1 && shortcutNameIndexLeft != shortcutNameIndexRight)
|
||||
{
|
||||
MatchCollection matches = Regex.Matches(shortcutNameProvided, @"'(.*?)'");
|
||||
shortcutName = matches[0].Groups[1].Value; // (Index 1 is the first group)
|
||||
}
|
||||
else
|
||||
{
|
||||
shortcutName = shortcutNameProvided;
|
||||
}
|
||||
|
||||
// Create an array of shortcuts we have
|
||||
var shortcuts = ShortcutRepository.AllShortcuts.ToArray();
|
||||
// Check if the user supplied a valid shortcut name
|
||||
int profileIndex = shortcuts.Length > 0 ? Array.FindIndex(shortcuts, p => p.Name.Contains(shortcutName)) : -1;
|
||||
|
||||
// If the profileID still isn't there, then raise the alarm
|
||||
if (profileIndex == -1)
|
||||
// Check if the UUID or ShortcutName are provided
|
||||
if (!ShortcutRepository.ContainsShortcut(shortcutName))
|
||||
{
|
||||
return new ValidationResult($"Couldn't find Shortcut Name supplied via command line: '{shortcutName}'. Please check the Shortcut Name you supplied on the command line is correct.");
|
||||
}
|
||||
|
||||
Console.WriteLine($"Using Shortcut: '{shortcuts[profileIndex].Name}'");
|
||||
ShortcutItem shortcut = ShortcutRepository.GetShortcut(shortcutName);
|
||||
Console.WriteLine($"Using Shortcut: '{shortcut.Name}' (ID: {shortcut.UUID})");
|
||||
return ValidationResult.Success;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user