Merge branch 'release/1.0.5' into main

This commit is contained in:
Terry MacDonald 2021-04-23 17:52:39 +12:00
commit 001853b2c5
26 changed files with 2459 additions and 961 deletions

2
.github/FUNDING.yml vendored
View File

@ -1,4 +1,4 @@
# These are supported funding model platforms
github: [terrymacdonald]
custom: ["https://www.buymeacoffee.com/displaymagician", Buy Me a Coffee]
custom: ["https://www.buymeacoffee.com/displaymagician"]

View File

@ -84,6 +84,7 @@
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Web" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq" />
@ -94,6 +95,7 @@
<Compile Include="DesktopNotificationActivator.cs" />
<Compile Include="DesktopNotificationManagerCompat.cs" />
<Compile Include="GameLibraries\Game.cs" />
<Compile Include="GameLibraries\GameLibrary.cs" />
<Compile Include="GameLibraries\GameUtils.cs" />
<Compile Include="GameLibraries\SteamAppInfoParser\AppInfo.cs" />
<Compile Include="GameLibraries\SteamAppInfoParser\EUniverse.cs" />
@ -101,13 +103,14 @@
<Compile Include="GameLibraries\SteamAppInfoParser\PackageInfo.cs" />
<Compile Include="GameLibraries\SteamAppInfoParser\App.cs" />
<Compile Include="GameLibraries\UplayConfigurationParser\UplayConfigurationParser.cs" />
<Compile Include="GameLibraries\OriginGame.cs" />
<Compile Include="GameLibraries\OriginLibrary.cs" />
<Compile Include="GameLibraries\UplayLibrary.cs" />
<Compile Include="GameLibraries\SteamLibrary.cs" />
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="IconFromFile.cs" />
<Compile Include="IconUtils.cs" />
<Compile Include="ImageUtils.cs" />
<Compile Include="ProcessCommandLine.cs" />
<Compile Include="ProgramSettings.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>

View File

@ -3,10 +3,17 @@
public class Game
{
#region Properties
public virtual int Id { get; set; }
public enum GameStartMode
{
URI
}
public virtual SupportedGameLibrary GameLibrary { get; }
#region Properties
public virtual string Id { get; set; }
public virtual SupportedGameLibraryType GameLibrary { get; }
public virtual bool IsRunning { get; set; }
@ -24,11 +31,18 @@
public virtual string ProcessName { get; set; }
public virtual GameStartMode StartMode { get; set; }
#endregion
#region Methods
public virtual bool CopyTo(SteamGame steamGame)
public virtual string GetStartURI(string gameArguments = "")
{
return "";
}
public virtual bool CopyTo(Game steamGame)
{
return true;
}

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
namespace DisplayMagician.GameLibraries
{
public enum SupportedGameLibraryType
{
Unknown,
Steam,
Uplay,
Origin
}
public class GameLibrary
{
public struct GameAppInfo
{
public string GameID;
public string GameName;
public string GameExePath;
public string GameInstallDir;
public string GameIconPath;
}
#region Class Properties
public virtual List<Game> AllInstalledGames { get; set; }
public virtual int InstalledGameCount { get; set; }
public virtual string GameLibraryName { get; set; }
public virtual SupportedGameLibraryType GameLibraryType { get; set; }
public virtual string GameLibraryExe { get; set; }
public virtual string GameLibraryPath { get; set; }
public virtual bool IsGameLibraryInstalled { get; set; }
public virtual bool IsRunning { get; set; }
public virtual List<string> GameLibraryProcesses { get; set; }
#endregion
#region Class Methods
public virtual bool AddGame(Game game)
{
return false;
}
public virtual bool RemoveGame(Game game)
{
return false;
}
public virtual bool RemoveGameById(string gameId)
{
return false;
}
public virtual bool RemoveGame(string gameNameOrId)
{
return false;
}
public virtual bool ContainsGame(Game game)
{
return false;
}
public virtual bool ContainsGameById(string gameId)
{
return false;
}
public virtual bool ContainsGame(string gameNameOrId)
{
return false;
}
public virtual Game GetGame(string gameNameOrId)
{
return null;
}
public virtual Game GetGameById(string gameId)
{
return null;
}
public virtual bool LoadInstalledGames()
{
return false;
}
#endregion
}
[global::System.Serializable]
public class GameLibraryException : Exception
{
public GameLibraryException() { }
public GameLibraryException(string message) : base(message) { }
public GameLibraryException(string message, Exception inner) : base(message, inner) { }
protected GameLibraryException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

@ -0,0 +1,210 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using DisplayMagician.Resources;
using System.Diagnostics;
namespace DisplayMagician.GameLibraries
{
public class OriginGame : Game
{
private string _originGameId;
private string _originGameName;
private string _originGameExePath;
private string _originGameDir;
private string _originGameExe;
private string _originGameProcessName;
private string _originGameIconPath;
//private string _originURI;
private static readonly OriginLibrary _originGameLibrary = OriginLibrary.GetLibrary();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static OriginGame()
{
ServicePointManager.ServerCertificateValidationCallback +=
(send, certificate, chain, sslPolicyErrors) => true;
}
public OriginGame(string originGameId, string originGameName, string originGameExePath, string originGameIconPath)
{
//_gameRegistryKey = $@"{OriginLibrary.registryOriginInstallsKey}\\{OriginGameId}";
_originGameId = originGameId;
_originGameName = originGameName;
_originGameExePath = originGameExePath;
_originGameDir = Path.GetDirectoryName(originGameExePath);
_originGameExe = Path.GetFileName(_originGameExePath);
_originGameProcessName = Path.GetFileNameWithoutExtension(_originGameExePath);
_originGameIconPath = originGameIconPath;
}
public override string Id
{
get => _originGameId;
set => _originGameId = value;
}
public override string Name
{
get => _originGameName;
set => _originGameName = value;
}
public override SupportedGameLibraryType GameLibrary
{
get => SupportedGameLibraryType.Origin;
}
public override string IconPath
{
get => _originGameIconPath;
set => _originGameIconPath = value;
}
public override string ExePath
{
get => _originGameExePath;
set => _originGameExePath = value;
}
public override string Directory
{
get => _originGameDir;
set => _originGameDir = value;
}
public override bool IsRunning
{
get
{
int numGameProcesses = 0;
List<Process> gameProcesses = Process.GetProcessesByName(_originGameProcessName).ToList();
foreach (Process gameProcess in gameProcesses)
{
try
{
if (gameProcess.ProcessName.Equals(_originGameProcessName))
numGameProcesses++;
}
catch (Exception ex)
{
logger.Debug(ex, $"OriginGame/IsRunning: Accessing Process.ProcessName caused exception. Trying GameUtils.GetMainModuleFilepath instead");
// If there is a race condition where MainModule isn't available, then we
// instead try the much slower GetMainModuleFilepath (which does the same thing)
string filePath = GameUtils.GetMainModuleFilepath(gameProcess.Id);
if (filePath == null)
{
// if we hit this bit then GameUtils.GetMainModuleFilepath failed,
// so we just assume that the process is a game process
// as it matched the original process search
numGameProcesses++;
continue;
}
else
{
if (filePath.StartsWith(_originGameExePath))
numGameProcesses++;
}
}
}
if (numGameProcesses > 0)
return true;
else
return false;
}
}
// Have to do much more research to figure out how to detect when Origin is updating a game
/*public override bool IsUpdating
{
get
{
try
{
using (
var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree))
{
if ((int)key?.GetValue(@"Updating", 0) == 1)
{
return true;
}
return false;
}
}
catch (SecurityException ex)
{
Console.WriteLine($"OriginGame/IsUpdating securityexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
if (ex.Source != null)
Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message);
throw;
}
catch (IOException ex)
{
// Extract some information from this exception, and then
// throw it to the parent method.
Console.WriteLine($"OriginGame/IsUpdating ioexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
if (ex.Source != null)
Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message);
throw;
}
}
}*/
public override GameStartMode StartMode
{
get => GameStartMode.URI;
}
public override string GetStartURI(string gameArguments = "")
{
string address = $"origin2://game/launch?offerIds={_originGameId}";
if (String.IsNullOrWhiteSpace(gameArguments))
{
address += "/" + gameArguments;
}
return address;
}
public bool CopyTo(OriginGame OriginGame)
{
if (!(OriginGame is OriginGame))
return false;
// Copy all the game data over to the other game
OriginGame.IconPath = IconPath;
OriginGame.Id = Id;
OriginGame.Name = Name;
OriginGame.ExePath = ExePath;
OriginGame.Directory = Directory;
return true;
}
public override string ToString()
{
var name = _originGameName;
if (string.IsNullOrWhiteSpace(name))
{
name = Language.Unknown;
}
if (IsRunning)
{
return name + " " + Language.Running;
}
/*if (IsUpdating)
{
return name + " " + Language.Updating;
}*/
return name;
}
}
}

View File

@ -0,0 +1,728 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Win32;
using System.IO;
using System.Security;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Web;
using System.Diagnostics;
namespace DisplayMagician.GameLibraries
{
public sealed class OriginLibrary : GameLibrary
{
#region Class Variables
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static readonly OriginLibrary _instance = new OriginLibrary();
// Common items to the class
private List<Game> _allOriginGames = new List<Game>();
private string OriginAppIdRegex = @"/^[0-9A-F]{1,10}$";
private string _originExe;
private string _originPath;
private string _originLocalContent = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Origin");
private bool _isOriginInstalled = false;
private List<string> _originProcessList = new List<string>(){ "origin" };
//private string _originConfigVdfFile;
internal string registryOriginLauncherKey = @"SOFTWARE\WOW6432Node\Origin";
//internal string registryOriginInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
//internal string registryOriginOpenCmdKey = @"SOFTWARE\Classes\Origin\Shell\Open\Command";
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
#region Class Constructors
static OriginLibrary() { }
private OriginLibrary()
{
try
{
logger.Trace($"OriginLibrary/OriginLibrary: Origin launcher registry key = HKLM\\{registryOriginLauncherKey}");
// Find the OriginExe location, and the OriginPath for later
RegistryKey OriginInstallKey = Registry.LocalMachine.OpenSubKey(registryOriginLauncherKey, RegistryKeyPermissionCheck.ReadSubTree);
if (OriginInstallKey == null)
return;
_originExe = OriginInstallKey.GetValue("ClientPath", @"C:\Program Files (x86)\Origin\Origin.exe").ToString();
_originPath = _originExe;
_originPath = _originPath.Replace(@"\Origin.exe", "");
if (File.Exists(_originExe))
{
logger.Info($"OriginLibrary/OriginLibrary: Origin library is installed in {_originPath}. Found {_originExe}");
_isOriginInstalled = true;
}
else
{
logger.Info($"OriginLibrary/OriginLibrary: Origin library is not installed!");
}
}
catch (SecurityException ex)
{
logger.Warn(ex, "OriginLibrary/OriginLibrary: The user does not have the permissions required to read the Origin ClientPath registry key.");
}
catch(ObjectDisposedException ex)
{
logger.Warn(ex, "OriginLibrary/OriginLibrary: The Microsoft.Win32.RegistryKey is closed when trying to access the Origin ClientPath registry key (closed keys cannot be accessed).");
}
catch (IOException ex)
{
logger.Warn(ex, "OriginLibrary/OriginLibrary: The Origin ClientPath registry key has been marked for deletion so we cannot access the value dueing the OriginLibrary check.");
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "OriginLibrary/OriginLibrary: The user does not have the necessary registry rights to check whether Origin is installed.");
}
}
#endregion
#region Class Properties
public override List<Game> AllInstalledGames
{
get
{
// Load the Origin Games from Origin Client if needed
if (_allOriginGames.Count == 0)
LoadInstalledGames();
return _allOriginGames;
}
}
public override int InstalledGameCount
{
get
{
return _allOriginGames.Count;
}
}
public override string GameLibraryName
{
get
{
return "Origin";
}
}
public override SupportedGameLibraryType GameLibraryType
{
get
{
return SupportedGameLibraryType.Origin;
}
}
public override string GameLibraryExe
{
get
{
return _originExe;
}
}
public override string GameLibraryPath
{
get
{
return _originPath;
}
}
public override bool IsGameLibraryInstalled
{
get
{
return _isOriginInstalled;
}
}
public override bool IsRunning
{
get
{
List<Process> originLibraryProcesses = new List<Process>();
foreach (string originLibraryProcessName in _originProcessList)
{
// Look for the processes with the ProcessName we sorted out earlier
originLibraryProcesses.AddRange(Process.GetProcessesByName(originLibraryProcessName));
}
// If we have found one or more processes then we should be good to go
// so let's break, and get to the next step....
if (originLibraryProcesses.Count > 0)
return true;
else
return false;
}
}
public override List<string> GameLibraryProcesses
{
get
{
return _originProcessList;
}
}
#endregion
#region Class Methods
public static OriginLibrary GetLibrary()
{
return _instance;
}
public override bool AddGame(Game originGame)
{
if (!(originGame is OriginGame))
return false;
// Doublecheck if it already exists
// Because then we just update the one that already exists
if (ContainsGame(originGame))
{
logger.Debug($"OriginLibrary/AddOriginGame: Updating Origin game {originGame.Name} in our Origin library");
// We update the existing Shortcut with the data over
OriginGame originGameToUpdate = (OriginGame)GetGame(originGame.Id.ToString());
originGame.CopyTo(originGameToUpdate);
}
else
{
logger.Debug($"OriginLibrary/AddOriginGame: Adding Origin game {originGame.Name} to our Origin library");
// Add the OriginGame to the list of OriginGames
_allOriginGames.Add(originGame);
}
//Doublecheck it's been added
if (ContainsGame(originGame))
{
return true;
}
else
return false;
}
public override bool RemoveGame(Game originGame)
{
if (!(originGame is OriginGame))
return false;
logger.Debug($"OriginLibrary/RemoveOriginGame: Removing Origin game {originGame.Name} from our Origin library");
// Remove the OriginGame from the list.
int numRemoved = _allOriginGames.RemoveAll(item => item.Id.Equals(originGame.Id));
if (numRemoved == 1)
{
logger.Debug($"OriginLibrary/RemoveOriginGame: Removed Origin game with name {originGame.Name}");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"OriginLibrary/RemoveOriginGame: Didn't remove Origin game with ID {originGame.Name} from the Origin Library");
return false;
}
else
throw new OriginLibraryException();
}
public override bool RemoveGameById(string originGameId)
{
if (originGameId.Equals(0))
return false;
logger.Debug($"OriginLibrary/RemoveOriginGame2: Removing Origin game with ID {originGameId} from the Origin library");
// Remove the OriginGame from the list.
int numRemoved = _allOriginGames.RemoveAll(item => item.Id.Equals(originGameId));
if (numRemoved == 1)
{
logger.Debug($"OriginLibrary/RemoveOriginGame2: Removed Origin game with ID {originGameId}");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"OriginLibrary/RemoveOriginGame2: Didn't remove Origin game with ID {originGameId} from the Origin Library");
return false;
}
else
throw new OriginLibraryException();
}
public override bool RemoveGame(string originGameNameOrId)
{
if (String.IsNullOrWhiteSpace(originGameNameOrId))
return false;
logger.Debug($"OriginLibrary/RemoveOriginGame3: Removing Origin game with Name or ID {originGameNameOrId} from the Origin library");
int numRemoved;
Match match = Regex.Match(originGameNameOrId, OriginAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
numRemoved = _allOriginGames.RemoveAll(item => originGameNameOrId.Equals(item.Id));
else
numRemoved = _allOriginGames.RemoveAll(item => originGameNameOrId.Equals(item.Name));
if (numRemoved == 1)
{
logger.Debug($"OriginLibrary/RemoveOriginGame3: Removed Origin game with Name or UUID {originGameNameOrId} ");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"OriginLibrary/RemoveOriginGame3: Didn't remove Origin game with Name or UUID {originGameNameOrId} from the Origin Library");
return false;
}
else
throw new OriginLibraryException();
}
public override bool ContainsGame(Game originGame)
{
if (!(originGame is OriginGame))
return false;
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (testOriginGame.Id.Equals(originGame.Id))
return true;
}
return false;
}
public override bool ContainsGameById(string originGameId)
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (originGameId == testOriginGame.Id)
return true;
}
return false;
}
public override bool ContainsGame(string originGameNameOrId)
{
if (String.IsNullOrWhiteSpace(originGameNameOrId))
return false;
Match match = Regex.Match(originGameNameOrId, OriginAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (originGameNameOrId.Equals(Convert.ToInt32(testOriginGame.Id)))
return true;
}
}
else
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (originGameNameOrId.Equals(testOriginGame.Name))
return true;
}
}
return false;
}
public override Game GetGame(string originGameNameOrId)
{
if (String.IsNullOrWhiteSpace(originGameNameOrId))
return null;
Match match = Regex.Match(originGameNameOrId, OriginAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (originGameNameOrId.Equals(Convert.ToInt32(testOriginGame.Id)))
return testOriginGame;
}
}
else
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (originGameNameOrId.Equals(testOriginGame.Name))
return testOriginGame;
}
}
return null;
}
public override Game GetGameById(string originGameId)
{
foreach (OriginGame testOriginGame in _allOriginGames)
{
if (originGameId == testOriginGame.Id)
return testOriginGame;
}
return null;
}
private Dictionary<string, string> ParseOriginManifest(string path)
{
string encodedContents = File.ReadAllText(path);
Dictionary<string, string> parameters = Regex.Matches(encodedContents, "([^?=&]+)(=([^&]*))?").Cast<Match>().ToDictionary(x => x.Groups[1].Value, x => x.Groups[3].Value);
return parameters;
}
public override bool LoadInstalledGames()
{
try
{
if (!_isOriginInstalled)
{
// Origin isn't installed, so we return an empty list.
logger.Info($"OriginLibrary/LoadInstalledGames: Origin library is not installed");
return false;
}
var localContentPath = Path.Combine(_originLocalContent, "LocalContent");
//var games = new Dictionary<string, GameInfo>();
if (Directory.Exists(localContentPath))
{
string[] packages = Directory.GetFiles(localContentPath, "*.mfst", SearchOption.AllDirectories);
foreach (string package in packages)
{
try
{
GameAppInfo originGame = new GameAppInfo();
originGame.GameID = Path.GetFileNameWithoutExtension(package);
if (!originGame.GameID.StartsWith("Origin"))
{
// If the gameId doesn't start with origin, then we need to find it!
// Get game id by fixing file via adding : before integer part of the name
// for example OFB-EAST52017 converts to OFB-EAST:52017
Match match = Regex.Match(originGame.GameID, @"^(.*?)(\d+)$");
if (!match.Success)
{
logger.Warn("Failed to get game id from file " + package);
continue;
}
originGame.GameID = match.Groups[1].Value + ":" + match.Groups[2].Value;
}
// Now we get the rest of the game information out of the manifest file
Dictionary<string, string> manifestInfo = ParseOriginManifest(package);
if (manifestInfo.ContainsKey("ddinitialdownload") && manifestInfo["ddinitialdownload"] == "1")
{
// Origin is downloading and installing the game so we skip it
continue;
}
if (manifestInfo.ContainsKey("downloading") && manifestInfo["downloading"] == "1")
{
// Origin is downloading some new content so we can't play it at the moment
// but we can still configure it
continue;
}
originGame.GameInstallDir = null;
if (manifestInfo.ContainsKey("dipinstallpath"))
{
// This is where Origin has installed this game
originGame.GameInstallDir = HttpUtility.UrlDecode(manifestInfo["dipinstallpath"]);
if (!Directory.Exists(originGame.GameInstallDir))
{
logger.Debug($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} found but no valid directory found at {originGame.GameInstallDir}");
continue;
}
}
// Now we want to look in the dinstallpath location for the game info
// for the __Installer\installerdata.xml
string gameInstallerData = Path.Combine(originGame.GameInstallDir, @"__Installer", @"installerdata.xml");
if (File.Exists(gameInstallerData))
{
// Now we parse the XML
XDocument xdoc = XDocument.Load(gameInstallerData);
originGame.GameName = xdoc.XPathSelectElement("/DiPManifest/gameTitles/gameTitle[@locale='en_US']").Value;
string gameFilePath = xdoc.XPathSelectElement("/DiPManifest/runtime/launcher/filePath").Value;
// Check whether gameFilePath contains a registry key! Cause if it does we need to lookup the path there instead
if (gameFilePath.StartsWith("[HKEY_LOCAL_MACHINE"))
{
// The filePath contains a registry key lookup that we need to execute and replace
MatchCollection mc = Regex.Matches(gameFilePath, @"\[HKEY_LOCAL_MACHINE\\(.*)\](.*)");
string originGameInstallKeyNameAndValue = mc[0].Groups[1].ToString();
string originGameRestOfFile = mc[0].Groups[2].ToString();
if (originGameInstallKeyNameAndValue == null)
{
// then we have a problem and we need to continue and ignore this game
logger.Warn($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} has registry but we can't match it! gameFilePath is {gameFilePath}.");
continue;
}
mc = Regex.Matches(originGameInstallKeyNameAndValue, @"(.*)\\([^\\]*)");
string originGameInstallKeyName = mc[0].Groups[1].ToString();
string originGameInstallKeyValue = mc[0].Groups[2].ToString();
try
{
RegistryKey originGameInstallKey = Registry.LocalMachine.OpenSubKey(originGameInstallKeyName, RegistryKeyPermissionCheck.ReadSubTree);
if (originGameInstallKey == null)
{
// then we have a problem as we cannot find the game exe location!
logger.Warn($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} has a install reg key we cannot find! originGameInstallKey is {gameFilePath} and originGameInstallKeyValue is {originGameInstallKeyValue}.");
continue;
}
string originGameInstallLocation = originGameInstallKey.GetValue(originGameInstallKeyValue).ToString();
originGameInstallLocation = Path.Combine(originGameInstallLocation, originGameRestOfFile);
if (!File.Exists(originGameInstallLocation))
{
// then we have a problem as we cannot locate the game exe file to start!
logger.Warn($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} has gameexe we cannot find! originGameInstallLocation is {originGameInstallLocation}.");
continue;
}
originGame.GameExePath = originGameInstallLocation;
}
catch (SecurityException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The user does not have the permissions required to read the Origin Game location registry key {}.");
}
catch (ObjectDisposedException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The Microsoft.Win32.RegistryKey is closed when trying to access the Origin ClientPath registry key (closed keys cannot be accessed).");
}
catch (IOException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The Origin ClientPath registry key has been marked for deletion so we cannot access the value dueing the OriginLibrary check.");
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The user does not have the necessary registry rights to check whether Origin is installed.");
}
}
else if (gameFilePath.StartsWith("[HKEY_CURRENT_USER"))
{
// The filePath contains a registry key lookup that we need to execute and replace
MatchCollection mc = Regex.Matches(gameFilePath, @"\[HKEY_CURRENT_USER\\(.*)\](.*)");
string originGameInstallKeyNameAndValue = mc[0].Groups[1].ToString();
string originGameRestOfFile = mc[0].Groups[2].ToString();
if (originGameInstallKeyNameAndValue == null)
{
// then we have a problem and we need to continue and ignore this game
logger.Warn($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} has registry but we can't match it! gameFilePath is {gameFilePath}.");
continue;
}
mc = Regex.Matches(originGameInstallKeyNameAndValue, @"(.*)\\([^\\]*)");
string originGameInstallKeyName = mc[0].Groups[1].ToString();
string originGameInstallKeyValue = mc[0].Groups[2].ToString();
try
{
RegistryKey originGameInstallKey = Registry.LocalMachine.OpenSubKey(originGameInstallKeyName, RegistryKeyPermissionCheck.ReadSubTree);
if (originGameInstallKey == null)
{
// then we have a problem as we cannot find the game exe location!
logger.Warn($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} has a install reg key we cannot find! originGameInstallKey is {gameFilePath} and originGameInstallKeyValue is {originGameInstallKeyValue}.");
continue;
}
string originGameInstallLocation = originGameInstallKey.GetValue(originGameInstallKeyValue).ToString();
originGameInstallLocation = Path.Combine(originGameInstallLocation, originGameRestOfFile);
if (!File.Exists(originGameInstallLocation))
{
// then we have a problem as we cannot locate the game exe file to start!
logger.Warn($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} has gameexe we cannot find! originGameInstallLocation is {originGameInstallLocation}.");
continue;
}
originGame.GameExePath = originGameInstallLocation;
}
catch (SecurityException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The user does not have the permissions required to read the Origin Game location registry key {}.");
}
catch (ObjectDisposedException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The Microsoft.Win32.RegistryKey is closed when trying to access the Origin ClientPath registry key (closed keys cannot be accessed).");
}
catch (IOException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The Origin ClientPath registry key has been marked for deletion so we cannot access the value dueing the OriginLibrary check.");
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "OriginLibrary/LoadInstalledGames: The user does not have the necessary registry rights to check whether Origin is installed.");
}
}
if (!File.Exists(originGame.GameExePath))
{
logger.Debug($"OriginLibrary/LoadInstalledGames: Origin game with ID {originGame.GameID} found but no game exe found at {originGame.GameExePath}");
continue;
}
// TODO check for icon! For now we will just use the exe one
originGame.GameIconPath = originGame.GameExePath;
// If we reach here we add the Game to the list of games we have!
_allOriginGames.Add(new OriginGame(originGame.GameID, originGame.GameName, originGame.GameExePath, originGame.GameIconPath));
}
else
{
// If we can't find the __Installer\installerdata.xml file then we ignore this game
continue;
}
}
catch (Exception ex)
{
logger.Error(ex, $"OriginLibrary/LoadInstalledGames: Failed to import installed Origin game {package}.");
}
}
}
else
{
logger.Warn($"OriginLibrary/LoadInstalledGames: No Origin games installed in the Origin library");
return false;
}
// up to here
/* if (gotGameRegistryKey)
{
// Now we need to lookup the game install path in registry using the game reg we got above
// We assume its 64-bit OS too (not 32bit)
using (RegistryKey OriginGameInstallKey = Registry.LocalMachine.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree))
{
// If the key doesn't exist we skip it as the game isn't installed any longer!
if (OriginGameInstallKey == null)
{
logger.Trace($"OriginLibrary/LoadInstalledGames: Skipping Origin Game {OriginGameAppInfo.GameName} as it isn't installed at the moment (it was uninstalled at some point)");
continue;
}
// If we get here, then we have a real game.
foreach (string regKeyName in OriginGameInstallKey.GetValueNames())
{
logger.Trace($"OriginLibrary/LoadInstalledGames: OriginGameInstallKey[{regKeyName}] = {OriginGameInstallKey.GetValue(regKeyName)}");
}
// From that we lookup the actual game path
string gameInstallDir = OriginGameInstallKey.GetValue("InstallDir", "").ToString();
logger.Trace($"OriginLibrary/LoadInstalledGames: gameInstallDir found = {gameInstallDir}");
if (!String.IsNullOrWhiteSpace(gameInstallDir))
{
OriginGameAppInfo.GameInstallDir = Path.GetFullPath(gameInstallDir).TrimEnd('\\');
logger.Trace($"OriginLibrary/LoadInstalledGames: OriginGameAppInfo.GameInstallDir = {OriginGameAppInfo.GameInstallDir }");
OriginGameAppInfo.GameExe = Path.Combine(OriginGameAppInfo.GameInstallDir, gameFileName);
logger.Trace($"OriginLibrary/LoadInstalledGames: OriginGameAppInfo.GameExe = {OriginGameAppInfo.GameExePath }");
OriginGameAppInfo.GameID = gameId;
logger.Trace($"OriginLibrary/LoadInstalledGames: OriginGameAppInfo.GameID = {OriginGameAppInfo.GameID }");
}
else
{
logger.Warn($"OriginLibrary/LoadInstalledGames: gameInstallDir is null or all whitespace!");
}
// Then we have the gameID, the thumbimage, the icon, the name, the exe path
// And we add the Game to the list of games we have!
_allOriginGames.Add(new OriginGame(OriginGameAppInfo.GameID, OriginGameAppInfo.GameName, OriginGameAppInfo.GameExePath, OriginGameAppInfo.GameOriginIconPath));
logger.Debug($"OriginLibrary/LoadInstalledGames: Adding Origin Game with game id {OriginGameAppInfo.GameID}, name {OriginGameAppInfo.GameName}, game exe {OriginGameAppInfo.GameExePath} and icon path {OriginGameAppInfo.GameOriginIconPath}");
}
}
}*/
logger.Info($"OriginLibrary/LoadInstalledGames: Found {_allOriginGames.Count} installed Origin games");
}
catch (ArgumentNullException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: An argument supplied to the function is null.");
}
catch (NotSupportedException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: The invoked method is not supported or reading, seeking or writing tp a stream that isn't supported.");
}
catch (PathTooLongException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: The path is longer than the maximum allowed by the operating system.");
}
catch (SecurityException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: The user does not have the permissions required to read the Origin InstallDir registry key.");
}
catch (ObjectDisposedException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: The Microsoft.Win32.RegistryKey is closed when trying to access the Origin InstallDir registry key (closed keys cannot be accessed).");
}
catch (IOException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: The Origin InstallDir registry key has been marked for deletion so we cannot access the value dueing the OriginLibrary check.");
}
catch (UnauthorizedAccessException ex)
{
logger.Warn(ex, "OriginLibrary/GetAllInstalledGames: The user does not have the necessary registry rights to check whether Origin is installed.");
}
return true;
}
#endregion
}
[global::System.Serializable]
public class OriginLibraryException : GameLibraryException
{
public OriginLibraryException() { }
public OriginLibraryException(string message) : base(message) { }
public OriginLibraryException(string message, Exception inner) : base(message, inner) { }
protected OriginLibraryException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}

View File

@ -13,13 +13,14 @@ namespace DisplayMagician.GameLibraries
public class SteamGame : Game
{
private string _gameRegistryKey;
private int _steamGameId;
private string _steamGameId;
private string _steamGameName;
private string _steamGameExePath;
private string _steamGameDir;
private string _steamGameExe;
private string _steamGameProcessName;
private string _steamGameIconPath;
private static readonly SteamLibrary _steamGameLibrary = SteamLibrary.GetLibrary();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static SteamGame()
@ -29,10 +30,10 @@ namespace DisplayMagician.GameLibraries
}
public SteamGame(int steamGameId, string steamGameName, string steamGameExePath, string steamGameIconPath)
public SteamGame(string steamGameId, string steamGameName, string steamGameExePath, string steamGameIconPath)
{
_gameRegistryKey = $@"{SteamLibrary.SteamAppsRegistryKey}\\{steamGameId}";
_gameRegistryKey = $@"{_steamGameLibrary.SteamAppsRegistryKey}\\{steamGameId}";
_steamGameId = steamGameId;
_steamGameName = steamGameName;
_steamGameExePath = steamGameExePath;
@ -43,7 +44,7 @@ namespace DisplayMagician.GameLibraries
}
public override int Id {
public override string Id {
get => _steamGameId;
set => _steamGameId = value;
}
@ -54,8 +55,8 @@ namespace DisplayMagician.GameLibraries
set => _steamGameName = value;
}
public override SupportedGameLibrary GameLibrary {
get => SupportedGameLibrary.Steam;
public override SupportedGameLibraryType GameLibrary {
get => SupportedGameLibraryType.Steam;
}
public override string IconPath {
@ -154,6 +155,21 @@ namespace DisplayMagician.GameLibraries
}
}
public override GameStartMode StartMode
{
get => GameStartMode.URI;
}
public override string GetStartURI(string gameArguments = "")
{
string address = $"steam://rungameid/{Id}";
if (String.IsNullOrWhiteSpace(gameArguments))
{
address += "/" + gameArguments;
}
return address;
}
public bool CopyInto(SteamGame steamGame)
{
if (!(steamGame is SteamGame))

View File

@ -11,33 +11,42 @@ using System.Diagnostics;
namespace DisplayMagician.GameLibraries
{
public static class SteamLibrary
public sealed class SteamLibrary : GameLibrary
{
#region Class Variables
// Common items to the class
private static List<Game> _allSteamGames = new List<Game>();
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\WOW6432Node\Valve\Steam"; // under LocalMachine
private static string _registryAppsKey = $@"SOFTWARE\Valve\Steam\Apps"; // under CurrentUser
private static bool _isSteamInstalled = false;
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
private struct SteamAppInfo
{
public int GameID;
public string GameID;
public string GameName;
public List<string> GameExes;
public string GameInstallDir;
public string GameSteamIconPath;
public string GameIconPath;
}
#region Class Variables
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static SteamLibrary _instance = new SteamLibrary();
// Common items to the class
private List<Game> _allSteamGames = new List<Game>();
private string steamAppIdRegex = @"/^[0-9A-F]{1,10}$";
private string _steamExe;
private string _steamPath;
private string _steamConfigVdfFile;
private List<string> _steamProcessList = new List<string>() { "steam"};
private string _registrySteamKey = @"SOFTWARE\WOW6432Node\Valve\Steam"; // under LocalMachine
private string _registryAppsKey = $@"SOFTWARE\Valve\Steam\Apps"; // under CurrentUser
private bool _isSteamInstalled = false;
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
#region Class Constructors
static SteamLibrary()
static SteamLibrary() { }
private SteamLibrary()
{
try
{
@ -80,7 +89,7 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Properties
public static List<Game> AllInstalledGames
public override List<Game> AllInstalledGames
{
get
{
@ -92,7 +101,7 @@ namespace DisplayMagician.GameLibraries
}
public static int InstalledSteamGameCount
public override int InstalledGameCount
{
get
{
@ -100,7 +109,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamRegistryKey
public string SteamRegistryKey
{
get
{
@ -108,7 +117,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamAppsRegistryKey
public string SteamAppsRegistryKey
{
get
{
@ -116,7 +125,23 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamExe
public override string GameLibraryName
{
get
{
return "Steam";
}
}
public override SupportedGameLibraryType GameLibraryType
{
get
{
return SupportedGameLibraryType.Steam;
}
}
public override string GameLibraryExe
{
get
{
@ -124,7 +149,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string SteamPath
public override string GameLibraryPath
{
get
{
@ -132,7 +157,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static bool IsSteamInstalled
public override bool IsGameLibraryInstalled
{
get
{
@ -141,23 +166,58 @@ namespace DisplayMagician.GameLibraries
}
public override bool IsRunning
{
get
{
List<Process> steamLibraryProcesses = new List<Process>();
foreach (string steamLibraryProcessName in _steamProcessList)
{
// Look for the processes with the ProcessName we sorted out earlier
steamLibraryProcesses.AddRange(Process.GetProcessesByName(steamLibraryProcessName));
}
// If we have found one or more processes then we should be good to go
// so let's break, and get to the next step....
if (steamLibraryProcesses.Count > 0)
return true;
else
return false;
}
}
public override List<string> GameLibraryProcesses
{
get
{
return _steamProcessList;
}
}
#endregion
#region Class Methods
public static bool AddSteamGame(SteamGame steamGame)
public static SteamLibrary GetLibrary()
{
return _instance;
}
public override bool AddGame(Game 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))
if (ContainsGame(steamGame))
{
logger.Debug($"SteamLibrary/AddSteamGame: Updating Steam game {steamGame.Name} in our Steam library");
// We update the existing Shortcut with the data over
SteamGame steamGameToUpdate = GetSteamGame(steamGame.Id.ToString());
steamGame.CopyInto(steamGameToUpdate);
SteamGame steamGameToUpdate = (SteamGame)GetGameById(steamGame.Id.ToString());
steamGame.CopyTo(steamGameToUpdate);
}
else
{
@ -167,7 +227,7 @@ namespace DisplayMagician.GameLibraries
}
//Doublecheck it's been added
if (ContainsSteamGame(steamGame))
if (ContainsGame(steamGame))
{
return true;
}
@ -176,7 +236,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveSteamGame(SteamGame steamGame)
public override bool RemoveGame(Game steamGame)
{
if (!(steamGame is SteamGame))
return false;
@ -200,9 +260,9 @@ namespace DisplayMagician.GameLibraries
throw new SteamLibraryException();
}
public static bool RemoveSteamGame(int steamGameId)
public override bool RemoveGameById(string steamGameId)
{
if (steamGameId<=0)
if (steamGameId.Equals("0"))
return false;
logger.Debug($"SteamLibrary/RemoveSteamGame2: Removing Steam game with ID {steamGameId} from the Steam library");
@ -225,28 +285,28 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveSteamGame(string steamGameNameOrUuid)
public override bool RemoveGame(string steamGameNameOrId)
{
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
if (String.IsNullOrWhiteSpace(steamGameNameOrId))
return false;
logger.Debug($"SteamLibrary/RemoveSteamGame3: Removing Steam game with Name or UUID {steamGameNameOrUuid} from the Steam library");
logger.Debug($"SteamLibrary/RemoveSteamGame3: Removing Steam game with Name or UUID {steamGameNameOrId} from the Steam library");
int numRemoved;
Match match = Regex.Match(steamGameNameOrUuid, steamAppIdRegex, RegexOptions.IgnoreCase);
Match match = Regex.Match(steamGameNameOrId, steamAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrUuid.Equals(Convert.ToUInt32(item.Id)));
numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrId.Equals(item.Id));
else
numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrUuid.Equals(item.Name));
numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrId.Equals(item.Name));
if (numRemoved == 1)
{
logger.Debug($"SteamLibrary/RemoveSteamGame3: Removed Steam game with Name or UUID {steamGameNameOrUuid} ");
logger.Debug($"SteamLibrary/RemoveSteamGame3: Removed Steam game with Name or UUID {steamGameNameOrId} ");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"SteamLibrary/RemoveSteamGame3: Didn't remove Steam game with Name or UUID {steamGameNameOrUuid} from the Steam Library");
logger.Debug($"SteamLibrary/RemoveSteamGame3: Didn't remove Steam game with Name or UUID {steamGameNameOrId} from the Steam Library");
return false;
}
else
@ -254,7 +314,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsSteamGame(SteamGame steamGame)
public override bool ContainsGame(Game steamGame)
{
if (!(steamGame is SteamGame))
return false;
@ -268,7 +328,7 @@ namespace DisplayMagician.GameLibraries
return false;
}
public static bool ContainsSteamGame(string steamGameNameOrUuid)
public override bool ContainsGame(string steamGameNameOrUuid)
{
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
return false;
@ -298,7 +358,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsSteamGame(int steamGameId)
public override bool ContainsGameById(string steamGameId)
{
foreach (SteamGame testSteamGame in _allSteamGames)
{
@ -312,7 +372,7 @@ namespace DisplayMagician.GameLibraries
}
public static SteamGame GetSteamGame(string steamGameNameOrUuid)
public override Game GetGame(string steamGameNameOrUuid)
{
if (String.IsNullOrWhiteSpace(steamGameNameOrUuid))
return null;
@ -341,7 +401,7 @@ namespace DisplayMagician.GameLibraries
}
public static SteamGame GetSteamGame(int steamGameId)
public override Game GetGameById(string steamGameId)
{
foreach (SteamGame testSteamGame in _allSteamGames)
{
@ -353,7 +413,7 @@ namespace DisplayMagician.GameLibraries
}
public static bool LoadInstalledGames()
public override bool LoadInstalledGames()
{
try
{
@ -368,7 +428,7 @@ namespace DisplayMagician.GameLibraries
logger.Trace($"SteamLibrary/LoadInstalledGames: Steam Base Registry Key = HKLM\\{_registrySteamKey}");
logger.Trace($"SteamLibrary/LoadInstalledGames: Steam Apps Registry Key = HKCU\\{_registryAppsKey}");
List<int> steamAppIdsInstalled = new List<int>();
List<string> steamAppIdsInstalled = new List<string>();
// Now look for what games app id's are actually installed on this computer
using (RegistryKey steamAppsKey = Registry.CurrentUser.OpenSubKey(_registryAppsKey, RegistryKeyPermissionCheck.ReadSubTree))
{
@ -376,13 +436,13 @@ namespace DisplayMagician.GameLibraries
{
//
// Loop through the subKeys as they are the Steam Game IDs
foreach (string steamGameKeyName in steamAppsKey.GetSubKeyNames())
foreach (string steamAppId in steamAppsKey.GetSubKeyNames())
{
logger.Trace($"SteamLibrary/LoadInstalledGames: Found SteamGameKeyName = {steamGameKeyName}");
if (int.TryParse(steamGameKeyName, out int steamAppId))
logger.Trace($"SteamLibrary/LoadInstalledGames: Found SteamGameKeyName = {steamAppId}");
if (!String.IsNullOrWhiteSpace(steamAppId))
{
logger.Trace($"SteamLibrary/LoadInstalledGames: SteamGameKeyName is an int, so trying to see if it is an installed app");
string steamGameKeyFullName = $"{_registryAppsKey}\\{steamGameKeyName}";
string steamGameKeyFullName = $"{_registryAppsKey}\\{steamAppId}";
using (RegistryKey steamGameKey = Registry.CurrentUser.OpenSubKey(steamGameKeyFullName, RegistryKeyPermissionCheck.ReadSubTree))
{
// If the Installed Value is set to 1, then the game is installed
@ -398,7 +458,7 @@ namespace DisplayMagician.GameLibraries
logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} does not contain an 'Installed' value so can't be a Steam App.");
}
}
}
}
}
@ -424,7 +484,7 @@ namespace DisplayMagician.GameLibraries
// - THe game installation dir
// - Sometimes the game icon
// - Sometimes the game executable name (from which we can get the icon)
Dictionary<int, SteamAppInfo> steamAppInfo = new Dictionary<int, SteamAppInfo>();
Dictionary<string, SteamAppInfo> steamAppInfo = new Dictionary<string, SteamAppInfo>();
string appInfoVdfFile = Path.Combine(_steamPath, "appcache", "appinfo.vdf");
var newAppInfo = new AppInfo();
@ -437,7 +497,7 @@ namespace DisplayMagician.GameLibraries
{
// We only care about the appIDs we have listed as actual games
// (The AppIds include all other DLC and Steam specific stuff too)
int detectedAppID = Convert.ToInt32(app.AppID);
string detectedAppID = app.AppID.ToString();
if (steamAppIdsInstalled.Contains(detectedAppID))
{
@ -468,7 +528,7 @@ namespace DisplayMagician.GameLibraries
else if (common.Name == "clienticon")
{
logger.Trace($"SteamLibrary/LoadInstalledGames: clienticon: App: {app.AppID} - Common {common.Name}: {common.Value}");
steamGameAppInfo.GameSteamIconPath = Path.Combine(_steamPath, @"steam", @"games", String.Concat(common.Value, @".ico"));
steamGameAppInfo.GameIconPath = Path.Combine(_steamPath, @"steam", @"games", String.Concat(common.Value, @".ico"));
}
else if (common.Name == "type")
{
@ -515,7 +575,7 @@ namespace DisplayMagician.GameLibraries
if (steamAppType.Equals("Game",StringComparison.OrdinalIgnoreCase))
{
steamAppInfo.Add(detectedAppID, steamGameAppInfo);
logger.Trace($"SteamLibrary/LoadInstalledGames: Adding Game with ID {detectedAppID} to the list of games");
logger.Trace($"SteamLibrary/LoadInstalledGames: Adding Game with ID {detectedAppID} '{steamGameAppInfo.GameName}' to the list of games");
}
}
@ -578,8 +638,9 @@ namespace DisplayMagician.GameLibraries
Match appidMatches = appidRegex.Match(steamLibraryAppManifestText);
if (appidMatches.Success)
{
if (int.TryParse(appidMatches.Groups[1].Value, out int steamGameId))
if (!String.IsNullOrWhiteSpace(appidMatches.Groups[1].Value))
{
string steamGameId = appidMatches.Groups[1].Value;
logger.Trace($"SteamLibrary/LoadInstalledGames: Found Steam Game ID {steamGameId} within {steamLibraryAppManifestFilename} steam app manifest within steam library {steamLibraryPath}");
// Check if this game is one that was installed
if (steamAppInfo.ContainsKey(steamGameId))
@ -593,32 +654,32 @@ namespace DisplayMagician.GameLibraries
// Construct the full path to the game dir from the appInfo and libraryAppManifest data
string steamGameInstallDir = Path.Combine(steamLibraryPath, @"steamapps", @"common", steamAppInfo[steamGameId].GameInstallDir);
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game ID {steamGameId} at {steamGameInstallDir }");
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game ID {steamGameId} at {steamGameInstallDir }");
// 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)
// 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)
{
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
// If the game executable exists, then we can proceed
if (File.Exists(steamGameExe))
foreach (string gameExe in steamAppInfo[steamGameId].GameExes)
{
logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
break;
steamGameExe = Path.Combine(steamGameInstallDir, gameExe);
logger.Trace($"SteamLibrary/LoadInstalledGames: Looking for Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
// If the game executable exists, then we can proceed
if (File.Exists(steamGameExe))
{
logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Exe {steamGameExe} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
break;
}
}
}
}
// 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) && steamAppInfo[steamGameId].GameSteamIconPath.EndsWith(".ico"))
if (File.Exists(steamAppInfo[steamGameId].GameIconPath) && steamAppInfo[steamGameId].GameIconPath.EndsWith(".ico"))
{
steamGameIconPath = steamAppInfo[steamGameId].GameSteamIconPath;
steamGameIconPath = steamAppInfo[steamGameId].GameIconPath;
logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Icon Path {steamGameIconPath} for Steam Game ID {steamGameId} at {steamGameInstallDir }");
}
@ -683,7 +744,7 @@ namespace DisplayMagician.GameLibraries
}
[global::System.Serializable]
public class SteamLibraryException : Exception
public class SteamLibraryException : GameLibraryException
{
public SteamLibraryException() { }
public SteamLibraryException(string message) : base(message) { }

View File

@ -10,14 +10,15 @@ namespace DisplayMagician.GameLibraries
{
public class UplayGame : Game
{
private string _gameRegistryKey;
private int _uplayGameId;
//private string _gameRegistryKey;
private string _uplayGameId;
private string _uplayGameName;
private string _uplayGameExePath;
private string _uplayGameDir;
private string _uplayGameExe;
private string _uplayGameProcessName;
private string _uplayGameIconPath;
private static readonly UplayLibrary _uplayGameLibrary = UplayLibrary.GetLibrary();
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
static UplayGame()
@ -27,10 +28,10 @@ namespace DisplayMagician.GameLibraries
}
public UplayGame(int uplayGameId, string uplayGameName, string uplayGameExePath, string uplayGameIconPath)
public UplayGame(string uplayGameId, string uplayGameName, string uplayGameExePath, string uplayGameIconPath)
{
_gameRegistryKey = $@"{UplayLibrary.registryUplayInstallsKey}\\{uplayGameId}";
//_gameRegistryKey = $@"{UplayLibrary.registryUplayInstallsKey}\\{uplayGameId}";
_uplayGameId = uplayGameId;
_uplayGameName = uplayGameName;
_uplayGameExePath = uplayGameExePath;
@ -41,7 +42,7 @@ namespace DisplayMagician.GameLibraries
}
public override int Id
public override string Id
{
get => _uplayGameId;
set => _uplayGameId = value;
@ -53,9 +54,9 @@ namespace DisplayMagician.GameLibraries
set => _uplayGameName = value;
}
public override SupportedGameLibrary GameLibrary
public override SupportedGameLibraryType GameLibrary
{
get => SupportedGameLibrary.Uplay;
get => SupportedGameLibraryType.Uplay;
}
public override string IconPath
@ -154,6 +155,25 @@ namespace DisplayMagician.GameLibraries
}
}*/
public override GameStartMode StartMode
{
get => GameStartMode.URI;
}
public override string GetStartURI(string gameArguments = "")
{
string address = $"uplay://launch/{Id}";
if (String.IsNullOrWhiteSpace(gameArguments))
{
address += "/" + gameArguments;
}
else
{
address += "/0";
}
return address;
}
public bool CopyTo(UplayGame uplayGame)
{
if (!(uplayGame is UplayGame))

View File

@ -5,39 +5,42 @@ using System.Text.RegularExpressions;
using Microsoft.Win32;
using System.IO;
using System.Security;
using System.Diagnostics;
namespace DisplayMagician.GameLibraries
{
public static class UplayLibrary
public class UplayLibrary : GameLibrary
{
#region Class Variables
// Static members are 'eagerly initialized', that is,
// immediately when class is loaded for the first time.
// .NET guarantees thread safety for static initialization
private static readonly UplayLibrary _instance = new UplayLibrary();
// Common items to the class
private static List<Game> _allUplayGames = new List<Game>();
private static string uplayAppIdRegex = @"/^[0-9A-F]{1,10}$";
private static bool _isUplayInstalled = false;
private static string _uplayExe;
private static string _uplayPath;
//private static string _uplayConfigVdfFile;
internal static string registryUplayLauncherKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher";
internal static string registryUplayInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
internal static string registryUplayOpenCmdKey = @"SOFTWARE\Classes\uplay\Shell\Open\Command";
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private List<Game> _allGames = new List<Game>();
private string uplayAppIdRegex = @"/^[0-9A-F]{1,10}$";
private bool _isUplayInstalled = false;
private string _uplayExe;
private string _uplayPath;
private List<string> _uplayProcessList = new List<string>() { "UbisoftGameLauncher", "UbisoftGameLauncher64" };
//private string _uplayConfigVdfFile;
internal string registryUplayLauncherKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher";
internal string registryUplayInstallsKey = @"SOFTWARE\WOW6432Node\Ubisoft\Launcher\Installs";
internal string registryUplayOpenCmdKey = @"SOFTWARE\Classes\uplay\Shell\Open\Command";
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
// Other constants that are useful
#endregion
private struct UplayAppInfo
{
public int GameID;
public string GameName;
public string GameExe;
public string GameInstallDir;
public string GameUplayIconPath;
}
#region Class Constructors
static UplayLibrary()
static UplayLibrary() { }
private UplayLibrary()
{
try
{
@ -79,27 +82,43 @@ namespace DisplayMagician.GameLibraries
#endregion
#region Class Properties
public static List<Game> AllInstalledGames
public override List<Game> AllInstalledGames
{
get
{
// Load the Uplay Games from Uplay Client if needed
if (_allUplayGames.Count == 0)
if (_allGames.Count == 0)
LoadInstalledGames();
return _allUplayGames;
return _allGames;
}
}
public static int InstalledUplayGameCount
public override int InstalledGameCount
{
get
{
return _allUplayGames.Count;
return _allGames.Count;
}
}
public static string UplayExe
public override string GameLibraryName
{
get
{
return "Uplay";
}
}
public override SupportedGameLibraryType GameLibraryType
{
get
{
return SupportedGameLibraryType.Uplay;
}
}
public override string GameLibraryExe
{
get
{
@ -107,7 +126,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static string UplayPath
public override string GameLibraryPath
{
get
{
@ -115,7 +134,7 @@ namespace DisplayMagician.GameLibraries
}
}
public static bool IsUplayInstalled
public override bool IsGameLibraryInstalled
{
get
{
@ -124,33 +143,68 @@ namespace DisplayMagician.GameLibraries
}
public override bool IsRunning
{
get
{
List<Process> uplayLibraryProcesses = new List<Process>();
foreach (string uplayLibraryProcessName in _uplayProcessList)
{
// Look for the processes with the ProcessName we sorted out earlier
uplayLibraryProcesses.AddRange(Process.GetProcessesByName(uplayLibraryProcessName));
}
// If we have found one or more processes then we should be good to go
// so let's break, and get to the next step....
if (uplayLibraryProcesses.Count > 0)
return true;
else
return false;
}
}
public override List<string> GameLibraryProcesses
{
get
{
return _uplayProcessList;
}
}
#endregion
#region Class Methods
public static bool AddUplayGame(UplayGame uplayGame)
public static UplayLibrary GetLibrary()
{
return _instance;
}
public override bool AddGame(Game uplayGame)
{
if (!(uplayGame is UplayGame))
return false;
// Doublecheck if it already exists
// Because then we just update the one that already exists
if (ContainsUplayGame(uplayGame))
if (ContainsGame(uplayGame))
{
logger.Debug($"UplayLibrary/AddUplayGame: Updating Uplay game {uplayGame.Name} in our Uplay library");
logger.Debug($"UplayLibrary/AddGame: Updating Uplay game {uplayGame.Name} in our Uplay library");
// We update the existing Shortcut with the data over
UplayGame uplayGameToUpdate = GetUplayGame(uplayGame.Id.ToString());
UplayGame uplayGameToUpdate = (UplayGame)GetGame(uplayGame.Id.ToString());
uplayGame.CopyTo(uplayGameToUpdate);
}
else
{
logger.Debug($"UplayLibrary/AddUplayGame: Adding Uplay game {uplayGame.Name} to our Uplay library");
logger.Debug($"UplayLibrary/AddGame: Adding Uplay game {uplayGame.Name} to our Uplay library");
// Add the uplayGame to the list of uplayGames
_allUplayGames.Add(uplayGame);
_allGames.Add(uplayGame);
}
//Doublecheck it's been added
if (ContainsUplayGame(uplayGame))
if (ContainsGame(uplayGame))
{
return true;
}
@ -159,76 +213,76 @@ namespace DisplayMagician.GameLibraries
}
public static bool RemoveUplayGame(UplayGame uplayGame)
public override bool RemoveGame(Game uplayGame)
{
if (!(uplayGame is UplayGame))
if (!(uplayGame is Game))
return false;
logger.Debug($"UplayLibrary/RemoveUplayGame: Removing Uplay game {uplayGame.Name} from our Uplay library");
logger.Debug($"UplayLibrary/RemoveGame: Removing Uplay game {uplayGame.Name} from our Uplay library");
// Remove the uplayGame from the list.
int numRemoved = _allUplayGames.RemoveAll(item => item.Id.Equals(uplayGame.Id));
int numRemoved = _allGames.RemoveAll(item => item.Id.Equals(uplayGame.Id));
if (numRemoved == 1)
{
logger.Debug($"UplayLibrary/RemoveUplayGame: Removed Uplay game with name {uplayGame.Name}");
logger.Debug($"UplayLibrary/RemoveGame: Removed Uplay game with name {uplayGame.Name}");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"UplayLibrary/RemoveUplayGame: Didn't remove Uplay game with ID {uplayGame.Name} from the Uplay Library");
logger.Debug($"UplayLibrary/RemoveGame: Didn't remove Uplay game with ID {uplayGame.Name} from the Uplay Library");
return false;
}
else
throw new UplayLibraryException();
}
public static bool RemoveUplayGame(int uplayGameId)
public override bool RemoveGameById(string uplayGameId)
{
if (uplayGameId<=0)
if (uplayGameId.Equals(0))
return false;
logger.Debug($"UplayLibrary/RemoveUplayGame2: Removing Uplay game with ID {uplayGameId} from the Uplay library");
logger.Debug($"UplayLibrary/RemoveGame2: Removing Uplay game with ID {uplayGameId} from the Uplay library");
// Remove the uplayGame from the list.
int numRemoved = _allUplayGames.RemoveAll(item => item.Id.Equals(uplayGameId));
int numRemoved = _allGames.RemoveAll(item => item.Id.Equals(uplayGameId));
if (numRemoved == 1)
{
logger.Debug($"UplayLibrary/RemoveUplayGame2: Removed Uplay game with ID {uplayGameId}");
logger.Debug($"UplayLibrary/RemoveGame2: Removed Uplay game with ID {uplayGameId}");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"UplayLibrary/RemoveUplayGame2: Didn't remove Uplay game with ID {uplayGameId} from the Uplay Library");
logger.Debug($"UplayLibrary/RemoveGame2: Didn't remove Uplay game with ID {uplayGameId} from the Uplay Library");
return false;
}
else
throw new UplayLibraryException();
}
public static bool RemoveUplayGame(string uplayGameNameOrUuid)
public override bool RemoveGame(string uplayGameNameOrId)
{
if (String.IsNullOrWhiteSpace(uplayGameNameOrUuid))
if (String.IsNullOrWhiteSpace(uplayGameNameOrId))
return false;
logger.Debug($"UplayLibrary/RemoveUplayGame3: Removing Uplay game with Name or UUID {uplayGameNameOrUuid} from the Uplay library");
logger.Debug($"UplayLibrary/RemoveGame3: Removing Uplay game with Name or ID {uplayGameNameOrId} from the Uplay library");
int numRemoved;
Match match = Regex.Match(uplayGameNameOrUuid, uplayAppIdRegex, RegexOptions.IgnoreCase);
Match match = Regex.Match(uplayGameNameOrId, uplayAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
numRemoved = _allUplayGames.RemoveAll(item => uplayGameNameOrUuid.Equals(Convert.ToUInt32(item.Id)));
numRemoved = _allGames.RemoveAll(item => uplayGameNameOrId.Equals(item.Id));
else
numRemoved = _allUplayGames.RemoveAll(item => uplayGameNameOrUuid.Equals(item.Name));
numRemoved = _allGames.RemoveAll(item => uplayGameNameOrId.Equals(item.Name));
if (numRemoved == 1)
{
logger.Debug($"UplayLibrary/RemoveUplayGame3: Removed Uplay game with Name or UUID {uplayGameNameOrUuid} ");
logger.Debug($"UplayLibrary/RemoveGame3: Removed Uplay game with Name or UUID {uplayGameNameOrId} ");
return true;
}
else if (numRemoved == 0)
{
logger.Debug($"UplayLibrary/RemoveUplayGame3: Didn't remove Uplay game with Name or UUID {uplayGameNameOrUuid} from the Uplay Library");
logger.Debug($"UplayLibrary/RemoveGame3: Didn't remove Uplay game with Name or UUID {uplayGameNameOrId} from the Uplay Library");
return false;
}
else
@ -236,25 +290,25 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsUplayGame(UplayGame uplayGame)
public override bool ContainsGame(Game uplayGame)
{
if (!(uplayGame is UplayGame))
return false;
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (testUplayGame.Id.Equals(uplayGame.Id))
if (testGame.Id.Equals(uplayGame.Id))
return true;
}
return false;
}
public static bool ContainsUplayGame(int uplayGameId)
public override bool ContainsGameById(string uplayGameId)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameId == testUplayGame.Id)
if (uplayGameId == testGame.Id)
return true;
}
@ -263,27 +317,27 @@ namespace DisplayMagician.GameLibraries
}
public static bool ContainsUplayGame(string uplayGameNameOrUuid)
public override bool ContainsGame(string uplayGameNameOrId)
{
if (String.IsNullOrWhiteSpace(uplayGameNameOrUuid))
if (String.IsNullOrWhiteSpace(uplayGameNameOrId))
return false;
Match match = Regex.Match(uplayGameNameOrUuid, uplayAppIdRegex, RegexOptions.IgnoreCase);
Match match = Regex.Match(uplayGameNameOrId, uplayAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrUuid.Equals(Convert.ToInt32(testUplayGame.Id)))
if (uplayGameNameOrId.Equals(Convert.ToInt32(testGame.Id)))
return true;
}
}
else
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrUuid.Equals(testUplayGame.Name))
if (uplayGameNameOrId.Equals(testGame.Name))
return true;
}
@ -294,27 +348,27 @@ namespace DisplayMagician.GameLibraries
}
public static UplayGame GetUplayGame(string uplayGameNameOrUuid)
public override Game GetGame(string uplayGameNameOrId)
{
if (String.IsNullOrWhiteSpace(uplayGameNameOrUuid))
if (String.IsNullOrWhiteSpace(uplayGameNameOrId))
return null;
Match match = Regex.Match(uplayGameNameOrUuid, uplayAppIdRegex, RegexOptions.IgnoreCase);
Match match = Regex.Match(uplayGameNameOrId, uplayAppIdRegex, RegexOptions.IgnoreCase);
if (match.Success)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrUuid.Equals(Convert.ToInt32(testUplayGame.Id)))
return testUplayGame;
if (uplayGameNameOrId.Equals(Convert.ToInt32(testGame.Id)))
return testGame;
}
}
else
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameNameOrUuid.Equals(testUplayGame.Name))
return testUplayGame;
if (uplayGameNameOrId.Equals(testGame.Name))
return testGame;
}
}
@ -323,19 +377,19 @@ namespace DisplayMagician.GameLibraries
}
public static UplayGame GetUplayGame(int uplayGameId)
public override Game GetGameById(string uplayGameId)
{
foreach (UplayGame testUplayGame in _allUplayGames)
foreach (UplayGame testGame in _allGames)
{
if (uplayGameId == testUplayGame.Id)
return testUplayGame;
if (uplayGameId == testGame.Id)
return testGame;
}
return null;
}
public static bool LoadInstalledGames()
public override bool LoadInstalledGames()
{
try
{
@ -462,7 +516,7 @@ namespace DisplayMagician.GameLibraries
}
// for each game record grab:
UplayAppInfo uplayGameAppInfo = new UplayAppInfo();
GameAppInfo uplayGameAppInfo = new GameAppInfo();
// find the exe name looking at root: -> start_game: -> online: -> executables: -> path: -> relative: (get ACU.exe)
// Lookup the Game registry key from looking at root: -> start_game: -> online: -> executables: -> working_directory: -> register: (get HKEY_LOCAL_MACHINE\SOFTWARE\Ubisoft\Launcher\Installs\720\InstallDir)
@ -485,7 +539,7 @@ namespace DisplayMagician.GameLibraries
// Stop this loop once we have both filname and gameid
if (gotGameFileName && gotGameId && gotGameIconPath && gotGameName && gotGameRegistryKey)
{
logger.Trace($"UplayLibrary/LoadInstalledGames: We got all the entries: gameFileName = {gameFileName } && gameId = {gameId } && gameIconPath = {uplayGameAppInfo.GameUplayIconPath} && gameName = {uplayGameAppInfo.GameName}");
logger.Trace($"UplayLibrary/LoadInstalledGames: We got all the entries: gameFileName = {gameFileName } && gameId = {gameId } && gameIconPath = {uplayGameAppInfo.GameIconPath} && gameName = {uplayGameAppInfo.GameName}");
break;
}
@ -516,8 +570,8 @@ namespace DisplayMagician.GameLibraries
string uplayGameIconPath = _uplayPath + @"data\games\" + iconImageFileName;
if (File.Exists(uplayGameIconPath) && uplayGameIconPath.EndsWith(".ico"))
{
uplayGameAppInfo.GameUplayIconPath = uplayGameIconPath;
logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameUplayIconPath = {uplayGameAppInfo.GameUplayIconPath }");
uplayGameAppInfo.GameIconPath = uplayGameIconPath;
logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameUplayIconPath = {uplayGameAppInfo.GameIconPath }");
}
gotGameIconPath = true;
}
@ -546,7 +600,7 @@ namespace DisplayMagician.GameLibraries
logger.Trace($"UplayLibrary/LoadInstalledGames: gameId = {gameId}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameFileName = {gameFileName}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameUplayIconPath}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameIconPath}");
logger.Trace($"UplayLibrary/LoadInstalledGames: gameRegistryKey = {gameRegistryKey}");
if (gotGameRegistryKey)
@ -575,9 +629,9 @@ namespace DisplayMagician.GameLibraries
{
uplayGameAppInfo.GameInstallDir = Path.GetFullPath(gameInstallDir).TrimEnd('\\');
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameInstallDir = {uplayGameAppInfo.GameInstallDir }");
uplayGameAppInfo.GameExe = Path.Combine(uplayGameAppInfo.GameInstallDir, gameFileName);
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameExe = {uplayGameAppInfo.GameExe }");
uplayGameAppInfo.GameID = int.Parse(gameId);
uplayGameAppInfo.GameExePath = Path.Combine(uplayGameAppInfo.GameInstallDir, gameFileName);
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameExe = {uplayGameAppInfo.GameExePath}");
uplayGameAppInfo.GameID = gameId;
logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameID = {uplayGameAppInfo.GameID }");
}
else
@ -587,14 +641,14 @@ namespace DisplayMagician.GameLibraries
// Then we have the gameID, the thumbimage, the icon, the name, the exe path
// And we add the Game to the list of games we have!
_allUplayGames.Add(new UplayGame(uplayGameAppInfo.GameID, uplayGameAppInfo.GameName, uplayGameAppInfo.GameExe, uplayGameAppInfo.GameUplayIconPath));
logger.Debug($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {uplayGameAppInfo.GameID}, name {uplayGameAppInfo.GameName}, game exe {uplayGameAppInfo.GameExe} and icon path {uplayGameAppInfo.GameUplayIconPath}");
_allGames.Add(new UplayGame(uplayGameAppInfo.GameID, uplayGameAppInfo.GameName, uplayGameAppInfo.GameExePath, uplayGameAppInfo.GameIconPath));
logger.Debug($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {uplayGameAppInfo.GameID}, name {uplayGameAppInfo.GameName}, game exe {uplayGameAppInfo.GameExePath} and icon path {uplayGameAppInfo.GameIconPath}");
}
}
}
logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allUplayGames.Count} installed Uplay games");
logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allGames.Count} installed Uplay games");
}

View File

@ -1,246 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
namespace DisplayMagician
{
public static class ProcessCommandLine
{
private static class Win32Native
{
public const uint PROCESS_BASIC_INFORMATION = 0;
[Flags]
public enum OpenProcessDesiredAccessFlags : uint
{
PROCESS_VM_READ = 0x0010,
PROCESS_QUERY_INFORMATION = 0x0400,
}
[StructLayout(LayoutKind.Sequential)]
public struct ProcessBasicInformation
{
public IntPtr Reserved1;
public IntPtr PebBaseAddress;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public IntPtr[] Reserved2;
public IntPtr UniqueProcessId;
public IntPtr Reserved3;
}
[StructLayout(LayoutKind.Sequential)]
public struct UnicodeString
{
public ushort Length;
public ushort MaximumLength;
public IntPtr Buffer;
}
// This is not the real struct!
// I faked it to get ProcessParameters address.
// Actual struct definition:
// https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb
[StructLayout(LayoutKind.Sequential)]
public struct PEB
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public IntPtr[] Reserved;
public IntPtr ProcessParameters;
}
[StructLayout(LayoutKind.Sequential)]
public struct RtlUserProcessParameters
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public byte[] Reserved1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
public IntPtr[] Reserved2;
public UnicodeString ImagePathName;
public UnicodeString CommandLine;
}
[DllImport("ntdll.dll")]
public static extern uint NtQueryInformationProcess(
IntPtr ProcessHandle,
uint ProcessInformationClass,
IntPtr ProcessInformation,
uint ProcessInformationLength,
out uint ReturnLength);
[DllImport("kernel32.dll")]
public static extern IntPtr OpenProcess(
OpenProcessDesiredAccessFlags dwDesiredAccess,
[MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
uint dwProcessId);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ReadProcessMemory(
IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer,
uint nSize, out uint lpNumberOfBytesRead);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("shell32.dll", SetLastError = true,
CharSet = CharSet.Unicode, EntryPoint = "CommandLineToArgvW")]
public static extern IntPtr CommandLineToArgv(string lpCmdLine, out int pNumArgs);
}
private static bool ReadStructFromProcessMemory<TStruct>(
IntPtr hProcess, IntPtr lpBaseAddress, out TStruct val)
{
val = default;
var structSize = Marshal.SizeOf<TStruct>();
var mem = Marshal.AllocHGlobal(structSize);
try
{
if (Win32Native.ReadProcessMemory(
hProcess, lpBaseAddress, mem, (uint)structSize, out var len) &&
(len == structSize))
{
val = Marshal.PtrToStructure<TStruct>(mem);
return true;
}
}
finally
{
Marshal.FreeHGlobal(mem);
}
return false;
}
public static string ErrorToString(int error) =>
new string[]
{
"Success",
"Failed to open process for reading",
"Failed to query process information",
"PEB address was null",
"Failed to read PEB information",
"Failed to read process parameters",
"Failed to read command line from process"
}[Math.Abs(error)];
public static int Retrieve(Process process, out string commandLine)
{
int rc = 0;
commandLine = null;
var hProcess = Win32Native.OpenProcess(
Win32Native.OpenProcessDesiredAccessFlags.PROCESS_QUERY_INFORMATION |
Win32Native.OpenProcessDesiredAccessFlags.PROCESS_VM_READ, false, (uint)process.Id);
if (hProcess != IntPtr.Zero)
{
try
{
var sizePBI = Marshal.SizeOf<Win32Native.ProcessBasicInformation>();
var memPBI = Marshal.AllocHGlobal(sizePBI);
try
{
var ret = Win32Native.NtQueryInformationProcess(
hProcess, Win32Native.PROCESS_BASIC_INFORMATION, memPBI,
(uint)sizePBI, out var len);
if (0 == ret)
{
var pbiInfo = Marshal.PtrToStructure<Win32Native.ProcessBasicInformation>(memPBI);
if (pbiInfo.PebBaseAddress != IntPtr.Zero)
{
if (ReadStructFromProcessMemory<Win32Native.PEB>(hProcess,
pbiInfo.PebBaseAddress, out var pebInfo))
{
if (ReadStructFromProcessMemory<Win32Native.RtlUserProcessParameters>(
hProcess, pebInfo.ProcessParameters, out var ruppInfo))
{
var clLen = ruppInfo.CommandLine.MaximumLength;
var memCL = Marshal.AllocHGlobal(clLen);
try
{
if (Win32Native.ReadProcessMemory(hProcess,
ruppInfo.CommandLine.Buffer, memCL, clLen, out len))
{
commandLine = Marshal.PtrToStringUni(memCL);
rc = 0;
}
else
{
// couldn't read command line buffer
rc = -6;
}
}
finally
{
Marshal.FreeHGlobal(memCL);
}
}
else
{
// couldn't read ProcessParameters
rc = -5;
}
}
else
{
// couldn't read PEB information
rc = -4;
}
}
else
{
// PebBaseAddress is null
rc = -3;
}
}
else
{
// NtQueryInformationProcess failed
rc = -2;
}
}
finally
{
Marshal.FreeHGlobal(memPBI);
}
}
finally
{
Win32Native.CloseHandle(hProcess);
}
}
else
{
// couldn't open process for VM read
rc = -1;
}
return rc;
}
public static IReadOnlyList<string> CommandLineToArgs(string commandLine)
{
if (string.IsNullOrEmpty(commandLine)) { return Array.Empty<string>(); }
var argv = Win32Native.CommandLineToArgv(commandLine, out var argc);
if (argv == IntPtr.Zero)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
try
{
var args = new string[argc];
for (var i = 0; i < args.Length; ++i)
{
var p = Marshal.ReadIntPtr(argv, i * IntPtr.Size);
args[i] = Marshal.PtrToStringUni(p);
}
return args.ToList().AsReadOnly();
}
finally
{
Marshal.FreeHGlobal(argv);
}
}
}
}

View File

@ -10,20 +10,15 @@ using DisplayMagician.InterProcess;
using DisplayMagician.Resources;
using DisplayMagicianShared;
using DisplayMagician.UIForms;
using DisplayMagician.GameLibraries;
using System.Text.RegularExpressions;
using System.Drawing;
using DesktopNotifications;
using System.Runtime.Serialization;
using NLog.Config;
using System.Collections.Generic;
namespace DisplayMagician {
public enum SupportedGameLibrary
{
Unknown,
Steam,
Uplay
}
public enum ApplyProfileResult
{
@ -714,17 +709,18 @@ namespace DisplayMagician {
Task loadSteamGamesTask = new Task(() =>
{
// Check if Steam is installed
if (GameLibraries.SteamLibrary.IsSteamInstalled)
GameLibrary steamLibrary = SteamLibrary.GetLibrary();
if (steamLibrary.IsGameLibraryInstalled)
{
// Load Steam library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Steam Games");
Console.Write("Loading Installed Steam Games...");
if (!DisplayMagician.GameLibraries.SteamLibrary.LoadInstalledGames())
if (!steamLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Steam Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Steam Games (found {GameLibraries.SteamLibrary.InstalledSteamGameCount})");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Steam Games (found {steamLibrary.InstalledGameCount})");
}
else
{
@ -737,17 +733,18 @@ namespace DisplayMagician {
Task loadUplayGamesTask = new Task(() =>
{
// Check if Uplay is installed
if (GameLibraries.UplayLibrary.IsUplayInstalled)
GameLibrary uplayLibrary = SteamLibrary.GetLibrary();
if (uplayLibrary.IsGameLibraryInstalled)
{
// Load Uplay library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Uplay Games");
Console.Write("Loading Installed Uplay Games...");
if (!DisplayMagician.GameLibraries.UplayLibrary.LoadInstalledGames())
if (!uplayLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Uplay Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Uplay Games (found {GameLibraries.UplayLibrary.InstalledUplayGameCount})");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Uplay Games (found {uplayLibrary.InstalledGameCount})");
}
else
{
@ -757,45 +754,131 @@ namespace DisplayMagician {
});
// Store all the tasks in an array so we can wait on them later
Task[] loadGamesTasks = new Task[2];
loadGamesTasks[0] = loadSteamGamesTask;
loadGamesTasks[1] = loadUplayGamesTask;
// Now lets prepare loading all the Origin games we have installed
Task loadOriginGamesTask = new Task(() =>
{
// Check if Origin is installed
GameLibrary originLibrary = SteamLibrary.GetLibrary();
if (originLibrary.IsGameLibraryInstalled)
{
// Load Origin library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Origin Games");
Console.Write("Loading Installed Origin Games...");
if (!originLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Origin Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Origin Games (found {originLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Origin not installed.");
Console.WriteLine("Origin not installed.");
}
logger.Debug($"Program/LoadGamesInBackground: Running game loading tasks.");
// Go through and start all the tasks
foreach (Task loadGameTask in loadGamesTasks)
loadGameTask.Start();
});
Action loadSteamGamesAction = new Action(() =>
{
// Check if Steam is installed
GameLibrary steamLibrary = SteamLibrary.GetLibrary();
if (steamLibrary.IsGameLibraryInstalled)
{
// Load Steam library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Steam Games");
Console.Write("Loading Installed Steam Games...");
if (!steamLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Steam Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Steam Games (found {steamLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Steam not installed.");
Console.WriteLine("Steam not installed.");
}
});
// Now lets prepare loading all the Uplay games we have installed
Action loadUplayGamesAction = new Action(() =>
{
// Check if Uplay is installed
GameLibrary uplayLibrary = UplayLibrary.GetLibrary();
if (uplayLibrary.IsGameLibraryInstalled)
{
// Load Uplay library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Uplay Games");
Console.Write("Loading Installed Uplay Games...");
if (!uplayLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Uplay Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Uplay Games (found {uplayLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Uplay not installed.");
Console.WriteLine("Uplay not installed.");
}
});
// Now lets prepare loading all the Origin games we have installed
Action loadOriginGamesAction = new Action(() =>
{
// Check if Origin is installed
GameLibrary originLibrary = OriginLibrary.GetLibrary();
if (originLibrary.IsGameLibraryInstalled)
{
// Load Origin library games
logger.Info($"Program/LoadGamesInBackground: Loading Installed Origin Games");
Console.Write("Loading Installed Origin Games...");
if (!originLibrary.LoadInstalledGames())
{
logger.Info($"Program/LoadGamesInBackground: Cannot load installed Origin Games!");
}
Console.WriteLine("Done.");
logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Origin Games (found {originLibrary.InstalledGameCount})");
}
else
{
logger.Info($"Program/LoadGamesInBackground: Origin not installed.");
Console.WriteLine("Origin not installed.");
}
});
// Store all the actions in a array so we can wait on them later
List<Action> loadGamesActions = new List<Action>();
loadGamesActions.Add(loadSteamGamesAction);
loadGamesActions.Add(loadUplayGamesAction);
loadGamesActions.Add(loadOriginGamesAction);
try
{
logger.Debug($"Program/LoadGamesInBackground: Waiting for all game loading tasks to finish");
Task.WaitAll(loadGamesTasks);
logger.Debug($"Program/LoadGamesInBackground: Running game loading actions.");
// Go through and start all the actions, making sure we only have one threat per action to avoid thread issues
int threads = loadGamesActions.Count;
ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = threads };
Parallel.Invoke(options, loadGamesActions.ToArray());
logger.Debug($"Program/LoadGamesInBackground: All game loading tasks finished");
}
catch (AggregateException ae)
{
logger.Error(ae, $"Program/LoadGamesInBackground exception during loadGamesTasks");
Console.WriteLine("Program/LoadGamesInBackground : Task exception!");
foreach (var e in ae.InnerExceptions)
{
// Handle the custom exception.
if (e is LoadingInstalledGamesException)
{
Console.WriteLine(e.Message);
}
// Rethrow any other exception.
else
{
throw;
}
}
logger.Error(ae, $"Program/LoadGamesInBackground exception during loadGamesActions");
}
bool failedTask = false;
foreach (var loadGameTask in loadGamesTasks)
// TODO replicate this failed Task handling in Actions
/*bool failedAction = false;
foreach (var loadGameAction in loadGamesActions)
{
if (loadGameTask.Exception != null)
if (loadGameAction. .Exception != null)
{
failedTask = true;
foreach (var ex in loadGameTask.Exception.InnerExceptions)
@ -804,7 +887,7 @@ namespace DisplayMagician {
}
if (failedTask)
return false;
return false;*/
return true;

View File

@ -37,8 +37,8 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.4.0")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyVersion("1.0.5.0")]
[assembly: AssemblyFileVersion("1.0.5.0")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: CLSCompliant(true)]

View File

@ -67,6 +67,8 @@ namespace DisplayMagician
public int StartTimeout;
public string GameArguments;
public bool GameArgumentsRequired;
public string DifferentGameExeToMonitor;
public bool MonitorDifferentGameExe;
}
public struct ShortcutError
@ -89,12 +91,14 @@ namespace DisplayMagician
private string _executableArguments;
private bool _executableArgumentsRequired = false;
private bool _processNameToMonitorUsesExecutable = true;
private int _gameAppId;
private string _gameAppId;
private string _gameName;
private SupportedGameLibrary _gameLibrary;
private SupportedGameLibraryType _gameLibrary;
private int _startTimeout = 20;
private string _gameArguments;
private bool _gameArgumentsRequired;
private string _differentGameExeToMonitor;
private bool _monitorDifferentGameExe = false;
private string _audioDevice;
private bool _changeAudioDevice;
private bool _setAudioVolume = false;
@ -126,9 +130,11 @@ namespace DisplayMagician
_uuid = Guid.NewGuid().ToString("D");
// If there are no GameLibraries then choose executable instead
if (!(UplayLibrary.IsUplayInstalled && SteamLibrary.IsSteamInstalled))
if (!(UplayLibrary.GetLibrary().IsGameLibraryInstalled &&
SteamLibrary.GetLibrary().IsGameLibraryInstalled &&
OriginLibrary.GetLibrary().IsGameLibraryInstalled))
{
_gameLibrary = SupportedGameLibrary.Unknown;
_gameLibrary = SupportedGameLibraryType.Unknown;
_gameName = "";
_gameArguments = "";
_category = ShortcutCategory.Application;
@ -278,12 +284,14 @@ namespace DisplayMagician
#pragma warning disable CS3001 // Argument type is not CLS-compliant
ProfileItem profile,
#pragma warning restore CS3001 // Argument type is not CLS-compliant
int gameAppId,
string gameAppId,
string gameName,
SupportedGameLibrary gameLibrary,
SupportedGameLibraryType gameLibrary,
int gameTimeout,
string gameArguments,
bool gameArgumentsRequired,
string differentGameExeToMonitor,
bool monitorDifferentGameExe,
ShortcutPermanence displayPermanence,
ShortcutPermanence audioPermanence,
ShortcutPermanence capturePermanence,
@ -312,6 +320,8 @@ namespace DisplayMagician
_startTimeout = gameTimeout;
_gameArguments = gameArguments;
_gameArgumentsRequired = gameArgumentsRequired;
_differentGameExeToMonitor = differentGameExeToMonitor;
_monitorDifferentGameExe = monitorDifferentGameExe;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
@ -377,6 +387,8 @@ namespace DisplayMagician
_startTimeout = game.StartTimeout;
_gameArguments = game.GameArguments;
_gameArgumentsRequired = game.GameArgumentsRequired;
_differentGameExeToMonitor = game.DifferentGameExeToMonitor;
_monitorDifferentGameExe = game.MonitorDifferentGameExe;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
@ -440,6 +452,8 @@ namespace DisplayMagician
_startTimeout = game.StartTimeout;
_gameArguments = game.GameArguments;
_gameArgumentsRequired = game.GameArgumentsRequired;
_differentGameExeToMonitor = game.DifferentGameExeToMonitor;
_monitorDifferentGameExe = game.MonitorDifferentGameExe;
_gameArgumentsRequired = false;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
@ -911,7 +925,7 @@ namespace DisplayMagician
}
}
public int GameAppId
public string GameAppId
{
get
{
@ -937,7 +951,7 @@ namespace DisplayMagician
}
}
public SupportedGameLibrary GameLibrary
public SupportedGameLibraryType GameLibrary
{
get
{
@ -989,6 +1003,33 @@ namespace DisplayMagician
}
}
public string DifferentGameExeToMonitor
{
get
{
return _differentGameExeToMonitor;
}
set
{
_differentGameExeToMonitor = value;
}
}
public bool MonitorDifferentGameExe
{
get
{
return _monitorDifferentGameExe;
}
set
{
_monitorDifferentGameExe = value;
}
}
public string AudioDevice
{
get
@ -1326,12 +1367,14 @@ namespace DisplayMagician
#pragma warning disable CS3001 // Argument type is not CLS-compliant
ProfileItem profile,
#pragma warning restore CS3001 // Argument type is not CLS-compliant
int gameAppId,
string gameAppId,
string gameName,
SupportedGameLibrary gameLibrary,
SupportedGameLibraryType gameLibrary,
int gameTimeout,
string gameArguments,
bool gameArgumentsRequired,
string differentGameExeToMonitor,
bool monitorDifferentGameExe,
ShortcutPermanence displayPermanence,
ShortcutPermanence audioPermanence,
ShortcutPermanence capturePermanence,
@ -1360,6 +1403,8 @@ namespace DisplayMagician
_startTimeout = gameTimeout;
_gameArguments = gameArguments;
_gameArgumentsRequired = gameArgumentsRequired;
_differentGameExeToMonitor = differentGameExeToMonitor;
_monitorDifferentGameExe = monitorDifferentGameExe;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
@ -1425,6 +1470,8 @@ namespace DisplayMagician
_startTimeout = game.StartTimeout;
_gameArguments = game.GameArguments;
_gameArgumentsRequired = game.GameArgumentsRequired;
_differentGameExeToMonitor = game.DifferentGameExeToMonitor;
_monitorDifferentGameExe = game.MonitorDifferentGameExe;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
@ -1489,7 +1536,8 @@ namespace DisplayMagician
_startTimeout = game.StartTimeout;
_gameArguments = game.GameArguments;
_gameArgumentsRequired = game.GameArgumentsRequired;
_gameArgumentsRequired = false;
_differentGameExeToMonitor = game.DifferentGameExeToMonitor;
_monitorDifferentGameExe = game.MonitorDifferentGameExe;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
@ -2014,12 +2062,13 @@ namespace DisplayMagician
else if (Category.Equals(ShortcutCategory.Game))
{
// If the game is a Steam Game we check for that
if (GameLibrary.Equals(SupportedGameLibrary.Steam))
if (GameLibrary.Equals(SupportedGameLibraryType.Steam))
{
SteamLibrary steamLibrary = SteamLibrary.GetLibrary();
// First check if Steam is installed
// Check if Steam is installed and error if it isn't
if (!SteamLibrary.IsSteamInstalled)
if (!steamLibrary.IsGameLibraryInstalled)
{
ShortcutError error = new ShortcutError();
error.Name = "SteamNotInstalled";
@ -2031,7 +2080,7 @@ namespace DisplayMagician
}
// We need to look up details about the game
if (!SteamLibrary.ContainsSteamGame(GameAppId))
if (!steamLibrary.ContainsGameById(GameAppId))
{
ShortcutError error = new ShortcutError();
error.Name = "SteamGameNotInstalled";
@ -2043,11 +2092,12 @@ namespace DisplayMagician
}
}
// If the game is a Uplay Game we check for that
else if (GameLibrary.Equals(SupportedGameLibrary.Uplay))
else if (GameLibrary.Equals(SupportedGameLibraryType.Uplay))
{
UplayLibrary uplayLibrary = UplayLibrary.GetLibrary();
// First check if Uplay is installed
// Check if Uplay is installed and error if it isn't
if (!UplayLibrary.IsUplayInstalled)
if (!uplayLibrary.IsGameLibraryInstalled)
{
ShortcutError error = new ShortcutError();
error.Name = "UplayNotInstalled";
@ -2059,7 +2109,7 @@ namespace DisplayMagician
}
// We need to look up details about the game
if (!UplayLibrary.ContainsUplayGame(GameAppId))
if (!uplayLibrary.ContainsGame(GameAppId))
{
ShortcutError error = new ShortcutError();
error.Name = "UplayGameNotInstalled";

View File

@ -586,8 +586,8 @@ namespace DisplayMagician
logger.Debug($"ShortcutRepository/RunShortcut: We're already on the {rollbackProfile.Name} profile so no need to change profiles.");
}
// Tell the IPC Service we are busy right now, and keep the previous status for later
InstanceStatus rollbackInstanceStatus = IPCService.GetInstance().Status;
IPCService.GetInstance().Status = InstanceStatus.Busy;
//InstanceStatus rollbackInstanceStatus = IPCService.GetInstance().Status;
//IPCService.GetInstance().Status = InstanceStatus.Busy;
// Only change profiles if we have to
if (needToChangeProfiles)
@ -769,7 +769,7 @@ namespace DisplayMagician
}
// Set the IP Service status back to what it was
IPCService.GetInstance().Status = rollbackInstanceStatus;
//IPCService.GetInstance().Status = rollbackInstanceStatus;
// Now run the pre-start applications
List<Process> startProgramsToStop = new List<Process>();
@ -963,12 +963,12 @@ namespace DisplayMagician
// make sure we have things to monitor and alert if not
if (processesToMonitor.Count == 0)
{
logger.Error($"No '{processNameToLookFor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout");
logger.Error($"ShortcutRepository/RunShortcut: No '{processNameToLookFor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout");
}
// Store the process to monitor for later
IPCService.GetInstance().HoldProcessId = processesToMonitor.FirstOrDefault()?.Id ?? 0;
IPCService.GetInstance().Status = InstanceStatus.OnHold;
//IPCService.GetInstance().HoldProcessId = processesToMonitor.FirstOrDefault()?.Id ?? 0;
//IPCService.GetInstance().Status = InstanceStatus.OnHold;
// Add a status notification icon in the status area
string notificationText = $"DisplayMagician: Running {shortcutToUse.ExecutableNameAndPath}...";
@ -1002,7 +1002,6 @@ namespace DisplayMagician
Thread.Sleep(2000);
// if we have things to monitor, then we should start to wait for them
Console.WriteLine($"Waiting for all {processNameToLookFor} windows to exit.");
logger.Debug($"ShortcutRepository/RunShortcut: Waiting for application {processNameToLookFor} to exit.");
if (processesToMonitor.Count > 0)
{
@ -1024,7 +1023,6 @@ namespace DisplayMagician
Thread.Sleep(1000);
}
}
Console.WriteLine($"{processNameToLookFor} has exited.");
logger.Debug($"ShortcutRepository/RunShortcut: Executable {processNameToLookFor} has exited.");
@ -1050,109 +1048,123 @@ namespace DisplayMagician
}
else if (shortcutToUse.Category.Equals(ShortcutCategory.Game))
{
Game gameToRun = null;
GameLibrary gameLibraryToUse = null;
// If the game is a Steam Game we check for that
if (shortcutToUse.GameLibrary.Equals(SupportedGameLibrary.Steam))
if (shortcutToUse.GameLibrary.Equals(SupportedGameLibraryType.Steam))
{
// We now need to get the SteamGame info
SteamGame steamGameToRun = SteamLibrary.GetSteamGame(shortcutToUse.GameAppId);
gameLibraryToUse = SteamLibrary.GetLibrary();
}
// If the game is a Uplay Uplay Game we check for that
else if (shortcutToUse.GameLibrary.Equals(SupportedGameLibraryType.Uplay))
{
// We now need to get the Uplay Game info
gameLibraryToUse = UplayLibrary.GetLibrary();
}
// If the game is a Uplay Game we check for that
else if (shortcutToUse.GameLibrary.Equals(SupportedGameLibraryType.Origin))
{
// We now need to get the Uplay Game info
gameLibraryToUse = UplayLibrary.GetLibrary();
}
logger.Info($"ShortcutRepository/RunShortcut: Starting the {steamGameToRun.Name} Steam Game, and then we're going to monitor it to wait for it to close.");
gameToRun = gameLibraryToUse.GetGameById(shortcutToUse.GameAppId);
logger.Info($"ShortcutRepository/RunShortcut: Starting the {gameToRun.Name} {gameLibraryToUse.GameLibraryName} Game, and then we're going to monitor it to wait for it to close.");
// If the GameAppID matches a Steam game, then lets run it
if (steamGameToRun is SteamGame)
// If the GameAppID is not null, then we've matched a game! Lets run it.
if (gameToRun != null)
{
// Now we want to tell the user we're start a game
// Construct the Windows toast content
ToastContentBuilder tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo($"notify=starting{gameLibraryToUse.GameLibraryName}", ToastActivationType.Foreground)
.AddText($"Starting {gameLibraryToUse.GameLibraryName}", hintMaxLines: 1)
.AddText($"Waiting for {gameLibraryToUse.GameLibraryName} Game Library to start (and update if needed)...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
ToastContent toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
var doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
var toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show this notification
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
Process gameProcess;
if (gameToRun.StartMode.Equals(Game.GameStartMode.URI))
{
// 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.Id}";
// Prepare to start the game using the URI method
string address = "";
if (shortcutToUse.GameArgumentsRequired)
{
address += "/" + shortcutToUse.GameArguments;
address = gameToRun.GetStartURI(shortcutToUse.GameArguments);
logger.Debug($"ShortcutRepository/RunShortcut: Shortcut has arguments: {shortcutToUse.GameArguments}");
}
logger.Debug($"ShortcutRepository/RunShortcut Steam launch address is {address}");
// Start the URI Handler to run Steam
Console.WriteLine($"Starting Steam Game: {steamGameToRun.Name}");
var steamProcess = Process.Start(address);
else
{
address = gameToRun.GetStartURI("");
logger.Debug($"ShortcutRepository/RunShortcut: Shortcut has no arguments");
}
logger.Debug($"ShortcutRepository/RunShortcut: Game launch URI is {address}");
gameProcess = Process.Start(address);
}
// Delay 500ms
// Delay 500ms
Thread.Sleep(500);
// Wait for GameLibrary to start
for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500)
{
// If we have found one or more processes then we should be good to go
// so let's break, and get to the next step....
if (gameLibraryToUse.IsRunning)
{
logger.Debug($"ShortcutRepository/RunShortcut: Found at least one GameLibrary process has started");
break;
}
// Let's wait a little while if we couldn't find
// any processes yet
Thread.Sleep(500);
// Wait for Steam game to update if needed
for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500)
{
}
if (!steamGameToRun.IsUpdating)
{
// Delay 500ms
Thread.Sleep(500);
// Delay 5secs
Thread.Sleep(5000);
logger.Debug($"ShortcutRepository/RunShortcut: Pausing to let the game library start the game.");
if (steamGameToRun.IsRunning)
{
logger.Info($"Found the '{steamGameToRun.Name}' process has started");
break;
}
}
// Delay 500ms
Thread.Sleep(500);
}
// Store the Steam Process ID for later
IPCService.GetInstance().HoldProcessId = steamProcess?.Id ?? 0;
IPCService.GetInstance().Status = InstanceStatus.OnHold;
// Store the Process ID for later
//IPCService.GetInstance().HoldProcessId = gameLibraryProcesses.FirstOrDefault()?.Id ?? 0;
//IPCService.GetInstance().Status = InstanceStatus.OnHold;
// At this point, if the user wants to actually monitor a different process,
// then we actually need to monitor that instead
if (shortcutToUse.MonitorDifferentGameExe)
{
// If we are monitoring a different executable rather than the game itself, then lets get that name ready instead
string altGameProcessToMonitor = System.IO.Path.GetFileNameWithoutExtension(shortcutToUse.DifferentGameExeToMonitor);
// Add a status notification icon in the status area
if (steamGameToRun.Name.Length <= 41)
notifyIcon.Text = $"DisplayMagician: Running {steamGameToRun.Name}...";
if (gameToRun.Name.Length <= 41)
notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name}...";
else
notifyIcon.Text = $"DisplayMagician: Running {steamGameToRun.Name.Substring(0, 41)}...";
notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name.Substring(0, 41)}...";
Application.DoEvents();
// Now we want to tell the user we're running a game!
// Construct the Windows toast content
ToastContentBuilder tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=runningSteamGame", ToastActivationType.Foreground)
.AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1)
.AddText($"Waiting for the Steam Game {shortcutToUse.GameName} to exit...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
ToastContent toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
var doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
var toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show this notification
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
// Wait 5 seconds for the game process to spawn
Thread.Sleep(5000);
// Wait for the game to exit
Console.WriteLine($"Waiting for {steamGameToRun.Name} to exit.");
logger.Debug($"ShortcutRepository/RunShortcut: Waiting for Steam Game {steamGameToRun.Name} to exit.");
while (true)
{
if (!steamGameToRun.IsRunning)
{
logger.Debug($"ShortcutRepository/RunShortcut: Steam Game {steamGameToRun.Name} is no longer running (IsRunning is false).");
break;
}
// Send a message to windows so that it doesn't think
// we're locked and try to kill us
System.Threading.Thread.CurrentThread.Join(0);
Thread.Sleep(1000);
}
Console.WriteLine($"{steamGameToRun.Name} has exited.");
logger.Debug($"ShortcutRepository/RunShortcut: Steam Game {steamGameToRun.Name} has exited.");
// Tell the user that the Steam Game has closed
// Construct the toast content
tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground)
.AddText($"{shortcutToUse.GameName} was closed", hintMaxLines: 1)
.AddText($"{shortcutToUse.GameName} game was shutdown and changes were reverted.");
.AddToastActivationInfo($"notify=running{gameLibraryToUse.GameLibraryName}Game", ToastActivationType.Foreground)
.AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1)
.AddText($"Waiting for the {altGameProcessToMonitor} alternative game process to exit...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
doc = new XmlDocument();
@ -1161,122 +1173,94 @@ namespace DisplayMagician
toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show it
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
}
}
// If the game is a Uplay Game we check for that
else if (shortcutToUse.GameLibrary.Equals(SupportedGameLibrary.Uplay))
{
// We now need to get the Uplay Game info
UplayGame uplayGameToRun = UplayLibrary.GetUplayGame(shortcutToUse.GameAppId);
logger.Info($"ShortcutRepository/RunShortcut: Starting the {uplayGameToRun.Name} Uplay Game, and then we're going to monitor it to wait for it to close.");
// If the GameAppID matches a Uplay game, then lets run it
if (uplayGameToRun is UplayGame)
{
// Prepare to start the Uplay game using the URI interface
// as used by Uplay for it's own desktop shortcuts.
var address = $"uplay://launch/{uplayGameToRun.Id}";
logger.Debug($"ShortcutRepository/RunShortcut: Uplay launch address is {address}");
if (shortcutToUse.GameArgumentsRequired)
{
address += "/" + shortcutToUse.GameArguments;
}
else
{
address += "/0";
}
// Now we want to tell the user we're starting upc.exe
// Construct the Windows toast content
ToastContentBuilder tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=startingUplay", ToastActivationType.Foreground)
.AddText($"Starting Uplay", hintMaxLines: 1)
.AddText($"Waiting for Uplay to start (and update if needed)...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
ToastContent toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
var doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
var toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show this notification
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
// Start the URI Handler to run Uplay
Console.WriteLine($"Starting Uplay Game: {uplayGameToRun.Name}");
logger.Info($"ShortcutRepository/RunShortcut: Starting Uplay Game: {uplayGameToRun.Name}");
Process uplayStartProcess = Process.Start(address);
// Wait for Uplay to start
List<Process> uplayProcesses = null;
// Now look for the thing we're supposed to monitor
// and wait until it starts up
List<Process> processesToMonitor = new List<Process>();
for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500)
{
// Look for the processes with the UplayGameLauncher name as those are the ones that launch the game
// Look for the 32 bit games processes
uplayProcesses = Process.GetProcessesByName("UbisoftGameLauncher").ToList();
// Look for the 64 bit games processes
uplayProcesses.AddRange(Process.GetProcessesByName("UbisoftGameLauncher64").ToList());
// Look for the processes with the ProcessName we sorted out earlier
processesToMonitor = Process.GetProcessesByName(altGameProcessToMonitor).ToList();
// If we have found one or more processes then we should be good to go
// so let's break
if (uplayProcesses.Count > 0)
if (processesToMonitor.Count > 0)
{
Thread.Sleep(500);
logger.Debug($"ShortcutRepository/RunShortcut: Found {uplayProcesses.Count} 'UplayGameLauncher' processes have started");
logger.Debug($"ShortcutRepository/RunShortcut: Found {processesToMonitor.Count} '{altGameProcessToMonitor}' processes to monitor");
break;
}
// Let's wait a little while if we couldn't find
// any processes yet
Thread.Sleep(500);
}
//logger.Debug($"ShortcutRepository/RunShortcut: Pausing for 5 seconds to let the Uplay process start the game, and update it if necessary.");
// Now we know the Uplay app is running then
// we wait until the Uplay game is running (*allows for uplay update)
for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500)
// make sure we have things to monitor and alert if not
if (processesToMonitor.Count == 0)
{
if (uplayGameToRun.IsRunning)
{
logger.Debug($"ShortcutRepository/RunShortcut: Found the '{uplayGameToRun.Name}' process has started");
break;
}
// Delay 500ms
Thread.Sleep(500);
logger.Error($"ShortcutRepository/RunShortcut: No Alternative Game Executable '{altGameProcessToMonitor}' processes found before waiting timeout. DisplayMagician was unable to find any processes before the {shortcutToUse.StartTimeout} second timeout");
}
// Store the Uplay Process ID for later
IPCService.GetInstance().HoldProcessId = uplayStartProcess?.Id ?? 0;
IPCService.GetInstance().Status = InstanceStatus.OnHold;
// if we have things to monitor, then we should start to wait for them
logger.Debug($"ShortcutRepository/RunShortcut: Waiting for alternative game proocess {altGameProcessToMonitor} to exit.");
if (processesToMonitor.Count > 0)
{
logger.Debug($"ShortcutRepository/RunShortcut: {processesToMonitor.Count} Alternative Game Executable '{altGameProcessToMonitor}' processes are still running");
while (true)
{
processesToMonitor = Process.GetProcessesByName(altGameProcessToMonitor).ToList();
// If we have no more processes left then we're done!
if (processesToMonitor.Count == 0)
{
logger.Debug($"ShortcutRepository/RunShortcut: No more '{altGameProcessToMonitor}' processes are still running");
break;
}
// Send a message to windows so that it doesn't think
// we're locked and try to kill us
System.Threading.Thread.CurrentThread.Join(0);
Thread.Sleep(1000);
}
}
logger.Debug($"ShortcutRepository/RunShortcut: Alternative Game Executable {altGameProcessToMonitor} has exited.");
// Tell the user that the Alt Game Executable has closed
// Construct the toast content
tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground)
.AddText($"{altGameProcessToMonitor} was closed", hintMaxLines: 1)
.AddText($"{altGameProcessToMonitor} alternative game executable was exited.");
toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
doc = new XmlDocument();
doc.LoadXml(toastContent.GetContent());
// And create the toast notification
toast = new ToastNotification(doc);
// Remove any other Notifications from us
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show it
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
}
else
{
// we are monitoring the game thats actually running (the most common scenario)
// Add a status notification icon in the status area
if (uplayGameToRun.Name.Length <= 41)
notifyIcon.Text = $"DisplayMagician: Running {uplayGameToRun.Name}...";
if (gameToRun.Name.Length <= 41)
notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name}...";
else
notifyIcon.Text = $"DisplayMagician: Running {uplayGameToRun.Name.Substring(0, 41)}...";
notifyIcon.Text = $"DisplayMagician: Running {gameToRun.Name.Substring(0, 41)}...";
Application.DoEvents();
// Now we want to tell the user we're running a game!
// Construct the Windows toast content
tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=runningUplayGame", ToastActivationType.Foreground)
.AddToastActivationInfo($"notify=running{gameLibraryToUse.GameLibraryName}Game", ToastActivationType.Foreground)
.AddText($"Running {shortcutToUse.GameName}", hintMaxLines: 1)
.AddText($"Waiting for the Uplay Game {shortcutToUse.GameName} to exit...");
.AddText($"Waiting for the {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} to exit...");
//.AddButton("Stop", ToastActivationType.Background, "notify=runningGame&action=stop");
toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
@ -1289,17 +1273,35 @@ namespace DisplayMagician
// And then show this notification
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
// Wait 5 seconds for the game process to spawn
Thread.Sleep(5000);
// Now we know the game library app is running then
// we wait until the game has started running (*allows for updates to occur)
for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500)
{
if (gameToRun.IsRunning)
{
// The game is running! So now we continue processing
logger.Debug($"ShortcutRepository/RunShortcut: Found the '{gameToRun.Name}' process has started");
break;
}
// Delay 500ms
Thread.Sleep(500);
}
// Wait 5 more seconds for the game process to spawn
// Thread.Sleep(5000);
// This is the main waiting thread!
// Wait for the game to exit
Console.WriteLine($"Waiting for {uplayGameToRun.Name} to exit.");
logger.Debug($"ShortcutRepository/RunShortcut: waiting for Uplay Game {uplayGameToRun.Name} to exit.");
logger.Debug($"ShortcutRepository/RunShortcut: waiting for {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} to exit.");
while (true)
{
if (!uplayGameToRun.IsRunning)
if (!gameToRun.IsRunning)
{
logger.Debug($"ShortcutRepository/RunShortcut: Uplay Game {uplayGameToRun.Name} is no longer running (IsRunning is false).");
logger.Debug($"ShortcutRepository/RunShortcut: {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} is no longer running (IsRunning is false).");
break;
}
@ -1308,15 +1310,15 @@ namespace DisplayMagician
System.Threading.Thread.CurrentThread.Join(0);
Thread.Sleep(1000);
}
Console.WriteLine($"{uplayGameToRun.Name} has exited.");
logger.Debug($"ShortcutRepository/RunShortcut: Uplay Game {uplayGameToRun.Name} has exited.");
Console.WriteLine($"{gameToRun.Name} has exited.");
logger.Debug($"ShortcutRepository/RunShortcut: {gameLibraryToUse.GameLibraryName} Game {gameToRun.Name} has exited.");
// Tell the user that the Uplay Game has closed
// Tell the user that the Game has closed
// Construct the toast content
tcBuilder = new ToastContentBuilder()
.AddToastActivationInfo("notify=stopDetected", ToastActivationType.Foreground)
.AddText($"{shortcutToUse.GameName} was closed", hintMaxLines: 1)
.AddText($"{shortcutToUse.GameName} game was shutdown and changes were reverted.");
.AddText($"{shortcutToUse.GameName} game was exited.");
toastContent = tcBuilder.Content;
// Make sure to use Windows.Data.Xml.Dom
doc = new XmlDocument();
@ -1327,12 +1329,18 @@ namespace DisplayMagician
DesktopNotifications.DesktopNotificationManagerCompat.History.Clear();
// And then show it
DesktopNotifications.DesktopNotificationManagerCompat.CreateToastNotifier().Show(toast);
}
}
else
{
logger.Error($"ShortcutRepository/RunShortcut: Error starting the {gameToRun.Name} {gameToRun.GameLibrary} Game as the game wasn't found.");
}
}
// Remove the status notification icon from the status area
// once we've exited the game, but only if its a game or app
logger.Debug($"ShortcutRepository/RunShortcut: Changing the system tray icon message back to what it was.");
@ -1429,7 +1437,7 @@ namespace DisplayMagician
// Change Audio Device back (if one specified)
if (activeAudioDevices.Count > 0)
{
if (needToChangeAudioDevice)
if (needToChangeAudioDevice && shortcutToUse.AudioPermanence == ShortcutPermanence.Temporary)
{
logger.Debug($"ShortcutRepository/RunShortcut: Reverting default audio back to {rollbackAudioDevice.Name} audio device");
// use the Audio Device
@ -1460,7 +1468,7 @@ namespace DisplayMagician
// Change Capture Device back (if one specified)
if (activeCaptureDevices.Count > 0)
{
if (needToChangeCaptureDevice)
if (needToChangeCaptureDevice && shortcutToUse.CapturePermanence == ShortcutPermanence.Temporary)
{
logger.Debug($"ShortcutRepository/RunShortcut: Reverting default capture (microphone) device back to {rollbackCaptureDevice.Name} capture device");
// use the Audio Device
@ -1489,7 +1497,8 @@ namespace DisplayMagician
}
// Change back to the original profile only if it is different
if (needToChangeProfiles)
// And if we're temporary
if (needToChangeProfiles && shortcutToUse.DisplayPermanence == ShortcutPermanence.Temporary)
{
logger.Debug($"ShortcutRepository/RunShortcut: Rolling back display profile to {rollbackProfile.Name}");
@ -1532,3 +1541,4 @@ namespace DisplayMagician
}
}

View File

@ -190,6 +190,7 @@
//
resources.ApplyResources(this.notifyIcon, "notifyIcon");
this.notifyIcon.ContextMenuStrip = this.mainContextMenuStrip;
this.notifyIcon.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.notifyIcon_MouseDoubleClick);
//
// mainContextMenuStrip
//

View File

@ -68,6 +68,14 @@ namespace DisplayMagician.UIForms
allowVisible = true;
// Really close the application when the form is closed
allowClose = true;
}
if (Program.AppProgramSettings.MinimiseOnStart && Program.AppProgramSettings.StartOnBootUp)
{
cb_minimise_notification_area.Checked = true;
}
else
{
cb_minimise_notification_area.Checked = false;
}
@ -320,6 +328,7 @@ namespace DisplayMagician.UIForms
allowClose = false;
// Enable the MinimiseOnStart setting
Program.AppProgramSettings.MinimiseOnStart = true;
Program.AppProgramSettings.StartOnBootUp = true;
// Change the exit_button text to say 'Close'
btn_exit.Text = "&Close";
}
@ -331,6 +340,7 @@ namespace DisplayMagician.UIForms
allowClose = true;
// Disable the MinimiseOnStart setting
Program.AppProgramSettings.MinimiseOnStart = false;
Program.AppProgramSettings.StartOnBootUp = false;
// Change the exit_button text to say 'Exit'
btn_exit.Text = "&Exit";
@ -475,5 +485,10 @@ namespace DisplayMagician.UIForms
string targetURL = @"https://github.com/sponsors/terrymacdonald";
System.Diagnostics.Process.Start(targetURL);
}
private void notifyIcon_MouseDoubleClick(object sender, MouseEventArgs e)
{
openApplicationWindow();
}
}
}

View File

@ -10837,7 +10837,7 @@
<value>NoControl</value>
</data>
<data name="lbl_create_shortcut.Location" type="System.Drawing.Point, System.Drawing">
<value>282, 245</value>
<value>282, 247</value>
</data>
<data name="lbl_create_shortcut.Size" type="System.Drawing.Size, System.Drawing">
<value>222, 22</value>
@ -10879,16 +10879,16 @@
<value>NoControl</value>
</data>
<data name="cb_minimise_notification_area.Location" type="System.Drawing.Point, System.Drawing">
<value>234, 353</value>
<value>162, 356</value>
</data>
<data name="cb_minimise_notification_area.Size" type="System.Drawing.Size, System.Drawing">
<value>332, 20</value>
<value>460, 20</value>
</data>
<data name="cb_minimise_notification_area.TabIndex" type="System.Int32, mscorlib">
<value>5</value>
</data>
<data name="cb_minimise_notification_area.Text" xml:space="preserve">
<value>Start DisplayMagician minimised in notification area</value>
<value>Start DisplayMagician minimised in notification area when computer starts</value>
</data>
<data name="&gt;&gt;cb_minimise_notification_area.Name" xml:space="preserve">
<value>cb_minimise_notification_area</value>
@ -10912,7 +10912,7 @@
<value>Microsoft Sans Serif, 9.75pt</value>
</data>
<data name="lbl_version.Location" type="System.Drawing.Point, System.Drawing">
<value>12, 354</value>
<value>12, 357</value>
</data>
<data name="lbl_version.Size" type="System.Drawing.Size, System.Drawing">
<value>25, 16</value>
@ -10948,7 +10948,7 @@
<value>Microsoft Sans Serif, 21.75pt</value>
</data>
<data name="btn_setup_game_shortcuts.Location" type="System.Drawing.Point, System.Drawing">
<value>212, 172</value>
<value>212, 174</value>
</data>
<data name="btn_setup_game_shortcuts.Size" type="System.Drawing.Size, System.Drawing">
<value>360, 50</value>
@ -10981,7 +10981,7 @@
<value>NoControl</value>
</data>
<data name="btn_exit.Location" type="System.Drawing.Point, System.Drawing">
<value>700, 350</value>
<value>700, 353</value>
</data>
<data name="btn_exit.Size" type="System.Drawing.Size, System.Drawing">
<value>75, 23</value>

View File

@ -44,6 +44,9 @@ namespace DisplayMagician.UIForms
this.ilv_saved_profiles = new Manina.Windows.Forms.ImageListView();
this.dv_profile = new DisplayMagicianShared.UserControls.DisplayView();
this.tabp_audio = new System.Windows.Forms.TabPage();
this.lbl_no_active_capture_devices = new System.Windows.Forms.Label();
this.lbl_no_active_audio_devices = new System.Windows.Forms.Label();
this.lbl_disabled_shortcut_audio_chipset = new System.Windows.Forms.Label();
this.gb_capture_settings = new System.Windows.Forms.GroupBox();
this.gb_capture_volume = new System.Windows.Forms.GroupBox();
this.rb_set_capture_volume = new System.Windows.Forms.RadioButton();
@ -118,6 +121,8 @@ namespace DisplayMagician.UIForms
this.rb_standalone = new System.Windows.Forms.RadioButton();
this.rb_no_game = new System.Windows.Forms.RadioButton();
this.p_game = new System.Windows.Forms.Panel();
this.btn_choose_alternative_game = new System.Windows.Forms.Button();
this.txt_alternative_game = new System.Windows.Forms.TextBox();
this.txt_game_launcher = new System.Windows.Forms.TextBox();
this.txt_game_name = new System.Windows.Forms.TextBox();
this.lbl_game_library = new System.Windows.Forms.Label();
@ -146,9 +151,7 @@ namespace DisplayMagician.UIForms
this.lbl_title = new System.Windows.Forms.Label();
this.lbl_shortcut_name = new System.Windows.Forms.Label();
this.cb_autosuggest = new System.Windows.Forms.CheckBox();
this.lbl_disabled_shortcut_audio_chipset = new System.Windows.Forms.Label();
this.lbl_no_active_audio_devices = new System.Windows.Forms.Label();
this.lbl_no_active_capture_devices = new System.Windows.Forms.Label();
this.cb_wait_alternative_game = new System.Windows.Forms.CheckBox();
this.tabc_shortcut.SuspendLayout();
this.tabp_display.SuspendLayout();
this.tabp_audio.SuspendLayout();
@ -336,6 +339,56 @@ namespace DisplayMagician.UIForms
this.tabp_audio.TabIndex = 4;
this.tabp_audio.Text = "2. Choose Audio";
//
// lbl_no_active_capture_devices
//
this.lbl_no_active_capture_devices.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.lbl_no_active_capture_devices.AutoSize = true;
this.lbl_no_active_capture_devices.BackColor = System.Drawing.Color.Brown;
this.lbl_no_active_capture_devices.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_no_active_capture_devices.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_no_active_capture_devices.ForeColor = System.Drawing.Color.White;
this.lbl_no_active_capture_devices.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.lbl_no_active_capture_devices.Location = new System.Drawing.Point(126, 433);
this.lbl_no_active_capture_devices.Name = "lbl_no_active_capture_devices";
this.lbl_no_active_capture_devices.Size = new System.Drawing.Size(831, 22);
this.lbl_no_active_capture_devices.TabIndex = 36;
this.lbl_no_active_capture_devices.Text = "No active microphone inputs found. Please connect or enable at least one micropho" +
"ne if you want to use this feature.";
this.lbl_no_active_capture_devices.Visible = false;
//
// lbl_no_active_audio_devices
//
this.lbl_no_active_audio_devices.Anchor = System.Windows.Forms.AnchorStyles.None;
this.lbl_no_active_audio_devices.AutoSize = true;
this.lbl_no_active_audio_devices.BackColor = System.Drawing.Color.Brown;
this.lbl_no_active_audio_devices.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_no_active_audio_devices.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_no_active_audio_devices.ForeColor = System.Drawing.Color.White;
this.lbl_no_active_audio_devices.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.lbl_no_active_audio_devices.Location = new System.Drawing.Point(131, 151);
this.lbl_no_active_audio_devices.Name = "lbl_no_active_audio_devices";
this.lbl_no_active_audio_devices.Size = new System.Drawing.Size(804, 22);
this.lbl_no_active_audio_devices.TabIndex = 35;
this.lbl_no_active_audio_devices.Text = "No active audio outputs found. Please connect or enable at least one audio output" +
" if you want to use this feature.";
this.lbl_no_active_audio_devices.Visible = false;
//
// lbl_disabled_shortcut_audio_chipset
//
this.lbl_disabled_shortcut_audio_chipset.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.lbl_disabled_shortcut_audio_chipset.AutoSize = true;
this.lbl_disabled_shortcut_audio_chipset.BackColor = System.Drawing.Color.Brown;
this.lbl_disabled_shortcut_audio_chipset.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_disabled_shortcut_audio_chipset.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_disabled_shortcut_audio_chipset.ForeColor = System.Drawing.Color.White;
this.lbl_disabled_shortcut_audio_chipset.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.lbl_disabled_shortcut_audio_chipset.Location = new System.Drawing.Point(326, 298);
this.lbl_disabled_shortcut_audio_chipset.Name = "lbl_disabled_shortcut_audio_chipset";
this.lbl_disabled_shortcut_audio_chipset.Size = new System.Drawing.Size(430, 22);
this.lbl_disabled_shortcut_audio_chipset.TabIndex = 34;
this.lbl_disabled_shortcut_audio_chipset.Text = "Unsupported Audio Chipset. Setting audio isn\'t supported :(";
this.lbl_disabled_shortcut_audio_chipset.Visible = false;
//
// gb_capture_settings
//
this.gb_capture_settings.Controls.Add(this.gb_capture_volume);
@ -1236,6 +1289,9 @@ namespace DisplayMagician.UIForms
//
// p_game
//
this.p_game.Controls.Add(this.cb_wait_alternative_game);
this.p_game.Controls.Add(this.btn_choose_alternative_game);
this.p_game.Controls.Add(this.txt_alternative_game);
this.p_game.Controls.Add(this.txt_game_launcher);
this.p_game.Controls.Add(this.txt_game_name);
this.p_game.Controls.Add(this.lbl_game_library);
@ -1252,6 +1308,27 @@ namespace DisplayMagician.UIForms
this.p_game.Size = new System.Drawing.Size(1006, 278);
this.p_game.TabIndex = 7;
//
// btn_choose_alternative_game
//
this.btn_choose_alternative_game.Enabled = false;
this.btn_choose_alternative_game.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.btn_choose_alternative_game.ForeColor = System.Drawing.Color.White;
this.btn_choose_alternative_game.Location = new System.Drawing.Point(878, 224);
this.btn_choose_alternative_game.Name = "btn_choose_alternative_game";
this.btn_choose_alternative_game.Size = new System.Drawing.Size(85, 27);
this.btn_choose_alternative_game.TabIndex = 26;
this.btn_choose_alternative_game.Text = "Choose";
this.btn_choose_alternative_game.UseVisualStyleBackColor = true;
this.btn_choose_alternative_game.Click += new System.EventHandler(this.btn_choose_alternative_game_Click);
//
// txt_alternative_game
//
this.txt_alternative_game.Enabled = false;
this.txt_alternative_game.Location = new System.Drawing.Point(667, 225);
this.txt_alternative_game.Name = "txt_alternative_game";
this.txt_alternative_game.Size = new System.Drawing.Size(205, 26);
this.txt_alternative_game.TabIndex = 24;
//
// txt_game_launcher
//
this.txt_game_launcher.Location = new System.Drawing.Point(605, 76);
@ -1378,7 +1455,7 @@ namespace DisplayMagician.UIForms
this.lv_games.LargeImageList = this.il_games;
this.lv_games.Location = new System.Drawing.Point(23, 30);
this.lv_games.Name = "lv_games";
this.lv_games.Size = new System.Drawing.Size(338, 217);
this.lv_games.Size = new System.Drawing.Size(338, 221);
this.lv_games.SmallImageList = this.il_games;
this.lv_games.TabIndex = 22;
this.lv_games.UseCompatibleStateImageBehavior = false;
@ -1583,55 +1660,16 @@ namespace DisplayMagician.UIForms
this.cb_autosuggest.UseVisualStyleBackColor = true;
this.cb_autosuggest.CheckedChanged += new System.EventHandler(this.cb_autosuggest_CheckedChanged);
//
// lbl_disabled_shortcut_audio_chipset
// cb_wait_alternative_game
//
this.lbl_disabled_shortcut_audio_chipset.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.lbl_disabled_shortcut_audio_chipset.AutoSize = true;
this.lbl_disabled_shortcut_audio_chipset.BackColor = System.Drawing.Color.Brown;
this.lbl_disabled_shortcut_audio_chipset.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_disabled_shortcut_audio_chipset.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_disabled_shortcut_audio_chipset.ForeColor = System.Drawing.Color.White;
this.lbl_disabled_shortcut_audio_chipset.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.lbl_disabled_shortcut_audio_chipset.Location = new System.Drawing.Point(326, 298);
this.lbl_disabled_shortcut_audio_chipset.Name = "lbl_disabled_shortcut_audio_chipset";
this.lbl_disabled_shortcut_audio_chipset.Size = new System.Drawing.Size(430, 22);
this.lbl_disabled_shortcut_audio_chipset.TabIndex = 34;
this.lbl_disabled_shortcut_audio_chipset.Text = "Unsupported Audio Chipset. Setting audio isn\'t supported :(";
this.lbl_disabled_shortcut_audio_chipset.Visible = false;
//
// lbl_no_active_audio_devices
//
this.lbl_no_active_audio_devices.Anchor = System.Windows.Forms.AnchorStyles.None;
this.lbl_no_active_audio_devices.AutoSize = true;
this.lbl_no_active_audio_devices.BackColor = System.Drawing.Color.Brown;
this.lbl_no_active_audio_devices.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_no_active_audio_devices.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_no_active_audio_devices.ForeColor = System.Drawing.Color.White;
this.lbl_no_active_audio_devices.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.lbl_no_active_audio_devices.Location = new System.Drawing.Point(131, 151);
this.lbl_no_active_audio_devices.Name = "lbl_no_active_audio_devices";
this.lbl_no_active_audio_devices.Size = new System.Drawing.Size(804, 22);
this.lbl_no_active_audio_devices.TabIndex = 35;
this.lbl_no_active_audio_devices.Text = "No active audio outputs found. Please connect or enable at least one audio output" +
" if you want to use this feature.";
this.lbl_no_active_audio_devices.Visible = false;
//
// lbl_no_active_capture_devices
//
this.lbl_no_active_capture_devices.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
this.lbl_no_active_capture_devices.AutoSize = true;
this.lbl_no_active_capture_devices.BackColor = System.Drawing.Color.Brown;
this.lbl_no_active_capture_devices.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.lbl_no_active_capture_devices.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
this.lbl_no_active_capture_devices.ForeColor = System.Drawing.Color.White;
this.lbl_no_active_capture_devices.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.lbl_no_active_capture_devices.Location = new System.Drawing.Point(126, 433);
this.lbl_no_active_capture_devices.Name = "lbl_no_active_capture_devices";
this.lbl_no_active_capture_devices.Size = new System.Drawing.Size(831, 22);
this.lbl_no_active_capture_devices.TabIndex = 36;
this.lbl_no_active_capture_devices.Text = "No active microphone inputs found. Please connect or enable at least one micropho" +
"ne if you want to use this feature.";
this.lbl_no_active_capture_devices.Visible = false;
this.cb_wait_alternative_game.AutoSize = true;
this.cb_wait_alternative_game.Location = new System.Drawing.Point(451, 214);
this.cb_wait_alternative_game.Name = "cb_wait_alternative_game";
this.cb_wait_alternative_game.Size = new System.Drawing.Size(220, 44);
this.cb_wait_alternative_game.TabIndex = 27;
this.cb_wait_alternative_game.Text = "Wait until this executable \r\nis closed before continuing:";
this.cb_wait_alternative_game.UseVisualStyleBackColor = true;
this.cb_wait_alternative_game.CheckedChanged += new System.EventHandler(this.cb_wait_alternative_game_CheckedChanged);
//
// ShortcutForm
//
@ -1819,5 +1857,8 @@ namespace DisplayMagician.UIForms
private System.Windows.Forms.Label lbl_disabled_shortcut_audio_chipset;
private System.Windows.Forms.Label lbl_no_active_audio_devices;
private System.Windows.Forms.Label lbl_no_active_capture_devices;
private System.Windows.Forms.Button btn_choose_alternative_game;
private System.Windows.Forms.TextBox txt_alternative_game;
private System.Windows.Forms.CheckBox cb_wait_alternative_game;
}
}

View File

@ -43,7 +43,7 @@ namespace DisplayMagician.UIForms
private bool _isUnsaved = true;
private bool _loadedShortcut = false;
private bool _autoName = true;
private int _gameId = 0;
private string _gameId = "0";
private string _uuid = "";
private CoreAudioController audioController = null;
private List<CoreAudioDevice> audioDevices = null;
@ -96,34 +96,42 @@ namespace DisplayMagician.UIForms
}
public SupportedGameLibrary GameLibrary
public SupportedGameLibraryType GameLibrary
{
get
{
if (txt_game_launcher.Text.Contains("Steam"))
{
return SupportedGameLibrary.Steam;
return SupportedGameLibraryType.Steam;
}
else if (txt_game_launcher.Text.Contains("Uplay"))
{
return SupportedGameLibrary.Uplay;
return SupportedGameLibraryType.Uplay;
}
else if (txt_game_launcher.Text.Contains("Origin"))
{
return SupportedGameLibraryType.Origin;
}
return SupportedGameLibrary.Unknown;
return SupportedGameLibraryType.Unknown;
}
set
{
switch (value)
{
case SupportedGameLibrary.Steam:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibrary), SupportedGameLibrary.Steam);
case SupportedGameLibraryType.Steam:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibraryType), SupportedGameLibraryType.Steam);
break;
case SupportedGameLibrary.Uplay:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibrary), SupportedGameLibrary.Uplay);
case SupportedGameLibraryType.Uplay:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibraryType), SupportedGameLibraryType.Uplay);
break;
case SupportedGameLibrary.Unknown:
case SupportedGameLibraryType.Origin:
txt_game_launcher.Text = Enum.GetName(typeof(SupportedGameLibraryType), SupportedGameLibraryType.Origin);
break;
case SupportedGameLibraryType.Unknown:
txt_game_launcher.Text = "No supported Game Libraries found";
break;
@ -269,7 +277,7 @@ namespace DisplayMagician.UIForms
return;
}
if (_gameId == 0)
if (_gameId.Equals("0"))
{
MessageBox.Show(
@"Please choose a Game by scrolling through the list, selecting the Game that you want, and then clicking the '>>' button to fill the Game fields.",
@ -300,6 +308,26 @@ namespace DisplayMagician.UIForms
return;
}
if (cb_wait_alternative_game.Checked && String.IsNullOrWhiteSpace(txt_alternative_game.Text))
{
MessageBox.Show(
$"If you want to wait for an alternative game executable then you need to choose it! Click the 'Choose' button next to the different game executable field.",
@"Need to choose the different game executable",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
return;
}
if (cb_wait_alternative_game.Checked && !File.Exists(txt_alternative_game.Text))
{
MessageBox.Show(
@"The alternative game executable you have chosen does not exist! Please reselect the alternative game executable, or check you have permissions to view it.",
@"Alternative game executable doesn't exist",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
return;
}
}
@ -475,76 +503,58 @@ namespace DisplayMagician.UIForms
if (rb_launcher.Checked)
{
logger.Trace($"ShortcutForm/btn_save_Click: We're saving a game!");
_gameToUse = new GameStruct
{
StartTimeout = Convert.ToInt32(nud_timeout_game.Value),
GameArguments = txt_args_game.Text,
GameArgumentsRequired = cb_args_game.Checked,
DifferentGameExeToMonitor = txt_alternative_game.Text,
MonitorDifferentGameExe = cb_wait_alternative_game.Checked
};
// If the game is a SteamGame
if (txt_game_launcher.Text == SupportedGameLibrary.Steam.ToString())
if (txt_game_launcher.Text == SupportedGameLibraryType.Steam.ToString())
{
logger.Trace($"ShortcutForm/btn_save_Click: We're saving a Steam game!");
// Find the SteamGame
_gameToUse = new GameStruct
{
GameToPlay = (from steamGame in SteamLibrary.AllInstalledGames where steamGame.Id == _gameId select steamGame).First(),
StartTimeout = Convert.ToInt32(nud_timeout_game.Value),
GameArguments = txt_args_game.Text,
GameArgumentsRequired = cb_args_game.Checked
};
_shortcutToEdit.UpdateGameShortcut(
txt_shortcut_save_name.Text,
_profileToUse,
_gameToUse,
_displayPermanence,
_audioPermanence,
_capturePermanence,
_gameToUse.GameToPlay.IconPath,
_changeAudioDevice,
_audioDevice,
_setAudioVolume,
_audioVolume,
_changeCaptureDevice,
_captureDevice,
_setCaptureVolume,
_captureVolume,
_startPrograms,
_autoName,
_uuid
);
_gameToUse.GameToPlay = (from steamGame in SteamLibrary.GetLibrary().AllInstalledGames where steamGame.Id == _gameId select steamGame).First();
}
// If the game is a SteamGame
else if (txt_game_launcher.Text == SupportedGameLibrary.Uplay.ToString())
// If the game is a UplayGame
else if (txt_game_launcher.Text == SupportedGameLibraryType.Uplay.ToString())
{
logger.Trace($"ShortcutForm/btn_save_Click: We're saving a Uplay game!");
// Find the UplayGame
_gameToUse = new GameStruct
{
GameToPlay = (from uplayGame in UplayLibrary.AllInstalledGames where uplayGame.Id == _gameId select uplayGame).First(),
StartTimeout = Convert.ToInt32(nud_timeout_game.Value),
GameArguments = txt_args_game.Text,
GameArgumentsRequired = cb_args_game.Checked
};
_shortcutToEdit.UpdateGameShortcut(
txt_shortcut_save_name.Text,
_profileToUse,
_gameToUse,
_displayPermanence,
_audioPermanence,
_capturePermanence,
_gameToUse.GameToPlay.IconPath,
_changeAudioDevice,
_audioDevice,
_setAudioVolume,
_audioVolume,
_changeCaptureDevice,
_captureDevice,
_setCaptureVolume,
_captureVolume,
_startPrograms,
_autoName,
_uuid
);
_gameToUse.GameToPlay = (from uplayGame in UplayLibrary.GetLibrary().AllInstalledGames where uplayGame.Id == _gameId select uplayGame).First();
}
// If the game is an Origin Game
else if (txt_game_launcher.Text == SupportedGameLibraryType.Origin.ToString())
{
logger.Trace($"ShortcutForm/btn_save_Click: We're saving an Origin game!");
_gameToUse.GameToPlay = (from originGame in OriginLibrary.GetLibrary().AllInstalledGames where originGame.Id == _gameId select originGame).First();
}
_shortcutToEdit.UpdateGameShortcut(
txt_shortcut_save_name.Text,
_profileToUse,
_gameToUse,
_displayPermanence,
_audioPermanence,
_capturePermanence,
_gameToUse.GameToPlay.IconPath,
_changeAudioDevice,
_audioDevice,
_setAudioVolume,
_audioVolume,
_changeCaptureDevice,
_captureDevice,
_setCaptureVolume,
_captureVolume,
_startPrograms,
_autoName,
_uuid
);
}
else if (rb_standalone.Checked)
{
@ -641,7 +651,7 @@ namespace DisplayMagician.UIForms
if ((txt_shortcut_save_name.Text.Length > 0) &&
_profileToUse is ProfileItem &&
(rb_no_game.Checked ||
rb_launcher.Checked && _gameId > 0 ||
rb_launcher.Checked && !_gameId.Equals("0") ||
rb_standalone.Checked && txt_executable.Text.Length > 0))
return true;
else
@ -913,9 +923,11 @@ namespace DisplayMagician.UIForms
// Populate a full list of games
// Start with the Steam Games
allGames = new List<Game>();
allGames.AddRange(SteamLibrary.AllInstalledGames);
allGames.AddRange(SteamLibrary.GetLibrary().AllInstalledGames);
// Then add the Uplay Games
allGames.AddRange(UplayLibrary.AllInstalledGames);
allGames.AddRange(UplayLibrary.GetLibrary().AllInstalledGames);
// Then add the Origin Games
allGames.AddRange(OriginLibrary.GetLibrary().AllInstalledGames);
// Load all the Games into the Games ListView
@ -937,11 +949,6 @@ namespace DisplayMagician.UIForms
// Add the images to the images array
il_games.Images.Add(bm);
/*if (!Visible)
{
//return;
}*/
// ADd the game to the game array
lv_games.Items.Add(new ListViewItem
{
@ -1043,8 +1050,23 @@ namespace DisplayMagician.UIForms
break;
}
// Monitor the alternative game exe if we have it
if (_shortcutToEdit.MonitorDifferentGameExe)
{
cb_wait_alternative_game.Checked = true;
if (!String.IsNullOrWhiteSpace(_shortcutToEdit.DifferentGameExeToMonitor))
{
txt_alternative_game.Text = _shortcutToEdit.DifferentGameExeToMonitor;
}
}
else
{
cb_wait_alternative_game.Checked = false;
}
// Set the launcher items if we have them
if (_shortcutToEdit.GameLibrary.Equals(SupportedGameLibrary.Unknown))
if (_shortcutToEdit.GameLibrary.Equals(SupportedGameLibraryType.Unknown))
{
if (allGames.Count <= 0)
{
@ -1063,7 +1085,6 @@ namespace DisplayMagician.UIForms
}
}
else
{
txt_game_launcher.Text = _shortcutToEdit.GameLibrary.ToString();
@ -1286,7 +1307,8 @@ namespace DisplayMagician.UIForms
{
if (_loadedShortcut)
_isUnsaved = true;
if (File.Exists(dialog_open.FileName) && Path.GetExtension(dialog_open.FileName) == @".exe")
string fileExt = Path.GetExtension(dialog_open.FileName);
if (File.Exists(dialog_open.FileName) && (fileExt == @".exe" || fileExt == @".com"))
{
txt_alternative_executable.Text = dialog_open.FileName;
dialog_open.FileName = string.Empty;
@ -2164,5 +2186,44 @@ namespace DisplayMagician.UIForms
else
cb_start_program4.CheckState = CheckState.Unchecked;
}
private void cb_wait_alternative_game_CheckedChanged(object sender, EventArgs e)
{
if (_loadedShortcut)
_isUnsaved = true;
if (cb_wait_alternative_game.Checked)
{
txt_alternative_game.Enabled = true;
btn_choose_alternative_game.Enabled = true;
}
else
{
txt_alternative_game.Enabled = false;
btn_choose_alternative_game.Enabled = false;
}
}
private void btn_choose_alternative_game_Click(object sender, EventArgs e)
{
if (dialog_open.ShowDialog(this) == DialogResult.OK)
{
if (_loadedShortcut)
_isUnsaved = true;
string fileExt = Path.GetExtension(dialog_open.FileName);
if (File.Exists(dialog_open.FileName) && (fileExt == @".exe" || fileExt == @".com"))
{
txt_alternative_game.Text = dialog_open.FileName;
dialog_open.FileName = string.Empty;
}
else
{
MessageBox.Show(
Language.Selected_file_is_not_a_valid_file,
Language.Executable,
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
}
}
}
}
}

View File

@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.4.0")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyVersion("1.0.5.0")]
[assembly: AssemblyFileVersion("1.0.5.0")]

View File

@ -6,7 +6,7 @@
-->
<?define MajorVersion="1" ?>
<?define MinorVersion="0" ?>
<?define BuildVersion="4" ?>
<?define BuildVersion="5" ?>
<!-- Revision is NOT used by WiX in the upgrade procedure -->
<!-- Full version number to display -->
<?define VersionNumber="$(var.MajorVersion).$(var.MinorVersion).$(var.BuildVersion)" ?>

View File

@ -807,18 +807,80 @@ namespace DisplayMagicianShared
NvAPIWrapper.Display.DisplayDevice aConnectedDisplayDevice = myPhysicalGPU.GetDisplayDeviceByOutput(aGPUOutput);
// Create an array of all the important display info we need to record
string[] displayInfo = {
"NVIDIA",
myPhysicalGPU.ArchitectInformation.ShortName.ToString(),
myPhysicalGPU.ArchitectInformation.Revision.ToString(),
myPhysicalGPU.Board.ToString(),
myPhysicalGPU.Foundry.ToString(),
myPhysicalGPU.GPUId.ToString(),
myPhysicalGPU.GPUType.ToString(),
//aGPUOutput.OutputId.ToString(),
aConnectedDisplayDevice.ConnectionType.ToString(),
aConnectedDisplayDevice.DisplayId.ToString()
};
List<string> displayInfo = new List<string>();
displayInfo.Add("NVIDIA");
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.ShortName.ToString());
}
catch(Exception ex)
{
SharedLogger.logger.Warn(ex,$"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture ShortName from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.Revision.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture Revision from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Board.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Board details from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Foundry.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Foundry from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUId from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUType from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aConnectedDisplayDevice.ConnectionType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Connection from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aConnectedDisplayDevice.DisplayId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA DisplayID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
// Create a display identifier out of it
string displayIdentifier = String.Join("|", displayInfo);
@ -848,59 +910,129 @@ namespace DisplayMagicianShared
PathDisplaySource pathDisplaySource = attachedDisplay.ToPathDisplaySource();
PathDisplayTarget pathDisplayTarget = attachedDisplay.ToPathDisplayTarget();
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDN : {attachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDFN : {attachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {attachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {attachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIGP : {attachedDisplay.IsGDIPrimary}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIV : {attachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSF : {attachedDisplay.CurrentSetting.Frequency}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSO : {attachedDisplay.CurrentSetting.Orientation}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSP : {attachedDisplay.CurrentSetting.Position}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSR : {attachedDisplay.CurrentSetting.Resolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DDA : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
try
{
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDN : {attachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDFN : {attachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIN : {attachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIN : {attachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIGP : {attachedDisplay.IsGDIPrimary}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIV : {attachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSF : {attachedDisplay.CurrentSetting.Frequency}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSO : {attachedDisplay.CurrentSetting.Orientation}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSP : {attachedDisplay.CurrentSetting.Position}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSR : {attachedDisplay.CurrentSetting.Resolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DDA : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception accessing one of the WindowsDisplayAPI items to print it out during a TRACE session");
}
// Create an array of all the important display info we need to record
string[] displayInfo = {
"WINAPI",
displayAdapter.DeviceName.ToString(),
pathDisplayAdapter.AdapterId.ToString(),
pathDisplayTarget.ConnectorInstance.ToString(),
pathDisplayTarget.FriendlyName,
pathDisplayTarget.EDIDManufactureCode.ToString(),
pathDisplayTarget.EDIDManufactureId.ToString(),
pathDisplayTarget.EDIDProductCode.ToString(),
pathDisplayTarget.TargetId.ToString(),
};
List<string> displayInfo = new List<string>();
displayInfo.Add("WINAPI");
try
{
displayInfo.Add(displayAdapter.DeviceName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Adapter Device name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayAdapter.AdapterId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Adapter ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.ConnectorInstance.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target Connector Instance from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.FriendlyName);
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target Friendly name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureCode.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDProductCode.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display EDID Product Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.TargetId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
// Create a display identifier out of it
string displayIdentifier = String.Join("|", displayInfo);
@ -954,18 +1086,80 @@ namespace DisplayMagicianShared
if (aDisplayDevice.IsAvailable== true)
{
// Create an array of all the important display info we need to record
string[] displayInfo = {
"NVIDIA",
myPhysicalGPU.ArchitectInformation.ShortName.ToString(),
myPhysicalGPU.ArchitectInformation.Revision.ToString(),
myPhysicalGPU.Board.ToString(),
myPhysicalGPU.Foundry.ToString(),
myPhysicalGPU.GPUId.ToString(),
myPhysicalGPU.GPUType.ToString(),
//aDisplayDevice.Output.OutputId.ToString(),
aDisplayDevice.ConnectionType.ToString(),
aDisplayDevice.DisplayId.ToString(),
};
List<string> displayInfo = new List<string>();
displayInfo.Add("NVIDIA");
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.ShortName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture ShortName from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.ArchitectInformation.Revision.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Architecture Revision from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Board.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Board details from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.Foundry.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Foundry from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUId from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(myPhysicalGPU.GPUType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA GPUType from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aDisplayDevice.ConnectionType.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA Connection from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(aDisplayDevice.DisplayId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting NVIDIA DisplayID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
// Create a display identifier out of it
string displayIdentifier = String.Join("|", displayInfo);
@ -976,7 +1170,7 @@ namespace DisplayMagicianShared
}
}
}
// else videocard is not NVIdia so we just use the WindowsAPI access method
// else videocard is not NVIDIA so we just use the WindowsAPI access method
// Note: This won't support any special AMD EyeFinity profiles unfortunately.....
// TODO: Add the detection and generation of the device ids using an AMD library
// so that we can match valid AMD Eyefinity profiles with valid AMD standard profiles.
@ -997,59 +1191,129 @@ namespace DisplayMagicianShared
PathDisplaySource pathDisplaySource = attachedDisplay.ToPathDisplaySource();
PathDisplayTarget pathDisplayTarget = attachedDisplay.ToPathDisplayTarget();
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDN : {attachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDFN : {attachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {attachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {attachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIGP : {attachedDisplay.IsGDIPrimary}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIV : {attachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSF : {attachedDisplay.CurrentSetting.Frequency}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSO : {attachedDisplay.CurrentSetting.Orientation}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSP : {attachedDisplay.CurrentSetting.Position}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADCSR : {attachedDisplay.CurrentSetting.Resolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: DDA : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
try
{
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDN : {attachedDisplay.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDFN : {attachedDisplay.DisplayFullName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIN : {attachedDisplay.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIN : {attachedDisplay.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIGP : {attachedDisplay.IsGDIPrimary}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADDIV : {attachedDisplay.IsValid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSF : {attachedDisplay.CurrentSetting.Frequency}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSO : {attachedDisplay.CurrentSetting.Orientation}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSP : {attachedDisplay.CurrentSetting.Position}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: ADCSR : {attachedDisplay.CurrentSetting.Resolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DP : {displayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DN : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DK : {displayAdapter.DeviceKey}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AI : {pathDisplayAdapter.AdapterId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AIDP : {pathDisplayAdapter.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: AIII : {pathDisplayAdapter.IsInvalid}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: DDA : {displayAdapter.DeviceName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSA : {pathDisplaySource.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSCDS : {pathDisplaySource.CurrentDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSDN : {pathDisplaySource.DisplayName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSMDS : {pathDisplaySource.MaximumDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSRDS : {pathDisplaySource.RecommendedDPIScale}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDSSI : {pathDisplaySource.SourceId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTA : {pathDisplayTarget.Adapter}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTCI : {pathDisplayTarget.ConnectorInstance}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTDP : {pathDisplayTarget.DevicePath}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEMC : {pathDisplayTarget.EDIDManufactureCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEMI : {pathDisplayTarget.EDIDManufactureId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTEPC : {pathDisplayTarget.EDIDProductCode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTFN : {pathDisplayTarget.FriendlyName}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTIA : {pathDisplayTarget.IsAvailable}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTPR : {pathDisplayTarget.PreferredResolution}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTPSM : {pathDisplayTarget.PreferredSignalMode}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTTI : {pathDisplayTarget.TargetId}");
SharedLogger.logger.Trace($"ProfileRepository/GenerateProfileDisplayIdentifiers: PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}");
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception accessing one of the WindowsDisplayAPI items to print it out during a TRACE session");
}
// Create an array of all the important display info we need to record
string[] displayInfo = {
"WINAPI",
displayAdapter.DeviceName.ToString(),
pathDisplayAdapter.AdapterId.ToString(),
pathDisplayTarget.ConnectorInstance.ToString(),
pathDisplayTarget.FriendlyName,
pathDisplayTarget.EDIDManufactureCode.ToString(),
pathDisplayTarget.EDIDManufactureId.ToString(),
pathDisplayTarget.EDIDProductCode.ToString(),
pathDisplayTarget.TargetId.ToString(),
};
List<string> displayInfo = new List<string>();
displayInfo.Add("WINAPI");
try
{
displayInfo.Add(displayAdapter.DeviceName.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Adapter Device name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayAdapter.AdapterId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Adapter ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.ConnectorInstance.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target Connector Instance from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.FriendlyName);
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target Friendly name from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureCode.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDManufactureId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display EDID Manufacturer ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.EDIDProductCode.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display EDID Product Code from video card. Substituting with a # instead");
displayInfo.Add("#");
}
try
{
displayInfo.Add(pathDisplayTarget.TargetId.ToString());
}
catch (Exception ex)
{
SharedLogger.logger.Warn(ex, $"ProfileRepository/GenerateProfileDisplayIdentifiers: Exception getting Windows Display Target ID from video card. Substituting with a # instead");
displayInfo.Add("#");
}
// Create a display identifier out of it
string displayIdentifier = String.Join("|", displayInfo);

View File

@ -35,5 +35,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.4.0")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyVersion("1.0.5.0")]
[assembly: AssemblyFileVersion("1.0.5.0")]

View File

@ -35,5 +35,5 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.4.0")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: AssemblyVersion("1.0.5.0")]
[assembly: AssemblyFileVersion("1.0.5.0")]

View File

@ -1,6 +1,6 @@
{
"version": "1.0.4.0",
"url": "https://github.com/terrymacdonald/DisplayMagician/releases/download/v1.0.4/DisplayMagicianSetup-v1.0.4.msi",
"version": "1.0.5.0",
"url": "https://github.com/terrymacdonald/DisplayMagician/releases/download/v1.0.5/DisplayMagicianSetup-v1.0.5.msi",
"changelog": "https://github.com/terrymacdonald/DisplayMagician/releases",
"mandatory": {
"value": false,
@ -8,7 +8,7 @@
"mode": 0
},
"checksum": {
"value": "253E7B3BCC753AA7621BD88C7F86155B5CAF5C09C2DD222B25A3D4F3D819790E",
"value": "36273CAEB4E7FE006ED48400CC243B0D01CE4AEFCF8F399A9641B7C124245F79",
"hashingAlgorithm": "SHA256"
}
}