From 40dd1473882d69526c0a366ee8edba944efed583 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sun, 4 Apr 2021 18:59:38 +1200 Subject: [PATCH 01/16] Fixed Display Driver change impacts NVIDIA just updated their device driver, and as part of those changes, it changed the name that was reported by the NVIDIA driver. This impacts our profile matching, as we previously used the name that it returned in the fingerprint we store about connected displays. This change removes that name so that it will correctly match on the old driver or the new driver. NOTE: This requires recreating the profiles though! --- DisplayMagicianShared/ProfileItem.cs | 7 ++++++- DisplayMagicianShared/ProfileRepository.cs | 6 ------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/DisplayMagicianShared/ProfileItem.cs b/DisplayMagicianShared/ProfileItem.cs index 08a0aeb..bea2f81 100644 --- a/DisplayMagicianShared/ProfileItem.cs +++ b/DisplayMagicianShared/ProfileItem.cs @@ -507,10 +507,15 @@ namespace DisplayMagicianShared { // Check each display in this profile and make sure it's currently available int validDisplayCount = 0; + + //validDisplayCount = (from connectedDisplay in ProfileRepository.ConnectedDisplayIdentifiers select connectedDisplay == profileDisplayIdentifier).Count(); + foreach (string profileDisplayIdentifier in ProfileDisplayIdentifiers) { // If this profile has a display that isn't currently available then we need to say it's a no! - if (ProfileRepository.ConnectedDisplayIdentifiers.Contains(profileDisplayIdentifier)) + //if (ProfileRepository.ConnectedDisplayIdentifiers.Contains(profileDisplayIdentifier)) + //validDisplayCount = (from connectedDisplay in ProfileRepository.ConnectedDisplayIdentifiers select connectedDisplay == profileDisplayIdentifier).Count(); + if (ProfileRepository.ConnectedDisplayIdentifiers.Any(s => profileDisplayIdentifier.Equals(s))) validDisplayCount++; } if (validDisplayCount == ProfileDisplayIdentifiers.Count) diff --git a/DisplayMagicianShared/ProfileRepository.cs b/DisplayMagicianShared/ProfileRepository.cs index d40868d..e7f23e5 100644 --- a/DisplayMagicianShared/ProfileRepository.cs +++ b/DisplayMagicianShared/ProfileRepository.cs @@ -762,8 +762,6 @@ namespace DisplayMagicianShared // Get the list of connected devices ConnectedDisplayIdentifiers = GenerateAllAvailableDisplayIdentifiers(); - - if (_profilesLoaded && _allProfiles.Count > 0) { @@ -810,8 +808,6 @@ namespace DisplayMagicianShared // Create an array of all the important display info we need to record string[] displayInfo = { "NVIDIA", - myPhysicalGPU.CorrespondingLogicalGPU.ToString(), - myPhysicalGPU.ToString(), myPhysicalGPU.ArchitectInformation.ShortName.ToString(), myPhysicalGPU.ArchitectInformation.Revision.ToString(), myPhysicalGPU.Board.ToString(), @@ -958,8 +954,6 @@ namespace DisplayMagicianShared // Create an array of all the important display info we need to record string[] displayInfo = { "NVIDIA", - myPhysicalGPU.CorrespondingLogicalGPU.ToString(), - myPhysicalGPU.ToString(), myPhysicalGPU.ArchitectInformation.ShortName.ToString(), myPhysicalGPU.ArchitectInformation.Revision.ToString(), myPhysicalGPU.Board.ToString(), From 3fcd90a54277a754563dddd6533134d29499cde9 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sun, 4 Apr 2021 21:49:37 +1200 Subject: [PATCH 02/16] Create app dirs on first boot Also improve logging detail when loglevel is set to trace. --- DisplayMagician/GameLibraries/UplayLibrary.cs | 115 +++++++++--------- DisplayMagician/Program.cs | 36 ++++++ 2 files changed, 93 insertions(+), 58 deletions(-) diff --git a/DisplayMagician/GameLibraries/UplayLibrary.cs b/DisplayMagician/GameLibraries/UplayLibrary.cs index f09c4ae..bee23b8 100644 --- a/DisplayMagician/GameLibraries/UplayLibrary.cs +++ b/DisplayMagician/GameLibraries/UplayLibrary.cs @@ -48,7 +48,15 @@ namespace DisplayMagician.GameLibraries _uplayPath = uplayInstallKey.GetValue("InstallDir", "C:\\Program Files (x86)\\Ubisoft\\Ubisoft Game Launcher\\").ToString(); _uplayExe = $"{_uplayPath}upc.exe"; if (File.Exists(_uplayExe)) - _isUplayInstalled = true; + { + logger.Info($"UplayLibrary/UplayLibrary: Uplay library is installed in {_uplayPath}. Found {_uplayExe}"); + _isUplayInstalled = true; + } + else + { + logger.Info($"UplayLibrary/UplayLibrary: Uplay library is not installed!"); + } + } catch (SecurityException ex) { @@ -335,6 +343,7 @@ namespace DisplayMagician.GameLibraries if (!_isUplayInstalled) { // Uplay isn't installed, so we return an empty list. + logger.Debug($"UplayLibrary/LoadInstalledGames: Uplay library is not installed, so returning false"); return false; } @@ -347,6 +356,7 @@ namespace DisplayMagician.GameLibraries // Access {installdir}\\cache\\configuration\\configurations file string uplayConfigFilePath = _uplayPath + @"cache\configuration\configurations"; + logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Config File Path = {uplayConfigFilePath }"); string uplayConfigFileString = File.ReadAllText(uplayConfigFilePath); uplayConfigFileString = uplayConfigFileString.Remove(0, 12); // Split the file into records at the SOH unicode character @@ -358,6 +368,8 @@ namespace DisplayMagician.GameLibraries if (!uplayEntry.StartsWith("version:",StringComparison.OrdinalIgnoreCase)) continue; + logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Entry (that don't start with version) = {uplayEntry}"); + //Split the record into entrylines string[] delimeters = { "\r\n" }; List uplayEntryLines = uplayEntry.Split(delimeters, System.StringSplitOptions.RemoveEmptyEntries).ToList(); @@ -401,38 +413,6 @@ namespace DisplayMagician.GameLibraries // for each game record grab: UplayAppInfo uplayGameAppInfo = new UplayAppInfo(); -/* // name: (lookup the id in lookup table to find the name if needed) - if (uplayEntryLines.Exists(a => a.StartsWith(" name:", StringComparison.InvariantCultureIgnoreCase))) - { - mc = Regex.Matches(uplayEntry, @" name\: (.*)"); - uplayGameAppInfo.GameName = mc[0].Groups[1].ToString(); - // if the name contains a localization reference, then dereference it - if (localizations.ContainsKey(uplayGameAppInfo.GameName)) - { - uplayGameAppInfo.GameName = localizations[uplayGameAppInfo.GameName]; - } - } - else - continue; -*/ - // icon_image: (lookup the id in lookup table to find the ICON) - /*if (uplayEntryLines.Exists(a => a.StartsWith(" icon_image:", StringComparison.InvariantCultureIgnoreCase))) - { - mc = Regex.Matches(uplayEntry, @"icon_image: (.*)"); - string iconImageFileName = mc[0].Groups[1].ToString(); - // if the icon_image contains a localization reference, then dereference it - if (localizations.ContainsKey(iconImageFileName)) - { - iconImageFileName = localizations[iconImageFileName]; - } - //61fdd16f06ae08158d0a6d476f1c6bd5.ico - string uplayGameIconPath = _uplayPath + @"data\games\" + iconImageFileName; - if (File.Exists(uplayGameIconPath) && uplayGameIconPath.EndsWith(".ico")) - { - uplayGameAppInfo.GameUplayIconPath = uplayGameIconPath; - } - }*/ - // 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) // Extract the GameAppID from the number in the working directory (e.g. 720) @@ -498,14 +478,34 @@ namespace DisplayMagician.GameLibraries } } + logger.Trace($"UplayLibrary/LoadInstalledGames: gameId = {gameId}"); + logger.Trace($"UplayLibrary/LoadInstalledGames: gameFileName = {gameFileName}"); + logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameUplayIconPath}"); + // Now we need to lookup the game install path in registry using the gameId string registryUplayGameInstallsKey = registryUplayInstallsKey + "\\" + gameId; + logger.Trace($"UplayLibrary/LoadInstalledGames: registryUplayGameInstallsKey = {registryUplayGameInstallsKey}"); RegistryKey uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(registryUplayGameInstallsKey, RegistryKeyPermissionCheck.ReadSubTree); + foreach (string regKeyName in uplayGameInstallKey.GetValueNames()) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameInstallKey[{regKeyName}] = {uplayGameInstallKey.GetValue(regKeyName)}"); + } - // From that we lookup the actual game path - uplayGameAppInfo.GameInstallDir = Path.GetFullPath(uplayGameInstallKey.GetValue("InstallDir", "").ToString()).TrimEnd('\\'); - uplayGameAppInfo.GameExe = Path.Combine(uplayGameAppInfo.GameInstallDir,gameFileName); - uplayGameAppInfo.GameID = int.Parse(gameId); + // From that we lookup the actual game path + string gameInstallDir = uplayGameInstallKey.GetValue("InstallDir", "").ToString(); + logger.Trace($"UplayLibrary/LoadInstalledGames: gameInstallDir found through first method (forward slashes) = {gameInstallDir}"); + if (!String.IsNullOrWhiteSpace(gameInstallDir)) + { + 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); + logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameID = {uplayGameAppInfo.GameID }"); + } + else { + logger.Warn($"UplayLibrary/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! @@ -513,35 +513,34 @@ namespace DisplayMagician.GameLibraries } } + + catch (ArgumentNullException ex) + { + logger.Warn(ex, "UplayLibrary/GetAllInstalledGames: An argument supplied to the function is null."); + } + catch (NotSupportedException ex) + { + logger.Warn(ex, "UplayLibrary/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, "UplayLibrary/GetAllInstalledGames: The path is longer than the maximum allowed by the operating system."); + } catch (SecurityException ex) { - Console.WriteLine($"UplayGame/GetAllInstalledGames securityexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; - } - catch (UnauthorizedAccessException ex) - { - Console.WriteLine($"UplayGame/GetAllInstalledGames unauthorizedaccessexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("UnauthorizedAccessException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, "UplayLibrary/GetAllInstalledGames: The user does not have the permissions required to read the Uplay InstallDir registry key."); } catch (ObjectDisposedException ex) { - Console.WriteLine($"UplayGame/GetAllInstalledGames objectdisposedexceptions: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("ObjectDisposedException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, "UplayLibrary/GetAllInstalledGames: The Microsoft.Win32.RegistryKey is closed when trying to access the Uplay InstallDir registry key (closed keys cannot be accessed)."); } catch (IOException ex) { - Console.WriteLine($"UplayGame/GetAllInstalledGames ioexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - // Extract some information from this exception, and then - // throw it to the parent method. - if (ex.Source != null) - Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, "UplayLibrary/GetAllInstalledGames: The Uplay InstallDir registry key has been marked for deletion so we cannot access the value dueing the UplayLibrary check."); + } + catch (UnauthorizedAccessException ex) + { + logger.Warn(ex, "UplayLibrary/GetAllInstalledGames: The user does not have the necessary registry rights to check whether Uplay is installed."); } return true; diff --git a/DisplayMagician/Program.cs b/DisplayMagician/Program.cs index a5431c8..e4e41a0 100644 --- a/DisplayMagician/Program.cs +++ b/DisplayMagician/Program.cs @@ -157,6 +157,42 @@ namespace DisplayMagician { // Start the Log file logger.Info($"Starting {Application.ProductName} v{Application.ProductVersion}"); + // Create the other DM Dir if it doesn't exist so that it's avilable for all + // parts of the program to use + if (!Directory.Exists(AppIconPath)) + { + try + { + Directory.CreateDirectory(AppIconPath); + } + catch (Exception ex) + { + logger.Error(ex, $"Program/StartUpNormally exception: Cannot create the Application Icon Folder {AppLogPath}"); + } + } + if (!Directory.Exists(AppProfilePath)) + { + try + { + Directory.CreateDirectory(AppProfilePath); + } + catch (Exception ex) + { + logger.Error(ex, $"Program/StartUpNormally exception: Cannot create the Application Profile Folder {AppProfilePath}"); + } + } + if (!Directory.Exists(AppShortcutPath)) + { + try + { + Directory.CreateDirectory(AppShortcutPath); + } + catch (Exception ex) + { + logger.Error(ex, $"Program/StartUpNormally exception: Cannot create the Application Shortcut Folder {AppShortcutPath}"); + } + } + // Write the Application Name Console.WriteLine($"{Application.ProductName} v{Application.ProductVersion}"); for (int i = 0; i <= Application.ProductName.Length + Application.ProductVersion .Length; i++) From a377f3477f683ed1287428fcf638339254b55367 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Wed, 7 Apr 2021 23:37:05 +1200 Subject: [PATCH 03/16] Fixing library with no installed games error Both Steam and Uplay library logic would error when the library was installed, but didn't have any installed games. Thanks to @joeymanson23 for the report. Fixes #4. Adds a LOT more logging to the Steam and Uplay libraries to allow for remote troubleshooting via the log file, especially if the logging settings are set to TRACE. Also fixed the long standing issue for being able to install two copies of DisplayMagician of the same version. Now the installer will prevent that from happening! --- DisplayMagician/GameLibraries/SteamLibrary.cs | 180 ++++++++++++------ DisplayMagician/GameLibraries/UplayLibrary.cs | 68 ++++++- DisplayMagician/Program.cs | 2 - DisplayMagician/Properties/AssemblyInfo.cs | 4 +- .../Includes/DisplayMagicianVariables.wxi | 8 + DisplayMagicianSetup/Product.wxs | 18 +- 6 files changed, 207 insertions(+), 73 deletions(-) diff --git a/DisplayMagician/GameLibraries/SteamLibrary.cs b/DisplayMagician/GameLibraries/SteamLibrary.cs index 9d1a305..f4694e3 100644 --- a/DisplayMagician/GameLibraries/SteamLibrary.cs +++ b/DisplayMagician/GameLibraries/SteamLibrary.cs @@ -20,8 +20,8 @@ namespace DisplayMagician.GameLibraries private static string _steamExe; private static string _steamPath; private static string _steamConfigVdfFile; - private static string _registrySteamKey = @"SOFTWARE\\Valve\\Steam"; - private static string _registryAppsKey = $@"{_registrySteamKey}\\Apps"; + 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 @@ -41,32 +41,40 @@ namespace DisplayMagician.GameLibraries { try { + logger.Trace($"SteamLibrary/SteamLibrary: Steam launcher registry key = HKLM\\{_registrySteamKey}"); // Find the SteamExe location, and the SteamPath for later - using (var key = Registry.CurrentUser.OpenSubKey(SteamLibrary.SteamRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) + using (var steamInstallKey = Registry.LocalMachine.OpenSubKey(_registrySteamKey, RegistryKeyPermissionCheck.ReadSubTree)) { - _steamExe = (string)key?.GetValue(@"SteamExe", string.Empty) ?? string.Empty; - _steamExe = _steamExe.Replace('/', '\\'); - _steamPath = (string)key?.GetValue(@"SteamPath", string.Empty) ?? string.Empty; - _steamPath = _steamPath.Replace('/', '\\'); - } + if (steamInstallKey == null) + return; + _steamPath = steamInstallKey.GetValue("InstallPath", "C:\\Program Files (x86)\\Steam").ToString(); + _steamExe = $"{_steamPath}\\steam.exe"; + } if (File.Exists(_steamExe)) - _isSteamInstalled = true; + { + logger.Info($"SteamLibrary/SteamLibrary: Steam library is installed in {_steamPath}. Found {_steamExe}"); + _isSteamInstalled = true; + } + else + { + logger.Info($"SteamLibrary/SteamLibrary: Steam library is not installed!"); + } } catch (SecurityException ex) { - logger.Warn(ex,"The user does not have the permissions required to read the Steam registry key."); + logger.Warn(ex, "SteamLibrary/SteamLibrary: The user does not have the permissions required to read the Steam registry key."); } catch (ObjectDisposedException ex) { - logger.Warn(ex, "The Microsoft.Win32.RegistryKey is closed when trying to access theSteam registry key (closed keys cannot be accessed)."); + logger.Warn(ex, "SteamLibrary/SteamLibrary: The Microsoft.Win32.RegistryKey is closed when trying to access the Steam registry key (closed keys cannot be accessed)."); } catch (IOException ex) { - logger.Warn(ex, "The Steam registry key has been marked for deletion so we cannot access the value during the SteamLibrary check."); + logger.Warn(ex, "SteamLibrary/SteamLibrary: The Steam registry key has been marked for deletion so we cannot access the value during the SteamLibrary check."); } catch (UnauthorizedAccessException ex) { - logger.Warn(ex, "The user does not have the necessary registry rights to check whether Steam is installed."); + logger.Warn(ex, "SteamLibrary/SteamLibrary: The user does not have the necessary registry rights to check whether Steam is installed."); } } #endregion @@ -146,12 +154,14 @@ namespace DisplayMagician.GameLibraries // Because then we just update the one that already exists if (ContainsSteamGame(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); } else { + logger.Debug($"SteamLibrary/AddSteamGame: Adding Steam game {steamGame.Name} to our Steam library"); // Add the steamGame to the list of steamGames _allSteamGames.Add(steamGame); } @@ -171,15 +181,21 @@ namespace DisplayMagician.GameLibraries if (!(steamGame is SteamGame)) return false; + logger.Debug($"SteamLibrary/RemoveSteamGame: Removing Steam game {steamGame.Name} from our Steam library"); + // Remove the steamGame from the list. int numRemoved = _allSteamGames.RemoveAll(item => item.Id.Equals(steamGame.Id)); if (numRemoved == 1) { + logger.Debug($"SteamLibrary/RemoveSteamGame: Removed Steam game with name {steamGame.Name}"); return true; } else if (numRemoved == 0) + { + logger.Debug($"SteamLibrary/RemoveSteamGame: Didn't remove Steam game with ID {steamGame.Name} from the Steam Library"); return false; + } else throw new SteamLibraryException(); } @@ -189,15 +205,21 @@ namespace DisplayMagician.GameLibraries if (steamGameId<=0) return false; + logger.Debug($"SteamLibrary/RemoveSteamGame2: Removing Steam game with ID {steamGameId} from the Steam library"); + // Remove the steamGame from the list. int numRemoved = _allSteamGames.RemoveAll(item => item.Id.Equals(steamGameId)); if (numRemoved == 1) { + logger.Debug($"SteamLibrary/RemoveSteamGame2: Removed Steam game with ID {steamGameId}"); return true; } else if (numRemoved == 0) + { + logger.Debug($"SteamLibrary/RemoveSteamGame2: Didn't remove Steam game with ID {steamGameId} from the Steam Library"); return false; + } else throw new SteamLibraryException(); } @@ -208,6 +230,8 @@ namespace DisplayMagician.GameLibraries if (String.IsNullOrWhiteSpace(steamGameNameOrUuid)) return false; + logger.Debug($"SteamLibrary/RemoveSteamGame3: Removing Steam game with Name or UUID {steamGameNameOrUuid} from the Steam library"); + int numRemoved; Match match = Regex.Match(steamGameNameOrUuid, steamAppIdRegex, RegexOptions.IgnoreCase); if (match.Success) @@ -216,9 +240,15 @@ namespace DisplayMagician.GameLibraries numRemoved = _allSteamGames.RemoveAll(item => steamGameNameOrUuid.Equals(item.Name)); if (numRemoved == 1) + { + logger.Debug($"SteamLibrary/RemoveSteamGame3: Removed Steam game with Name or UUID {steamGameNameOrUuid} "); return true; + } else if (numRemoved == 0) + { + logger.Debug($"SteamLibrary/RemoveSteamGame3: Didn't remove Steam game with Name or UUID {steamGameNameOrUuid} from the Steam Library"); return false; + } else throw new SteamLibraryException(); @@ -328,26 +358,15 @@ namespace DisplayMagician.GameLibraries try { - // Find the SteamExe location, and the SteamPath for later - /*using (var key = Registry.CurrentUser.OpenSubKey(_registrySteamKey, RegistryKeyPermissionCheck.ReadSubTree)) - { - _steamExe = (string)key?.GetValue(@"SteamExe", string.Empty) ?? string.Empty; - _steamExe = _steamExe.Replace('/', '\\'); - _steamPath = (string)key?.GetValue(@"SteamPath", string.Empty) ?? string.Empty; - _steamPath = _steamPath.Replace('/', '\\'); - }*/ - if (!_isSteamInstalled) { // Steam isn't installed, so we return an empty list. + logger.Info($"SteamLibrary/LoadInstalledGames: Steam library is not installed"); return false; } - //Icon _steamIcon = Icon.ExtractAssociatedIcon(_steamExe); - //IconExtractor steamIconExtractor = new IconExtractor(_steamExe); - //Icon _steamIcon = steamIconExtractor.GetIcon(0); - //MultiIcon _steamIcon = new MultiIcon(); - //_steamIcon.Load(_steamExe); + logger.Trace($"SteamLibrary/LoadInstalledGames: Steam Base Registry Key = HKLM\\{_registrySteamKey}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Steam Apps Registry Key = HKCU\\{_registryAppsKey}"); List steamAppIdsInstalled = new List(); // Now look for what games app id's are actually installed on this computer @@ -355,11 +374,14 @@ namespace DisplayMagician.GameLibraries { if (steamAppsKey != null) { + // // Loop through the subKeys as they are the Steam Game IDs foreach (string steamGameKeyName in steamAppsKey.GetSubKeyNames()) { + logger.Trace($"SteamLibrary/LoadInstalledGames: Found SteamGameKeyName = {steamGameKeyName}"); if (int.TryParse(steamGameKeyName, out int steamAppId)) { + logger.Trace($"SteamLibrary/LoadInstalledGames: SteamGameKeyName is an int, so trying to see if it is a game"); string steamGameKeyFullName = $"{_registryAppsKey}\\{steamGameKeyName}"; using (RegistryKey steamGameKey = Registry.CurrentUser.OpenSubKey(steamGameKeyFullName, RegistryKeyPermissionCheck.ReadSubTree)) { @@ -367,14 +389,36 @@ namespace DisplayMagician.GameLibraries // We want to keep track of that for later if ((int)steamGameKey.GetValue(@"Installed", 0) == 1) { + logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} contains an 'Installed' value so is an installed Steam Game."); // Add this Steam App ID to the list we're keeping for later steamAppIdsInstalled.Add(steamAppId); } + else + { + logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} does not contain an 'Installed' value so can't be a Steam Game."); + } } } } + + if (steamAppIdsInstalled.Count == 0) + { + // There aren't any game ids so return false + logger.Warn($"SteamLibrary/LoadInstalledGames: No Steam games installed in the Steam library"); + return false; + } + else + { + logger.Info($"SteamLibrary/LoadInstalledGames: Found {steamAppIdsInstalled.Count} installed games in the Steam library"); + } + } + else + { + // There isnt any steam registry key + logger.Warn($"SteamLibrary/LoadInstalledGames: Couldn't access the Steam Registry Key {_registrySteamKey}"); + return false; } } @@ -389,7 +433,7 @@ namespace DisplayMagician.GameLibraries var newAppInfo = new AppInfo(); newAppInfo.Read(appInfoVdfFile); - Debug.WriteLine($"{newAppInfo.Apps.Count} apps"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found {newAppInfo.Apps.Count} apps in the {appInfoVdfFile} VDF file"); // Chec through all the apps we've extracted foreach (var app in newAppInfo.Apps) @@ -411,28 +455,30 @@ namespace DisplayMagician.GameLibraries foreach (KVObject data in app.Data) { - //Debug.WriteLine($"App: {app.AppID} - Data.Name: {data.Name}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found App: {app.AppID} - Data.Name: {data.Name}"); if (data.Name == "common") { foreach (KVObject common in data.Children) { - //Debug.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}"); - if (common.Name == "name") { - Debug.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: name: App: {app.AppID} - Common {common.Name}: {common.Value}"); steamGameAppInfo.GameName = common.Value.ToString(); } else if (common.Name == "clienticon") { - Debug.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}"); + 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")); } else if (common.Name == "type") { - Debug.WriteLine($"App: {app.AppID} - Common {common.Name}: {common.Value}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: type: App: {app.AppID} - Common {common.Name}: {common.Value}"); + } + else + { + logger.Trace($"SteamLibrary/LoadInstalledGames: Found unrecognised line App: {app.AppID} - Common {common.Name}: {common.Value}"); } } } @@ -444,7 +490,7 @@ namespace DisplayMagician.GameLibraries if (config.Name == "installdir") { - Debug.WriteLine($"App: {detectedAppID} - Config {config.Name}: {config.Value}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found installdir App: {detectedAppID} - Config {config.Name}: {config.Value}"); steamGameAppInfo.GameInstallDir = config.Value.ToString(); } else if (config.Name == "launch") @@ -455,7 +501,7 @@ namespace DisplayMagician.GameLibraries { if (launch_num.Name == "executable") { - Debug.WriteLine($"App: {detectedAppID} - Config - Launch {launch.Name} - {launch_num.Name}: {launch_num.Value}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found launch executable App: {detectedAppID} - Config - Launch {launch.Name} - {launch_num.Name}: {launch_num.Value}"); steamGameAppInfo.GameExes.Add(launch_num.Value.ToString()); } @@ -470,11 +516,11 @@ namespace DisplayMagician.GameLibraries } catch (ArgumentException ex) { - Console.WriteLine($"SteamGame/GetAllInstalledGames exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); + logger.Warn(ex, $"SteamLibrary/LoadInstalledGames: ArgumentException while processing the {appInfoVdfFile} VDF file"); //we just want to ignore it if we try to add it twice.... } - Debug.WriteLine($"App: {detectedAppID} - Token: {app.Token}"); + logger.Trace($"SteamLibrary/LoadInstalledGames: Found end of loop App: {detectedAppID} - Token: {app.Token}"); } } @@ -485,6 +531,8 @@ namespace DisplayMagician.GameLibraries _steamConfigVdfFile = Path.Combine(_steamPath, "config", "config.vdf"); string steamConfigVdfText = File.ReadAllText(_steamConfigVdfFile, Encoding.UTF8); + logger.Trace($"SteamLibrary/LoadInstalledGames: Processing the {_steamConfigVdfFile} VDF file"); + List steamLibrariesPaths = new List(); // Now we have to parse the config.vdf looking for the location of the SteamLibraries // We look for lines similar to this: "BaseInstallFolder_1" "E:\\SteamLibrary" @@ -498,7 +546,7 @@ namespace DisplayMagician.GameLibraries if (steamLibraryMatch.Success) { string steamLibraryPath = Regex.Unescape(steamLibraryMatch.Groups[1].Value); - Debug.WriteLine($"Found steam library: {steamLibraryPath}"); + logger.Info($"SteamLibrary/LoadInstalledGames: Found steam library {steamLibraryPath}"); steamLibrariesPaths.Add(steamLibraryPath); } } @@ -512,6 +560,7 @@ namespace DisplayMagician.GameLibraries // Go through each app and extract it's details foreach (string steamLibraryAppManifestFilename in steamLibraryAppManifestFilenames) { + logger.Trace($"SteamLibrary/LoadInstalledGames: Found {steamLibraryAppManifestFilename} app manifest within steam library {steamLibraryPath}"); // Read in the contents of the file string steamLibraryAppManifestText = File.ReadAllText(steamLibraryAppManifestFilename); // Grab the appid from the file @@ -519,12 +568,13 @@ namespace DisplayMagician.GameLibraries Match appidMatches = appidRegex.Match(steamLibraryAppManifestText); if (appidMatches.Success) { - if (int.TryParse(appidMatches.Groups[1].Value, out int steamGameId)) { + 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)) { + logger.Trace($"SteamLibrary/LoadInstalledGames: Steam Game ID {steamGameId} is installed within steam library {steamLibraryPath}!"); // This game is an installed game! so we start to populate it with data! string steamGameExe = ""; @@ -533,6 +583,8 @@ 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 }"); + // 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) @@ -540,9 +592,11 @@ namespace DisplayMagician.GameLibraries foreach (string gameExe in steamAppInfo[steamGameId].GameExes) { 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; } } @@ -555,57 +609,59 @@ namespace DisplayMagician.GameLibraries if (File.Exists(steamAppInfo[steamGameId].GameSteamIconPath) && steamAppInfo[steamGameId].GameSteamIconPath.EndsWith(".ico")) { steamGameIconPath = steamAppInfo[steamGameId].GameSteamIconPath; + logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Icon Path {steamGameIconPath} for Steam Game ID {steamGameId} at {steamGameInstallDir }"); + } // If there isn't an icon for us to use, then we need to extract one from the Game Executables else if (!String.IsNullOrEmpty(steamGameExe)) { steamGameIconPath = steamGameExe; + logger.Debug($"SteamLibrary/LoadInstalledGames: Found Steam Game Icon Path {steamGameIconPath} for Steam Game ID {steamGameId} at {steamGameInstallDir }"); } // The absolute worst case means we don't have an icon to use. SO we use the Steam one. else { // And we have to make do with a Steam Icon + logger.Debug($"SteamLibrary/LoadInstalledGames: Couldn't find Steam Game Icon Path {steamGameIconPath} for Steam Game ID {steamGameId} so using default Steam Icon"); steamGameIconPath = _steamPath; } // And we add the Game to the list of games we have! _allSteamGames.Add(new SteamGame(steamGameId, steamGameName, steamGameExe, steamGameIconPath)); - + logger.Debug($"SteamLibrary/LoadInstalledGames: Adding Steam Game with game id {steamGameId}, name {steamGameName}, game exe {steamGameExe} and icon path {steamGameIconPath}"); } } } } } } + catch (ArgumentNullException ex) + { + logger.Warn(ex, "SteamLibrary/GetAllInstalledGames: An argument supplied to the function is null."); + } + catch (NotSupportedException ex) + { + logger.Warn(ex, "SteamLibrary/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, "SteamLibrary/GetAllInstalledGames: The path is longer than the maximum allowed by the operating system."); + } catch (SecurityException ex) { - Console.WriteLine($"SteamGame/GetAllInstalledGames securityexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; - } - catch (UnauthorizedAccessException ex) - { - Console.WriteLine($"SteamGame/GetAllInstalledGames unauthorizedaccessexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("UnauthorizedAccessException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, "SteamLibrary/GetAllInstalledGames: The user does not have the permissions required to read the Uplay InstallDir registry key."); } catch (ObjectDisposedException ex) { - Console.WriteLine($"SteamGame/GetAllInstalledGames objectdisposedexceptions: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("ObjectDisposedException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, "SteamLibrary/GetAllInstalledGames: The Microsoft.Win32.RegistryKey is closed when trying to access the Uplay InstallDir registry key (closed keys cannot be accessed)."); } catch (IOException ex) { - Console.WriteLine($"SteamGame/GetAllInstalledGames ioexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - // Extract some information from this exception, and then - // throw it to the parent method. - if (ex.Source != null) - Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, "SteamLibrary/GetAllInstalledGames: The Uplay InstallDir registry key has been marked for deletion so we cannot access the value dueing the UplayLibrary check."); + } + catch (UnauthorizedAccessException ex) + { + logger.Warn(ex, "SteamLibrary/GetAllInstalledGames: The user does not have the necessary registry rights to check whether Uplay is installed."); } return true; diff --git a/DisplayMagician/GameLibraries/UplayLibrary.cs b/DisplayMagician/GameLibraries/UplayLibrary.cs index bee23b8..1cbf51e 100644 --- a/DisplayMagician/GameLibraries/UplayLibrary.cs +++ b/DisplayMagician/GameLibraries/UplayLibrary.cs @@ -41,6 +41,7 @@ namespace DisplayMagician.GameLibraries { try { + logger.Trace($"UplayLibrary/UplayLibrary: Uplay launcher registry key = HKLM\\{registryUplayLauncherKey}"); // Find the UplayExe location, and the UplayPath for later RegistryKey uplayInstallKey = Registry.LocalMachine.OpenSubKey(registryUplayLauncherKey, RegistryKeyPermissionCheck.ReadSubTree); if (uplayInstallKey == null) @@ -177,8 +178,7 @@ namespace DisplayMagician.GameLibraries { logger.Debug($"UplayLibrary/RemoveUplayGame: Didn't remove Uplay game with ID {uplayGame.Name} from the Uplay Library"); return false; - } - + } else throw new UplayLibraryException(); } @@ -343,11 +343,63 @@ namespace DisplayMagician.GameLibraries if (!_isUplayInstalled) { // Uplay isn't installed, so we return an empty list. - logger.Debug($"UplayLibrary/LoadInstalledGames: Uplay library is not installed, so returning false"); + logger.Info($"UplayLibrary/LoadInstalledGames: Uplay library is not installed"); return false; } + logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Game Installs Registry Key = HKLM\\{registryUplayInstallsKey}"); + using (RegistryKey uplayInstallKey = Registry.LocalMachine.OpenSubKey(registryUplayInstallsKey, RegistryKeyPermissionCheck.ReadSubTree)) + { + if (uplayInstallKey != null) + { + int uplayGamesInstalledCount = 0; + // Loop through the subKeys as they are the Steam Game IDs + foreach (string uplayGameKeyName in uplayInstallKey.GetSubKeyNames()) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameKeyName = {uplayGameKeyName}"); + if (int.TryParse(uplayGameKeyName, out int uplayGameId)) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameKeyName is an int, so trying to see if it is a game"); + string uplayGameKeyFullName = $"{registryUplayInstallsKey}\\{uplayGameKeyName}"; + using (RegistryKey uplayGameKey = Registry.LocalMachine.OpenSubKey(uplayGameKeyFullName, RegistryKeyPermissionCheck.ReadSubTree)) + { + // If the Installed Value is set to 1, then the game is installed + // We want to keep track of that for later + if (!uplayGameKey.GetValue(@"InstallDir", "").ToString().Equals("")) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: {uplayGameKey} contains an 'InstallDir' value so is an installed Uplay Game."); + // Add this Steam App ID to the list we're keeping for later + uplayGamesInstalledCount++; + } + else + { + logger.Trace($"UplayLibrary/LoadInstalledGames: {uplayGameKey} does not contain an 'Installed' value so can't be a Uplay Game."); + } + + } + } + } + + if (uplayGamesInstalledCount == 0) + { + // There aren't any game ids so return false + logger.Warn($"UplayLibrary/LoadInstalledGames: No Uplay games installed in the Uplay library"); + return false; + } + else + { + logger.Info($"UplayLibrary/LoadInstalledGames: Found {uplayGamesInstalledCount} installed games in the Uplay library"); + } + + } + else + { + // There isnt any Uplay registry key + logger.Warn($"UplayLibrary/LoadInstalledGames: Couldn't access the Uplay Registry Key {registryUplayInstallsKey}"); + return false; + } + } // Look in HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Ubisoft\\Launcher and check the InstallDir key // That returns the location of the install dir : E:\Program Files (x86)\Ubisoft\Ubisoft Game Launcher\ @@ -431,7 +483,11 @@ namespace DisplayMagician.GameLibraries { // Stop this loop once we have both filname and gameid if (gotGameFileName && gotGameId && gotGameIconPath && gotGameName) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: We got all the entries: gameFileName = {gameFileName } && gameId = {gameId } && gameIconPath = {uplayGameAppInfo.GameUplayIconPath} && gameName = {uplayGameAppInfo.GameName}"); break; + } + // This line contains the Game Name if (uplayEntryLines[i].StartsWith(" name:", StringComparison.OrdinalIgnoreCase) && !gotGameName) { @@ -442,6 +498,7 @@ namespace DisplayMagician.GameLibraries { uplayGameAppInfo.GameName = localizations[uplayGameAppInfo.GameName]; } + logger.Trace($"UplayLibrary/LoadInstalledGames: Found uplayGameAppInfo.GameName = {uplayGameAppInfo.GameName}"); gotGameName = true; } else if (uplayEntryLines[i].StartsWith(" icon_image:", StringComparison.OrdinalIgnoreCase) && !gotGameIconPath) @@ -452,12 +509,14 @@ namespace DisplayMagician.GameLibraries if (localizations.ContainsKey(iconImageFileName)) { iconImageFileName = localizations[iconImageFileName]; + logger.Trace($"UplayLibrary/LoadInstalledGames: Found iconImageFile = {iconImageFileName }"); } //61fdd16f06ae08158d0a6d476f1c6bd5.ico 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 }"); } gotGameIconPath = true; } @@ -467,6 +526,7 @@ namespace DisplayMagician.GameLibraries mc = Regex.Matches(uplayEntryLines[i], @"relative: (.*)"); gameFileName = mc[0].Groups[1].ToString(); gotGameFileName = true; + logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameFileName = {gameFileName}"); } // This line contains the registryKey else if (uplayEntryLines[i].StartsWith(" register: HKEY_LOCAL_MACHINE") && !gotGameId) @@ -475,6 +535,7 @@ namespace DisplayMagician.GameLibraries mc = Regex.Matches(uplayEntryLines[i], @"Installs\\(\d+)\\InstallDir"); gameId = mc[0].Groups[1].ToString(); gotGameId = true; + logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameId = {gameId}"); } } @@ -510,6 +571,7 @@ 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}"); } } diff --git a/DisplayMagician/Program.cs b/DisplayMagician/Program.cs index e4e41a0..e6d0bbc 100644 --- a/DisplayMagician/Program.cs +++ b/DisplayMagician/Program.cs @@ -722,7 +722,6 @@ namespace DisplayMagician { if (!DisplayMagician.GameLibraries.SteamLibrary.LoadInstalledGames()) { logger.Info($"Program/LoadGamesInBackground: Cannot load installed Steam Games!"); - throw new LoadingInstalledGamesException("Program/LoadGamesInBackground: Cannot load installed Steam Games!"); } Console.WriteLine("Done."); logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Steam Games (found {GameLibraries.SteamLibrary.InstalledSteamGameCount})"); @@ -746,7 +745,6 @@ namespace DisplayMagician { if (!DisplayMagician.GameLibraries.UplayLibrary.LoadInstalledGames()) { logger.Info($"Program/LoadGamesInBackground: Cannot load installed Uplay Games!"); - throw new LoadingInstalledGamesException("Program/LoadGamesInBackground: Cannot load installed Uplay Games!"); } Console.WriteLine("Done."); logger.Info($"Program/LoadGamesInBackground: Loaded all Installed Uplay Games (found {GameLibraries.UplayLibrary.InstalledUplayGameCount})"); diff --git a/DisplayMagician/Properties/AssemblyInfo.cs b/DisplayMagician/Properties/AssemblyInfo.cs index cba880a..d77b7de 100644 --- a/DisplayMagician/Properties/AssemblyInfo.cs +++ b/DisplayMagician/Properties/AssemblyInfo.cs @@ -37,8 +37,8 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.3.*")] -[assembly: AssemblyFileVersion("1.0.3.0")] +[assembly: AssemblyVersion("1.0.3.1")] +[assembly: AssemblyFileVersion("1.0.3.1")] [assembly: NeutralResourcesLanguage("en")] [assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi b/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi index ac73b2c..34efacc 100644 --- a/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi +++ b/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi @@ -10,6 +10,14 @@ + + + + + + + + - - + + + - - NOT NEWER_VERSION_FOUND + + + + + From 15a80ff0ac850dbf1d06e5f3ecfe566dcc73ffb8 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Fri, 9 Apr 2021 18:52:05 +1200 Subject: [PATCH 04/16] Fixed Steam library passing Steam library processing was missing the default steam library. This meant that only people with additional steam libraries were detecting games. This has been fixed now. Added in some more TRACE logging for Steam and for Uplay libraries. --- DisplayMagician/GameLibraries/SteamLibrary.cs | 33 ++++++++++++------- DisplayMagician/GameLibraries/UplayLibrary.cs | 2 ++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/DisplayMagician/GameLibraries/SteamLibrary.cs b/DisplayMagician/GameLibraries/SteamLibrary.cs index f4694e3..0ac2fa5 100644 --- a/DisplayMagician/GameLibraries/SteamLibrary.cs +++ b/DisplayMagician/GameLibraries/SteamLibrary.cs @@ -381,7 +381,7 @@ namespace DisplayMagician.GameLibraries logger.Trace($"SteamLibrary/LoadInstalledGames: Found SteamGameKeyName = {steamGameKeyName}"); if (int.TryParse(steamGameKeyName, out int steamAppId)) { - logger.Trace($"SteamLibrary/LoadInstalledGames: SteamGameKeyName is an int, so trying to see if it is a game"); + logger.Trace($"SteamLibrary/LoadInstalledGames: SteamGameKeyName is an int, so trying to see if it is an installed app"); string steamGameKeyFullName = $"{_registryAppsKey}\\{steamGameKeyName}"; using (RegistryKey steamGameKey = Registry.CurrentUser.OpenSubKey(steamGameKeyFullName, RegistryKeyPermissionCheck.ReadSubTree)) { @@ -389,13 +389,13 @@ namespace DisplayMagician.GameLibraries // We want to keep track of that for later if ((int)steamGameKey.GetValue(@"Installed", 0) == 1) { - logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} contains an 'Installed' value so is an installed Steam Game."); + logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} contains an 'Installed' value so is an installed Steam App."); // Add this Steam App ID to the list we're keeping for later steamAppIdsInstalled.Add(steamAppId); } else { - logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} does not contain an 'Installed' value so can't be a Steam Game."); + logger.Trace($"SteamLibrary/LoadInstalledGames: {steamGameKeyFullName} does not contain an 'Installed' value so can't be a Steam App."); } } @@ -409,10 +409,7 @@ namespace DisplayMagician.GameLibraries logger.Warn($"SteamLibrary/LoadInstalledGames: No Steam games installed in the Steam library"); return false; } - else - { - logger.Info($"SteamLibrary/LoadInstalledGames: Found {steamAppIdsInstalled.Count} installed games in the Steam library"); - } + } else { @@ -452,6 +449,7 @@ namespace DisplayMagician.GameLibraries GameID = detectedAppID, GameExes = new List() }; + string steamAppType = ""; foreach (KVObject data in app.Data) { @@ -475,6 +473,7 @@ namespace DisplayMagician.GameLibraries else if (common.Name == "type") { logger.Trace($"SteamLibrary/LoadInstalledGames: type: App: {app.AppID} - Common {common.Name}: {common.Value}"); + steamAppType = common.Value.ToString(); } else { @@ -512,7 +511,13 @@ namespace DisplayMagician.GameLibraries } } - steamAppInfo.Add(detectedAppID, steamGameAppInfo); + // Only store the app if it's a game! + if (steamAppType.Equals("Game",StringComparison.OrdinalIgnoreCase)) + { + steamAppInfo.Add(detectedAppID, steamGameAppInfo); + logger.Trace($"SteamLibrary/LoadInstalledGames: Adding Game with ID {detectedAppID} to the list of games"); + } + } catch (ArgumentException ex) { @@ -526,6 +531,7 @@ namespace DisplayMagician.GameLibraries + // Now we access the config.vdf that lives in the Steam Config file, as that lists all // the SteamLibraries. We need to find out where they areso we can interrogate them _steamConfigVdfFile = Path.Combine(_steamPath, "config", "config.vdf"); @@ -534,7 +540,11 @@ namespace DisplayMagician.GameLibraries logger.Trace($"SteamLibrary/LoadInstalledGames: Processing the {_steamConfigVdfFile} VDF file"); List steamLibrariesPaths = new List(); - // Now we have to parse the config.vdf looking for the location of the SteamLibraries + // We add the default library which is based on where Steam was installed + logger.Info($"SteamLibrary/LoadInstalledGames: Found original steam library {_steamPath}"); + steamLibrariesPaths.Add(_steamPath); + + // Now we have to parse the config.vdf looking for the location of any additional SteamLibraries // We look for lines similar to this: "BaseInstallFolder_1" "E:\\SteamLibrary" // There may be multiple so we need to check the whole file Regex steamLibrariesRegex = new Regex(@"""BaseInstallFolder_\d+""\s+""(.*)""", RegexOptions.IgnoreCase); @@ -546,7 +556,7 @@ namespace DisplayMagician.GameLibraries if (steamLibraryMatch.Success) { string steamLibraryPath = Regex.Unescape(steamLibraryMatch.Groups[1].Value); - logger.Info($"SteamLibrary/LoadInstalledGames: Found steam library {steamLibraryPath}"); + logger.Info($"SteamLibrary/LoadInstalledGames: Found additional steam library {steamLibraryPath}"); steamLibrariesPaths.Add(steamLibraryPath); } } @@ -632,8 +642,9 @@ namespace DisplayMagician.GameLibraries } } } - } + } } + logger.Info($"SteamLibrary/LoadInstalledGames: Found {_allSteamGames.Count} installed Steam games"); } catch (ArgumentNullException ex) { diff --git a/DisplayMagician/GameLibraries/UplayLibrary.cs b/DisplayMagician/GameLibraries/UplayLibrary.cs index 1cbf51e..714ecaf 100644 --- a/DisplayMagician/GameLibraries/UplayLibrary.cs +++ b/DisplayMagician/GameLibraries/UplayLibrary.cs @@ -574,6 +574,8 @@ namespace DisplayMagician.GameLibraries logger.Debug($"UplayLibrary/LoadInstalledGames: Adding Uplay Game with game id {uplayGameAppInfo.GameID}, name {uplayGameAppInfo.GameName}, game exe {uplayGameAppInfo.GameExe} and icon path {uplayGameAppInfo.GameUplayIconPath}"); } + logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allUplayGames.Count} installed Uplay games"); + } catch (ArgumentNullException ex) From c799121a771c46423707e29c41ff201d809228fe Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Fri, 9 Apr 2021 20:21:02 +1200 Subject: [PATCH 05/16] Testing WINAPI device recognition Tests to make sure the WINAP display detection and recognition are working as expected. They tested fine. --- DisplayMagicianShared/ProfileRepository.cs | 222 +++++++++++---------- 1 file changed, 112 insertions(+), 110 deletions(-) diff --git a/DisplayMagicianShared/ProfileRepository.cs b/DisplayMagicianShared/ProfileRepository.cs index e7f23e5..9014e48 100644 --- a/DisplayMagicianShared/ProfileRepository.cs +++ b/DisplayMagicianShared/ProfileRepository.cs @@ -792,6 +792,7 @@ namespace DisplayMagicianShared } if (isNvidia && myPhysicalGPUs != null && myPhysicalGPUs.Length > 0) + //if (false) { SharedLogger.logger.Debug($"ProfileRepository/GenerateProfileDisplayIdentifiers: We were able to GetPhysicalCPUs through NvAPIWrapper library. There are {myPhysicalGPUs.Length} Physical GPUs detected"); @@ -847,46 +848,46 @@ namespace DisplayMagicianShared PathDisplaySource pathDisplaySource = attachedDisplay.ToPathDisplaySource(); PathDisplayTarget pathDisplayTarget = attachedDisplay.ToPathDisplayTarget(); - Debug.WriteLine($"ADDN : {attachedDisplay.DeviceName}"); - Debug.WriteLine($"ADDFN : {attachedDisplay.DisplayFullName}"); - Debug.WriteLine($"ADDIN : {attachedDisplay.DisplayName}"); - Debug.WriteLine($"ADDIN : {attachedDisplay.IsAvailable}"); - Debug.WriteLine($"ADDIGP : {attachedDisplay.IsGDIPrimary}"); - Debug.WriteLine($"ADDIV : {attachedDisplay.IsValid}"); - Debug.WriteLine($"ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}"); - Debug.WriteLine($"ADCSF : {attachedDisplay.CurrentSetting.Frequency}"); - Debug.WriteLine($"ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}"); - Debug.WriteLine($"ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}"); - Debug.WriteLine($"ADCSO : {attachedDisplay.CurrentSetting.Orientation}"); - Debug.WriteLine($"ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}"); - Debug.WriteLine($"ADCSP : {attachedDisplay.CurrentSetting.Position}"); - Debug.WriteLine($"ADCSR : {attachedDisplay.CurrentSetting.Resolution}"); - Debug.WriteLine($"DP : {displayAdapter.DevicePath}"); - Debug.WriteLine($"DK : {displayAdapter.DeviceKey}"); - Debug.WriteLine($"DN : {displayAdapter.DeviceName}"); - Debug.WriteLine($"DK : {displayAdapter.DeviceKey}"); - Debug.WriteLine($"AI : {pathDisplayAdapter.AdapterId}"); - Debug.WriteLine($"AIDP : {pathDisplayAdapter.DevicePath}"); - Debug.WriteLine($"AIII : {pathDisplayAdapter.IsInvalid}"); - Debug.WriteLine($"DDA : {displayAdapter.DeviceName}"); - Debug.WriteLine($"PDSA : {pathDisplaySource.Adapter}"); - Debug.WriteLine($"PDSCDS : {pathDisplaySource.CurrentDPIScale}"); - Debug.WriteLine($"PDSDN : {pathDisplaySource.DisplayName}"); - Debug.WriteLine($"PDSMDS : {pathDisplaySource.MaximumDPIScale}"); - Debug.WriteLine($"PDSRDS : {pathDisplaySource.RecommendedDPIScale}"); - Debug.WriteLine($"PDSSI : {pathDisplaySource.SourceId}"); - Debug.WriteLine($"PDTA : {pathDisplayTarget.Adapter}"); - Debug.WriteLine($"PDTCI : {pathDisplayTarget.ConnectorInstance}"); - Debug.WriteLine($"PDTDP : {pathDisplayTarget.DevicePath}"); - Debug.WriteLine($"PDTEMC : {pathDisplayTarget.EDIDManufactureCode}"); - Debug.WriteLine($"PDTEMI : {pathDisplayTarget.EDIDManufactureId}"); - Debug.WriteLine($"PDTEPC : {pathDisplayTarget.EDIDProductCode}"); - Debug.WriteLine($"PDTFN : {pathDisplayTarget.FriendlyName}"); - Debug.WriteLine($"PDTIA : {pathDisplayTarget.IsAvailable}"); - Debug.WriteLine($"PDTPR : {pathDisplayTarget.PreferredResolution}"); - Debug.WriteLine($"PDTPSM : {pathDisplayTarget.PreferredSignalMode}"); - Debug.WriteLine($"PDTTI : {pathDisplayTarget.TargetId}"); - Debug.WriteLine($"PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}"); + 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}"); // Create an array of all the important display info we need to record string[] displayInfo = { @@ -937,6 +938,7 @@ namespace DisplayMagicianShared } if (isNvidia && myPhysicalGPUs != null && myPhysicalGPUs.Length > 0) + //if (false) { SharedLogger.logger.Debug($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: We were able to GetPhysicalCPUs through NvAPIWrapper library. There are {myPhysicalGPUs.Length} Physical GPUs detected"); @@ -995,46 +997,46 @@ namespace DisplayMagicianShared PathDisplaySource pathDisplaySource = attachedDisplay.ToPathDisplaySource(); PathDisplayTarget pathDisplayTarget = attachedDisplay.ToPathDisplayTarget(); - Debug.WriteLine($"ADDN : {attachedDisplay.DeviceName}"); - Debug.WriteLine($"ADDFN : {attachedDisplay.DisplayFullName}"); - Debug.WriteLine($"ADDIN : {attachedDisplay.DisplayName}"); - Debug.WriteLine($"ADDIN : {attachedDisplay.IsAvailable}"); - Debug.WriteLine($"ADDIGP : {attachedDisplay.IsGDIPrimary}"); - Debug.WriteLine($"ADDIV : {attachedDisplay.IsValid}"); - Debug.WriteLine($"ADCSCD : {attachedDisplay.CurrentSetting.ColorDepth}"); - Debug.WriteLine($"ADCSF : {attachedDisplay.CurrentSetting.Frequency}"); - Debug.WriteLine($"ADCSIE : {attachedDisplay.CurrentSetting.IsEnable}"); - Debug.WriteLine($"ADCSII : {attachedDisplay.CurrentSetting.IsInterlaced}"); - Debug.WriteLine($"ADCSO : {attachedDisplay.CurrentSetting.Orientation}"); - Debug.WriteLine($"ADCSOSM : {attachedDisplay.CurrentSetting.OutputScalingMode}"); - Debug.WriteLine($"ADCSP : {attachedDisplay.CurrentSetting.Position}"); - Debug.WriteLine($"ADCSR : {attachedDisplay.CurrentSetting.Resolution}"); - Debug.WriteLine($"DP : {displayAdapter.DevicePath}"); - Debug.WriteLine($"DK : {displayAdapter.DeviceKey}"); - Debug.WriteLine($"DN : {displayAdapter.DeviceName}"); - Debug.WriteLine($"DK : {displayAdapter.DeviceKey}"); - Debug.WriteLine($"AI : {pathDisplayAdapter.AdapterId}"); - Debug.WriteLine($"AIDP : {pathDisplayAdapter.DevicePath}"); - Debug.WriteLine($"AIII : {pathDisplayAdapter.IsInvalid}"); - Debug.WriteLine($"DDA : {displayAdapter.DeviceName}"); - Debug.WriteLine($"PDSA : {pathDisplaySource.Adapter}"); - Debug.WriteLine($"PDSCDS : {pathDisplaySource.CurrentDPIScale}"); - Debug.WriteLine($"PDSDN : {pathDisplaySource.DisplayName}"); - Debug.WriteLine($"PDSMDS : {pathDisplaySource.MaximumDPIScale}"); - Debug.WriteLine($"PDSRDS : {pathDisplaySource.RecommendedDPIScale}"); - Debug.WriteLine($"PDSSI : {pathDisplaySource.SourceId}"); - Debug.WriteLine($"PDTA : {pathDisplayTarget.Adapter}"); - Debug.WriteLine($"PDTCI : {pathDisplayTarget.ConnectorInstance}"); - Debug.WriteLine($"PDTDP : {pathDisplayTarget.DevicePath}"); - Debug.WriteLine($"PDTEMC : {pathDisplayTarget.EDIDManufactureCode}"); - Debug.WriteLine($"PDTEMI : {pathDisplayTarget.EDIDManufactureId}"); - Debug.WriteLine($"PDTEPC : {pathDisplayTarget.EDIDProductCode}"); - Debug.WriteLine($"PDTFN : {pathDisplayTarget.FriendlyName}"); - Debug.WriteLine($"PDTIA : {pathDisplayTarget.IsAvailable}"); - Debug.WriteLine($"PDTPR : {pathDisplayTarget.PreferredResolution}"); - Debug.WriteLine($"PDTPSM : {pathDisplayTarget.PreferredSignalMode}"); - Debug.WriteLine($"PDTTI : {pathDisplayTarget.TargetId}"); - Debug.WriteLine($"PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}"); + 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}"); // Create an array of all the important display info we need to record string[] displayInfo = { @@ -1063,36 +1065,36 @@ namespace DisplayMagicianShared PathDisplaySource pathDisplaySource = unattachedDisplay.ToPathDisplaySource(); PathDisplayTarget pathDisplayTarget = unattachedDisplay.ToPathDisplayTarget(); - Debug.WriteLine($"ADDN : {unattachedDisplay.DeviceName}"); - Debug.WriteLine($"ADDFN : {unattachedDisplay.DisplayFullName}"); - Debug.WriteLine($"ADDIN : {unattachedDisplay.DisplayName}"); - Debug.WriteLine($"ADDIN : {unattachedDisplay.IsAvailable}"); - Debug.WriteLine($"ADDIV : {unattachedDisplay.IsValid}"); - Debug.WriteLine($"DP : {displayAdapter.DevicePath}"); - Debug.WriteLine($"DK : {displayAdapter.DeviceKey}"); - Debug.WriteLine($"DN : {displayAdapter.DeviceName}"); - Debug.WriteLine($"DK : {displayAdapter.DeviceKey}"); - Debug.WriteLine($"AI : {pathDisplayAdapter.AdapterId}"); - Debug.WriteLine($"AIDP : {pathDisplayAdapter.DevicePath}"); - Debug.WriteLine($"AIII : {pathDisplayAdapter.IsInvalid}"); - Debug.WriteLine($"PDSA : {pathDisplaySource.Adapter}"); - Debug.WriteLine($"PDSCDS : {pathDisplaySource.CurrentDPIScale}"); - Debug.WriteLine($"PDSDN : {pathDisplaySource.DisplayName}"); - Debug.WriteLine($"PDSMDS : {pathDisplaySource.MaximumDPIScale}"); - Debug.WriteLine($"PDSRDS : {pathDisplaySource.RecommendedDPIScale}"); - Debug.WriteLine($"PDSSI : {pathDisplaySource.SourceId}"); - Debug.WriteLine($"PDTA : {pathDisplayTarget.Adapter}"); - Debug.WriteLine($"PDTCI : {pathDisplayTarget.ConnectorInstance}"); - Debug.WriteLine($"PDTDP : {pathDisplayTarget.DevicePath}"); - Debug.WriteLine($"PDTEMC : {pathDisplayTarget.EDIDManufactureCode}"); - Debug.WriteLine($"PDTEMI : {pathDisplayTarget.EDIDManufactureId}"); - Debug.WriteLine($"PDTEPC : {pathDisplayTarget.EDIDProductCode}"); - Debug.WriteLine($"PDTFN : {pathDisplayTarget.FriendlyName}"); - Debug.WriteLine($"PDTIA : {pathDisplayTarget.IsAvailable}"); - Debug.WriteLine($"PDTPR : {pathDisplayTarget.PreferredResolution}"); - Debug.WriteLine($"PDTPSM : {pathDisplayTarget.PreferredSignalMode}"); - Debug.WriteLine($"PDTTI : {pathDisplayTarget.TargetId}"); - Debug.WriteLine($"PDTVRS : {pathDisplayTarget.VirtualResolutionSupport}"); + SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDN : {unattachedDisplay.DeviceName}"); + SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDFN : {unattachedDisplay.DisplayFullName}"); + SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {unattachedDisplay.DisplayName}"); + SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIN : {unattachedDisplay.IsAvailable}"); + SharedLogger.logger.Trace($"ProfileRepository/GenerateAllAvailableDisplayIdentifiers: ADDIV : {unattachedDisplay.IsValid}"); + 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: 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}"); // Create an array of all the important display info we need to record string[] displayInfo = { From 07f328b8901fe276d0e60d851d07cc204ccb8fcd Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 10:51:20 +1200 Subject: [PATCH 06/16] Fixing ShortcutForm audio config Added more robustness and error checks to handle AudioSwitcher not being able to detect chipsets, and to cope with situations with no active audio or capture devices. Should be much more robust as it also handles exceptions better, and has better error logging. --- DisplayMagician/ShortcutItem.cs | 185 ++++--- DisplayMagician/ShortcutRepository.cs | 332 ++++++++----- .../UIForms/ShortcutForm.Designer.cs | 160 ++++-- DisplayMagician/UIForms/ShortcutForm.cs | 463 +++++++++++------- 4 files changed, 713 insertions(+), 427 deletions(-) diff --git a/DisplayMagician/ShortcutItem.cs b/DisplayMagician/ShortcutItem.cs index fb1f789..beff4ab 100644 --- a/DisplayMagician/ShortcutItem.cs +++ b/DisplayMagician/ShortcutItem.cs @@ -14,6 +14,7 @@ using System.Windows.Forms; using System.Text.RegularExpressions; using IWshRuntimeLibrary; using AudioSwitcher.AudioApi.CoreAudio; +using AudioSwitcher.AudioApi; namespace DisplayMagician { @@ -2090,87 +2091,135 @@ namespace DisplayMagician } } // Check the Audio Device is still valid (if one is specified) + CoreAudioController audioController = ShortcutRepository.AudioController; if (ChangeAudioDevice) { - CoreAudioController audioController = ShortcutRepository.AudioController; - IEnumerable audioDevices = audioController.GetPlaybackDevices(); - foreach (CoreAudioDevice audioDevice in audioDevices) + IEnumerable audioDevices = null; + if (audioController != null) { - if (audioDevice.FullName.Equals(AudioDevice)) + try { - if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.Disabled) - { - ShortcutError error = new ShortcutError(); - error.Name = "AudioDeviceDisabled"; - error.Validity = ShortcutValidity.Warning; - error.Message = $"The Audio Device { AudioDevice} is disabled, so the shortcut '{Name}' cannot be used.You need to enable the audio device to use this shortcut, or edit the shortcut to change the audio device."; - _shortcutErrors.Add(error); - if (worstError != ShortcutValidity.Error) - worstError = ShortcutValidity.Warning; - } - if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.NotPresent) - { - ShortcutError error = new ShortcutError(); - error.Name = "AudioDeviceNotPresent"; - error.Validity = ShortcutValidity.Error; - error.Message = $"The Audio Device {AudioDevice} is not present, so the shortcut '{Name}' cannot be used."; - _shortcutErrors.Add(error); - if (worstError != ShortcutValidity.Error) - worstError = ShortcutValidity.Error; - } - if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.Unplugged) - { - ShortcutError error = new ShortcutError(); - error.Name = "AudioDeviceUnplugged"; - error.Validity = ShortcutValidity.Warning; - error.Message = $"The Audio Device {AudioDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the audio device to use this shortcut, or edit the shortcut to change the audio device."; - _shortcutErrors.Add(error); - if (worstError != ShortcutValidity.Error) - worstError = ShortcutValidity.Warning; - } + audioDevices = audioController.GetPlaybackDevices(); } + catch (Exception ex) + { + logger.Warn(ex, $"ShortcutRepository/RefreshValidity: Exception trying to get all playback devices!"); + } + if (audioDevices != null) + { + foreach (CoreAudioDevice audioDevice in audioDevices) + { + if (audioDevice.FullName.Equals(AudioDevice)) + { + if (audioDevice.State == DeviceState.Disabled) + { + ShortcutError error = new ShortcutError(); + error.Name = "AudioDeviceDisabled"; + error.Validity = ShortcutValidity.Warning; + error.Message = $"The Audio Device { AudioDevice} is disabled, so the shortcut '{Name}' cannot be used.You need to enable the audio device to use this shortcut, or edit the shortcut to change the audio device."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Warning; + } + if (audioDevice.State == DeviceState.NotPresent) + { + ShortcutError error = new ShortcutError(); + error.Name = "AudioDeviceNotPresent"; + error.Validity = ShortcutValidity.Error; + error.Message = $"The Audio Device {AudioDevice} is not present, so the shortcut '{Name}' cannot be used."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Error; + } + if (audioDevice.State == DeviceState.Unplugged) + { + ShortcutError error = new ShortcutError(); + error.Name = "AudioDeviceUnplugged"; + error.Validity = ShortcutValidity.Warning; + error.Message = $"The Audio Device {AudioDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the audio device to use this shortcut, or edit the shortcut to change the audio device."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Warning; + } + } + } + } + } + else + { + ShortcutError error = new ShortcutError(); + error.Name = "AudioChipsetNotSupported"; + error.Validity = ShortcutValidity.Warning; + error.Message = $"The Audio chipset isn't supported by DisplayMagician. You need to edit the shortcut to not change the audio output settings."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Warning; } } // Check the Capture Device is still valid (if one is specified) if (ChangeCaptureDevice) { - CoreAudioController audioController = ShortcutRepository.AudioController; - IEnumerable captureDevices = audioController.GetCaptureDevices(); - foreach (CoreAudioDevice captureDevice in captureDevices) + IEnumerable captureDevices = null; + if (audioController != null) { - if (captureDevice.FullName.Equals(CaptureDevice)) + try { - if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.Disabled) - { - ShortcutError error = new ShortcutError(); - error.Name = "CaptureDeviceDisabled"; - error.Validity = ShortcutValidity.Warning; - error.Message = $"The Capture Device {CaptureDevice} is disabled, so the shortcut '{Name}' cannot be used. You need to enable the capture device to use this shortcut, or edit the shortcut to change the capture device."; - _shortcutErrors.Add(error); - if (worstError != ShortcutValidity.Error) - worstError = ShortcutValidity.Warning; - } - if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.NotPresent) - { - ShortcutError error = new ShortcutError(); - error.Name = "CaptureDeviceNotPresent"; - error.Validity = ShortcutValidity.Error; - error.Message = $"The Capture Device {CaptureDevice} is not present, so the shortcut '{Name}' cannot be used."; - _shortcutErrors.Add(error); - if (worstError != ShortcutValidity.Error) - worstError = ShortcutValidity.Error; - } - if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.Unplugged) - { - ShortcutError error = new ShortcutError(); - error.Name = "CaptureDeviceUnplugged"; - error.Validity = ShortcutValidity.Warning; - error.Message = $"The Capture Device {CaptureDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the capture device to use this shortcut, or edit the shortcut to change the capture device."; - _shortcutErrors.Add(error); - if (worstError != ShortcutValidity.Error) - worstError = ShortcutValidity.Warning; - } + captureDevices = audioController.GetCaptureDevices(); } + catch(Exception ex) + { + logger.Warn(ex, $"ShortcutRepository/RefreshValidity: Exception trying to get all capture devices!"); + } + + if (captureDevices != null) + { + foreach (CoreAudioDevice captureDevice in captureDevices) + { + if (captureDevice.FullName.Equals(CaptureDevice)) + { + if (captureDevice.State == DeviceState.Disabled) + { + ShortcutError error = new ShortcutError(); + error.Name = "CaptureDeviceDisabled"; + error.Validity = ShortcutValidity.Warning; + error.Message = $"The Capture Device {CaptureDevice} is disabled, so the shortcut '{Name}' cannot be used. You need to enable the capture device to use this shortcut, or edit the shortcut to change the capture device."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Warning; + } + if (captureDevice.State == DeviceState.NotPresent) + { + ShortcutError error = new ShortcutError(); + error.Name = "CaptureDeviceNotPresent"; + error.Validity = ShortcutValidity.Error; + error.Message = $"The Capture Device {CaptureDevice} is not present, so the shortcut '{Name}' cannot be used."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Error; + } + if (captureDevice.State == DeviceState.Unplugged) + { + ShortcutError error = new ShortcutError(); + error.Name = "CaptureDeviceUnplugged"; + error.Validity = ShortcutValidity.Warning; + error.Message = $"The Capture Device {CaptureDevice} is unplugged, so the shortcut '{Name}' cannot be used. You need to plug in the capture device to use this shortcut, or edit the shortcut to change the capture device."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Warning; + } + } + } + } + } + else + { + ShortcutError error = new ShortcutError(); + error.Name = "AudioChipsetNotSupported"; + error.Validity = ShortcutValidity.Warning; + error.Message = $"The Audio chipset isn't supported by DisplayMagician. You need to edit the shortcut to not change the microphone input settings."; + _shortcutErrors.Add(error); + if (worstError != ShortcutValidity.Error) + worstError = ShortcutValidity.Warning; } } diff --git a/DisplayMagician/ShortcutRepository.cs b/DisplayMagician/ShortcutRepository.cs index ea75329..3ddc086 100644 --- a/DisplayMagician/ShortcutRepository.cs +++ b/DisplayMagician/ShortcutRepository.cs @@ -1,4 +1,5 @@ -using AudioSwitcher.AudioApi.CoreAudio; +using AudioSwitcher.AudioApi; +using AudioSwitcher.AudioApi.CoreAudio; using DisplayMagician.GameLibraries; using DisplayMagician.InterProcess; using DisplayMagicianShared; @@ -44,35 +45,24 @@ namespace DisplayMagician try { NvAPIWrapper.NVIDIA.Initialize(); - _audioController = new CoreAudioController(); - - // Create the Profile Storage Path if it doesn't exist so that it's avilable for all the program - if (!Directory.Exists(AppShortcutStoragePath)) - { - Directory.CreateDirectory(AppShortcutStoragePath); - } - } - catch (UnauthorizedAccessException ex) - { - logger.Error(ex, $"ShortcutRepository/ShortcutRepository: DisplayMagician doesn't have permissions to create the Shortcut storage folder {AppShortcutStoragePath}."); - } - catch (ArgumentException ex) - { - logger.Error(ex, $"ShortcutRepository/ShortcutRepository: DisplayMagician can't create the Shortcut storage folder {AppShortcutStoragePath} due to an invalid argument."); - } - catch (PathTooLongException ex) - { - logger.Error(ex, $"ShortcutRepository/ShortcutRepository: DisplayMagician can't create the Shortcut storage folder {AppShortcutStoragePath} as the path is too long."); - } - catch (DirectoryNotFoundException ex) - { - logger.Error(ex, $"ShortcutRepository/ShortcutRepository: DisplayMagician can't create the Shortcut storage folder {AppShortcutStoragePath} as the parent folder isn't there."); } catch (Exception ex) { logger.Warn(ex, $"ShortcutRepository/ShortcutRepository: Initialising NVIDIA NvAPIWrapper or CoreAudioController caused an exception."); } + try + { + _audioController = new CoreAudioController(); + } + catch (Exception ex) + { + logger.Warn(ex, $"ShortcutRepository/ShortcutRepository: Exception while trying to initialise CoreAudioController. Audio Chipset on your computer is not supported. You will be unable to set audio settings."); + } + + //_audioController.DefaultPlaybackDevice.SetAsDefault(); + //_audioController.DefaultCaptureDevice.SetAsDefault(); + // Load the Shortcuts from storage LoadShortcuts(); @@ -620,96 +610,148 @@ namespace DisplayMagician } - // record the old audio device + // Get the list of Audio Devices currently connected and active bool needToChangeAudioDevice = false; - CoreAudioDevice rollbackAudioDevice = _audioController.DefaultPlaybackDevice; + CoreAudioDevice rollbackAudioDevice = null; double rollbackAudioVolume = 50; - if (rollbackAudioDevice != null) - { - rollbackAudioVolume = _audioController.DefaultPlaybackDevice.Volume; - if (!rollbackAudioDevice.FullName.Equals(shortcutToUse.AudioDevice)) - { - logger.Debug($"ShortcutRepository/RunShortcut: We need to change to the {shortcutToUse.AudioDevice} audio device."); - needToChangeAudioDevice = true; - } - else - { - logger.Debug($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.AudioDevice} audio device so no need to change audio devices."); - } - } - - // Change Audio Device (if one specified) - if (shortcutToUse.ChangeAudioDevice) - { - logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.AudioDevice} audio device."); - - IEnumerable audioDevices = _audioController.GetPlaybackDevices(); - foreach (CoreAudioDevice audioDevice in audioDevices) - { - if (audioDevice.FullName.Equals(shortcutToUse.AudioDevice)) - { - // use the Audio Device - audioDevice.SetAsDefault(); - - if (shortcutToUse.SetAudioVolume) - { - logger.Debug($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.AudioDevice} audio level to {shortcutToUse.AudioVolume}%."); - Task myTask = new Task(() => - { - audioDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.AudioVolume)); - }); - myTask.Start(); - myTask.Wait(2000); - } - - } - } - } - - // record the old microphone device + List activeAudioDevices = new List(); bool needToChangeCaptureDevice = false; - CoreAudioDevice rollbackCaptureDevice = _audioController.DefaultCaptureDevice; + CoreAudioDevice rollbackCaptureDevice = null; double rollbackCaptureVolume = 50; - if (rollbackCaptureDevice != null) - { - rollbackCaptureVolume = _audioController.DefaultCaptureDevice.Volume; - if (!rollbackCaptureDevice.FullName.Equals(shortcutToUse.CaptureDevice)) - { - logger.Debug($"ShortcutRepository/RunShortcut: We need to change to the {shortcutToUse.CaptureDevice} capture (microphone) device."); - needToChangeCaptureDevice = true; - } - else - { - logger.Debug($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.CaptureDevice} capture (microphone) device so no need to change capture devices."); - } - } - - // Change capture Device (if one specified) - if (shortcutToUse.ChangeCaptureDevice) - { - logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.CaptureDevice} capture (microphone) device."); + List activeCaptureDevices = new List(); - IEnumerable captureDevices = _audioController.GetCaptureDevices(); - foreach (CoreAudioDevice captureDevice in captureDevices) - { - if (captureDevice.FullName.Equals(shortcutToUse.CaptureDevice)) + if (_audioController != null) + { + try { + activeAudioDevices = _audioController.GetPlaybackDevices(DeviceState.Active).ToList(); + if (activeAudioDevices.Count > 0) { - // use the Audio Device - captureDevice.SetAsDefault(); - - if (shortcutToUse.SetCaptureVolume) + // Change Audio Device (if one specified) + if (shortcutToUse.ChangeAudioDevice && !shortcutToUse.AudioDevice.Equals("")) { - logger.Debug($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.CaptureDevice} audio level to {shortcutToUse.CaptureVolume}%."); - Task myTask = new Task(() => - { - captureDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.CaptureVolume)); - }); - myTask.Start(); - myTask.Wait(2000); - } + // record the old audio device + rollbackAudioDevice = _audioController.DefaultPlaybackDevice; + if (rollbackAudioDevice != null) + { + rollbackAudioVolume = _audioController.DefaultPlaybackDevice.Volume; + if (!rollbackAudioDevice.FullName.Equals(shortcutToUse.AudioDevice)) + { + logger.Debug($"ShortcutRepository/RunShortcut: We need to change to the {shortcutToUse.AudioDevice} audio device."); + needToChangeAudioDevice = true; + } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.AudioDevice} audio device so no need to change audio devices."); + } + } + + logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.AudioDevice} audio device."); + + foreach (CoreAudioDevice audioDevice in activeAudioDevices) + { + if (audioDevice.FullName.Equals(shortcutToUse.AudioDevice)) + { + // use the Audio Device + audioDevice.SetAsDefault(); + + if (shortcutToUse.SetAudioVolume) + { + logger.Debug($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.AudioDevice} audio level to {shortcutToUse.AudioVolume}%."); + Task myTask = new Task(() => + { + audioDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.AudioVolume)); + }); + myTask.Start(); + myTask.Wait(2000); + } + + } + } + } + else + { + logger.Info($"ShortcutRepository/RunShortcut: Shortcut does not require changing Audio Device."); + } + } + else + { + logger.Warn($"ShortcutRepository/RunShortcut: No active Audio Devices to use so skipping audio device checks!"); } } + catch(Exception ex) + { + logger.Warn(ex, $"ShortcutRepository/RunShortcut: Exception accessing or manipulating Audio Devices!"); + } + + + try + { + // Get the list of Audio Devices currently connected + activeCaptureDevices = _audioController.GetCaptureDevices(DeviceState.Active).ToList(); + if (activeCaptureDevices.Count > 0) + { + + // Change capture Device (if one specified) + if (shortcutToUse.ChangeCaptureDevice && !shortcutToUse.CaptureDevice.Equals("")) + { + // record the old microphone device + rollbackCaptureDevice = _audioController.DefaultCaptureDevice; + if (rollbackCaptureDevice != null) + { + rollbackCaptureVolume = _audioController.DefaultCaptureDevice.Volume; + if (!rollbackCaptureDevice.FullName.Equals(shortcutToUse.CaptureDevice)) + { + logger.Debug($"ShortcutRepository/RunShortcut: We need to change to the {shortcutToUse.CaptureDevice} capture (microphone) device."); + needToChangeCaptureDevice = true; + } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.CaptureDevice} capture (microphone) device so no need to change capture devices."); + } + } + + logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.CaptureDevice} capture (microphone) device."); + + foreach (CoreAudioDevice captureDevice in activeCaptureDevices) + { + if (captureDevice.FullName.Equals(shortcutToUse.CaptureDevice)) + { + // use the Audio Device + captureDevice.SetAsDefault(); + + if (shortcutToUse.SetCaptureVolume) + { + logger.Debug($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.CaptureDevice} audio level to {shortcutToUse.CaptureVolume}%."); + Task myTask = new Task(() => + { + captureDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.CaptureVolume)); + }); + myTask.Start(); + myTask.Wait(2000); + } + + } + } + } + else + { + logger.Info($"ShortcutRepository/RunShortcut: Shortcut does not require changing Capture Device."); + } + } + else + { + logger.Warn($"ShortcutRepository/RunShortcut: No active Capture Devices to use so skipping capture device checks!"); + } + } + catch (Exception ex) + { + logger.Warn(ex, $"ShortcutRepository/RunShortcut: Exception accessing or manipulating Capture Devices!"); + } + } + else + { + logger.Warn($"ShortcutRepository/RunShortcut: CoreAudio Controller is null, so we can't set Audio or Capture Devices!"); } // Set the IP Service status back to what it was @@ -1369,43 +1411,65 @@ namespace DisplayMagician } // Change Audio Device back (if one specified) - if (needToChangeAudioDevice) + if (activeAudioDevices.Count > 0) { - logger.Debug($"ShortcutRepository/RunShortcut: Reverting default audio back to {rollbackAudioDevice.Name} audio device"); - // use the Audio Device - rollbackAudioDevice.SetAsDefault(); - - if (shortcutToUse.SetAudioVolume) + if (needToChangeAudioDevice) { - logger.Debug($"ShortcutRepository/RunShortcut: Reverting default audio volume back to {shortcutToUse.SetAudioVolume}% volume"); - Task myTask = new Task(() => - { - rollbackAudioDevice.SetVolumeAsync(Convert.ToDouble(rollbackAudioVolume)); - }); - myTask.Start(); - myTask.Wait(2000); - } + logger.Debug($"ShortcutRepository/RunShortcut: Reverting default audio back to {rollbackAudioDevice.Name} audio device"); + // use the Audio Device + rollbackAudioDevice.SetAsDefault(); + if (shortcutToUse.SetAudioVolume) + { + logger.Debug($"ShortcutRepository/RunShortcut: Reverting default audio volume back to {shortcutToUse.SetAudioVolume}% volume"); + Task myTask = new Task(() => + { + rollbackAudioDevice.SetVolumeAsync(Convert.ToDouble(rollbackAudioVolume)); + }); + myTask.Start(); + myTask.Wait(2000); + } + } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: Shortcut did not require changing Audio Device, so no need to change it back."); + } + } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: No Audio Devices active, so no need to change them back."); } + // Change Capture Device back (if one specified) - if (needToChangeCaptureDevice) + if (activeCaptureDevices.Count > 0) { - logger.Debug($"ShortcutRepository/RunShortcut: Reverting default capture (microphone) device back to {rollbackCaptureDevice.Name} capture device"); - // use the Audio Device - rollbackCaptureDevice.SetAsDefault(); - - if (shortcutToUse.SetCaptureVolume) + if (needToChangeCaptureDevice) { - logger.Debug($"ShortcutRepository/RunShortcut: Reverting default capture (microphone) volume back to {shortcutToUse.SetAudioVolume}% volume"); - Task myTask = new Task(() => - { - rollbackCaptureDevice.SetVolumeAsync(Convert.ToDouble(rollbackCaptureVolume)); - }); - myTask.Start(); - myTask.Wait(2000); - } + logger.Debug($"ShortcutRepository/RunShortcut: Reverting default capture (microphone) device back to {rollbackCaptureDevice.Name} capture device"); + // use the Audio Device + rollbackCaptureDevice.SetAsDefault(); + if (shortcutToUse.SetCaptureVolume) + { + logger.Debug($"ShortcutRepository/RunShortcut: Reverting default capture (microphone) volume back to {shortcutToUse.SetAudioVolume}% volume"); + Task myTask = new Task(() => + { + rollbackCaptureDevice.SetVolumeAsync(Convert.ToDouble(rollbackCaptureVolume)); + }); + myTask.Start(); + myTask.Wait(2000); + } + + } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: Shortcut did not require changing Capture Device, so no need to change it back."); + } + } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: No Capture Devices active, so no need to change them back."); } // Change back to the original profile only if it is different @@ -1429,6 +1493,10 @@ namespace DisplayMagician } } + else + { + logger.Debug($"ShortcutRepository/RunShortcut: Shortcut did not require changing Display Profile, so no need to change it back."); + } } diff --git a/DisplayMagician/UIForms/ShortcutForm.Designer.cs b/DisplayMagician/UIForms/ShortcutForm.Designer.cs index f352d99..3116524 100644 --- a/DisplayMagician/UIForms/ShortcutForm.Designer.cs +++ b/DisplayMagician/UIForms/ShortcutForm.Designer.cs @@ -66,6 +66,7 @@ namespace DisplayMagician.UIForms this.rb_no_change_audio = new System.Windows.Forms.RadioButton(); this.tabp_before = new System.Windows.Forms.TabPage(); this.pnl_start_program4 = new System.Windows.Forms.Panel(); + this.cb_dont_start_if_running4 = new System.Windows.Forms.CheckBox(); this.cb_start_program4 = new System.Windows.Forms.CheckBox(); this.txt_start_program4 = new System.Windows.Forms.TextBox(); this.cb_start_program_close4 = new System.Windows.Forms.CheckBox(); @@ -74,6 +75,7 @@ namespace DisplayMagician.UIForms this.cb_start_program_pass_args4 = new System.Windows.Forms.CheckBox(); this.lbl_start_program4 = new System.Windows.Forms.Label(); this.pnl_start_program3 = new System.Windows.Forms.Panel(); + this.cb_dont_start_if_running3 = new System.Windows.Forms.CheckBox(); this.cb_start_program3 = new System.Windows.Forms.CheckBox(); this.txt_start_program3 = new System.Windows.Forms.TextBox(); this.cb_start_program_close3 = new System.Windows.Forms.CheckBox(); @@ -82,6 +84,7 @@ namespace DisplayMagician.UIForms this.cb_start_program_pass_args3 = new System.Windows.Forms.CheckBox(); this.lbl_start_program3 = new System.Windows.Forms.Label(); this.pnl_start_program2 = new System.Windows.Forms.Panel(); + this.cb_dont_start_if_running2 = new System.Windows.Forms.CheckBox(); this.cb_start_program2 = new System.Windows.Forms.CheckBox(); this.txt_start_program2 = new System.Windows.Forms.TextBox(); this.cb_start_program_close2 = new System.Windows.Forms.CheckBox(); @@ -90,6 +93,7 @@ namespace DisplayMagician.UIForms this.cb_start_program_pass_args2 = new System.Windows.Forms.CheckBox(); this.lbl_start_program2 = new System.Windows.Forms.Label(); this.pnl_start_program1 = new System.Windows.Forms.Panel(); + this.cb_dont_start_if_running1 = new System.Windows.Forms.CheckBox(); this.cb_start_program1 = new System.Windows.Forms.CheckBox(); this.txt_start_program1 = new System.Windows.Forms.TextBox(); this.cb_start_program_close1 = new System.Windows.Forms.CheckBox(); @@ -142,10 +146,9 @@ 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.cb_dont_start_if_running1 = new System.Windows.Forms.CheckBox(); - this.cb_dont_start_if_running2 = new System.Windows.Forms.CheckBox(); - this.cb_dont_start_if_running3 = new System.Windows.Forms.CheckBox(); - this.cb_dont_start_if_running4 = 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.tabc_shortcut.SuspendLayout(); this.tabp_display.SuspendLayout(); this.tabp_audio.SuspendLayout(); @@ -321,6 +324,9 @@ namespace DisplayMagician.UIForms // tabp_audio // this.tabp_audio.BackColor = System.Drawing.Color.Black; + this.tabp_audio.Controls.Add(this.lbl_no_active_capture_devices); + this.tabp_audio.Controls.Add(this.lbl_no_active_audio_devices); + this.tabp_audio.Controls.Add(this.lbl_disabled_shortcut_audio_chipset); this.tabp_audio.Controls.Add(this.gb_capture_settings); this.tabp_audio.Controls.Add(this.gb_audio_settings); this.tabp_audio.Location = new System.Drawing.Point(4, 32); @@ -623,6 +629,19 @@ namespace DisplayMagician.UIForms this.pnl_start_program4.Size = new System.Drawing.Size(959, 124); this.pnl_start_program4.TabIndex = 19; // + // cb_dont_start_if_running4 + // + this.cb_dont_start_if_running4.AutoSize = true; + this.cb_dont_start_if_running4.ForeColor = System.Drawing.Color.White; + this.cb_dont_start_if_running4.Location = new System.Drawing.Point(167, 82); + this.cb_dont_start_if_running4.Name = "cb_dont_start_if_running4"; + this.cb_dont_start_if_running4.Size = new System.Drawing.Size(289, 24); + this.cb_dont_start_if_running4.TabIndex = 20; + this.cb_dont_start_if_running4.Text = "Don\'t start if program already running"; + this.cb_dont_start_if_running4.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.cb_dont_start_if_running4.UseVisualStyleBackColor = true; + this.cb_dont_start_if_running4.Visible = false; + // // cb_start_program4 // this.cb_start_program4.Location = new System.Drawing.Point(21, 18); @@ -713,6 +732,19 @@ namespace DisplayMagician.UIForms this.pnl_start_program3.Size = new System.Drawing.Size(959, 124); this.pnl_start_program3.TabIndex = 18; // + // cb_dont_start_if_running3 + // + this.cb_dont_start_if_running3.AutoSize = true; + this.cb_dont_start_if_running3.ForeColor = System.Drawing.Color.White; + this.cb_dont_start_if_running3.Location = new System.Drawing.Point(167, 82); + this.cb_dont_start_if_running3.Name = "cb_dont_start_if_running3"; + this.cb_dont_start_if_running3.Size = new System.Drawing.Size(289, 24); + this.cb_dont_start_if_running3.TabIndex = 20; + this.cb_dont_start_if_running3.Text = "Don\'t start if program already running"; + this.cb_dont_start_if_running3.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.cb_dont_start_if_running3.UseVisualStyleBackColor = true; + this.cb_dont_start_if_running3.Visible = false; + // // cb_start_program3 // this.cb_start_program3.Location = new System.Drawing.Point(21, 18); @@ -803,6 +835,19 @@ namespace DisplayMagician.UIForms this.pnl_start_program2.Size = new System.Drawing.Size(959, 124); this.pnl_start_program2.TabIndex = 18; // + // cb_dont_start_if_running2 + // + this.cb_dont_start_if_running2.AutoSize = true; + this.cb_dont_start_if_running2.ForeColor = System.Drawing.Color.White; + this.cb_dont_start_if_running2.Location = new System.Drawing.Point(167, 82); + this.cb_dont_start_if_running2.Name = "cb_dont_start_if_running2"; + this.cb_dont_start_if_running2.Size = new System.Drawing.Size(289, 24); + this.cb_dont_start_if_running2.TabIndex = 19; + this.cb_dont_start_if_running2.Text = "Don\'t start if program already running"; + this.cb_dont_start_if_running2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.cb_dont_start_if_running2.UseVisualStyleBackColor = true; + this.cb_dont_start_if_running2.Visible = false; + // // cb_start_program2 // this.cb_start_program2.Location = new System.Drawing.Point(21, 18); @@ -893,6 +938,19 @@ namespace DisplayMagician.UIForms this.pnl_start_program1.Size = new System.Drawing.Size(959, 124); this.pnl_start_program1.TabIndex = 0; // + // cb_dont_start_if_running1 + // + this.cb_dont_start_if_running1.AutoSize = true; + this.cb_dont_start_if_running1.ForeColor = System.Drawing.Color.White; + this.cb_dont_start_if_running1.Location = new System.Drawing.Point(167, 82); + this.cb_dont_start_if_running1.Name = "cb_dont_start_if_running1"; + this.cb_dont_start_if_running1.Size = new System.Drawing.Size(289, 24); + this.cb_dont_start_if_running1.TabIndex = 18; + this.cb_dont_start_if_running1.Text = "Don\'t start if program already running"; + this.cb_dont_start_if_running1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + this.cb_dont_start_if_running1.UseVisualStyleBackColor = true; + this.cb_dont_start_if_running1.Visible = false; + // // cb_start_program1 // this.cb_start_program1.Location = new System.Drawing.Point(21, 18); @@ -1525,57 +1583,55 @@ namespace DisplayMagician.UIForms this.cb_autosuggest.UseVisualStyleBackColor = true; this.cb_autosuggest.CheckedChanged += new System.EventHandler(this.cb_autosuggest_CheckedChanged); // - // cb_dont_start_if_running1 + // lbl_disabled_shortcut_audio_chipset // - this.cb_dont_start_if_running1.AutoSize = true; - this.cb_dont_start_if_running1.ForeColor = System.Drawing.Color.White; - this.cb_dont_start_if_running1.Location = new System.Drawing.Point(167, 82); - this.cb_dont_start_if_running1.Name = "cb_dont_start_if_running1"; - this.cb_dont_start_if_running1.Size = new System.Drawing.Size(289, 24); - this.cb_dont_start_if_running1.TabIndex = 18; - this.cb_dont_start_if_running1.Text = "Don\'t start if program already running"; - this.cb_dont_start_if_running1.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.cb_dont_start_if_running1.UseVisualStyleBackColor = true; - this.cb_dont_start_if_running1.Visible = false; + 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; // - // cb_dont_start_if_running2 + // lbl_no_active_audio_devices // - this.cb_dont_start_if_running2.AutoSize = true; - this.cb_dont_start_if_running2.ForeColor = System.Drawing.Color.White; - this.cb_dont_start_if_running2.Location = new System.Drawing.Point(167, 82); - this.cb_dont_start_if_running2.Name = "cb_dont_start_if_running2"; - this.cb_dont_start_if_running2.Size = new System.Drawing.Size(289, 24); - this.cb_dont_start_if_running2.TabIndex = 19; - this.cb_dont_start_if_running2.Text = "Don\'t start if program already running"; - this.cb_dont_start_if_running2.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.cb_dont_start_if_running2.UseVisualStyleBackColor = true; - this.cb_dont_start_if_running2.Visible = false; + 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; // - // cb_dont_start_if_running3 + // lbl_no_active_capture_devices // - this.cb_dont_start_if_running3.AutoSize = true; - this.cb_dont_start_if_running3.ForeColor = System.Drawing.Color.White; - this.cb_dont_start_if_running3.Location = new System.Drawing.Point(167, 82); - this.cb_dont_start_if_running3.Name = "cb_dont_start_if_running3"; - this.cb_dont_start_if_running3.Size = new System.Drawing.Size(289, 24); - this.cb_dont_start_if_running3.TabIndex = 20; - this.cb_dont_start_if_running3.Text = "Don\'t start if program already running"; - this.cb_dont_start_if_running3.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.cb_dont_start_if_running3.UseVisualStyleBackColor = true; - this.cb_dont_start_if_running3.Visible = false; - // - // cb_dont_start_if_running4 - // - this.cb_dont_start_if_running4.AutoSize = true; - this.cb_dont_start_if_running4.ForeColor = System.Drawing.Color.White; - this.cb_dont_start_if_running4.Location = new System.Drawing.Point(167, 82); - this.cb_dont_start_if_running4.Name = "cb_dont_start_if_running4"; - this.cb_dont_start_if_running4.Size = new System.Drawing.Size(289, 24); - this.cb_dont_start_if_running4.TabIndex = 20; - this.cb_dont_start_if_running4.Text = "Don\'t start if program already running"; - this.cb_dont_start_if_running4.TextAlign = System.Drawing.ContentAlignment.MiddleRight; - this.cb_dont_start_if_running4.UseVisualStyleBackColor = true; - this.cb_dont_start_if_running4.Visible = false; + 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; // // ShortcutForm // @@ -1606,6 +1662,7 @@ namespace DisplayMagician.UIForms this.tabp_display.ResumeLayout(false); this.tabp_display.PerformLayout(); this.tabp_audio.ResumeLayout(false); + this.tabp_audio.PerformLayout(); this.gb_capture_settings.ResumeLayout(false); this.gb_capture_settings.PerformLayout(); this.gb_capture_volume.ResumeLayout(false); @@ -1759,5 +1816,8 @@ namespace DisplayMagician.UIForms private System.Windows.Forms.CheckBox cb_dont_start_if_running3; private System.Windows.Forms.CheckBox cb_dont_start_if_running2; private System.Windows.Forms.CheckBox cb_dont_start_if_running1; + 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; } } \ No newline at end of file diff --git a/DisplayMagician/UIForms/ShortcutForm.cs b/DisplayMagician/UIForms/ShortcutForm.cs index 2bf6690..130f423 100644 --- a/DisplayMagician/UIForms/ShortcutForm.cs +++ b/DisplayMagician/UIForms/ShortcutForm.cs @@ -14,6 +14,7 @@ using System.Globalization; using Manina.Windows.Forms; using System.Windows.Forms.VisualStyles; using AudioSwitcher.AudioApi.CoreAudio; +using AudioSwitcher.AudioApi; namespace DisplayMagician.UIForms { @@ -44,11 +45,12 @@ namespace DisplayMagician.UIForms private bool _autoName = true; private int _gameId = 0; private string _uuid = ""; - private CoreAudioController audioController = new CoreAudioController(); + private CoreAudioController audioController = null; private List audioDevices = null; private CoreAudioDevice selectedAudioDevice = null; private List captureDevices = null; private CoreAudioDevice selectedCaptureDevice = null; + private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); public ShortcutForm(ShortcutItem shortcutToEdit) { @@ -69,6 +71,15 @@ namespace DisplayMagician.UIForms lbl_profile_shown.Text = "No Display Profiles available"; lbl_profile_shown_subtitle.Text = "Please go back to the main window, click on 'Display Profiles', and save a new Display Profile. Then come back here."; + + try + { + audioController = new CoreAudioController(); + } + catch (Exception ex) + { + logger.Warn(ex, $"ShortcutForm/ShortcutForm: Exception while trying to initialise CoreAudioController in ShortcutForm. Audio Chipset on your computer is not supported. You will be unable to set audio settings."); + } } public ShortcutItem Shortcut @@ -283,61 +294,6 @@ namespace DisplayMagician.UIForms } - // Save the Audio features - if (rb_change_audio.Checked) - { - _changeAudioDevice = true; - _audioDevice = cb_audio_device.Text; - } - else - { - _changeAudioDevice = false; - _audioDevice = ""; - } - - - if (rb_set_audio_volume.Checked) - { - _setAudioVolume = true; - _audioVolume = nud_audio_volume.Value; - } - else - { - _setAudioVolume = false; - _audioVolume = -1; - } - - // Save the Capture features - if (rb_change_capture.Checked) - { - _changeCaptureDevice = true; - _captureDevice = cb_capture_device.Text; - } - else - { - _changeCaptureDevice = false; - _captureDevice = ""; - } - - - if (rb_set_capture_volume.Checked) - { - _setCaptureVolume = true; - _captureVolume = nud_capture_volume.Value; - } - else - { - _setCaptureVolume = false; - _captureVolume = -1; - } - - - // Check the audio permanence requirements - if (rb_switch_audio_temp.Checked) - _audioPermanence = ShortcutPermanence.Temporary; - - if (rb_switch_audio_permanent.Checked) - _audioPermanence = ShortcutPermanence.Permanent; // Check the display permanence requirements if (rb_switch_display_temp.Checked) @@ -346,12 +302,117 @@ namespace DisplayMagician.UIForms if (rb_switch_display_permanent.Checked) _displayPermanence = ShortcutPermanence.Permanent; - // Check the microphone permanence requirements - if (rb_switch_capture_temp.Checked) - _capturePermanence = ShortcutPermanence.Temporary; - if (rb_switch_capture_permanent.Checked) - _capturePermanence = ShortcutPermanence.Permanent; + // If we can get access to the audio chipset then + // we try to get the settings + if (audioController != null) + { + if (audioDevices != null && audioDevices.Count > 0) + { + // Save the Audio features + if (rb_change_audio.Checked) + { + _changeAudioDevice = true; + _audioDevice = cb_audio_device.Text; + } + else + { + _changeAudioDevice = false; + _audioDevice = ""; + } + + + if (rb_set_audio_volume.Checked) + { + _setAudioVolume = true; + _audioVolume = nud_audio_volume.Value; + } + else + { + _setAudioVolume = false; + _audioVolume = -1; + } + + // Check the audio permanence requirements + if (rb_switch_audio_temp.Checked) + _audioPermanence = ShortcutPermanence.Temporary; + + if (rb_switch_audio_permanent.Checked) + _audioPermanence = ShortcutPermanence.Permanent; + + } + else + { + // No active audio devices found, so we force the save to disable changing the audio device + logger.Warn($"ShortcutForm/btn_save_Click: No active audio devices found, so forcing the save to disable changing the audio device for this shortcut."); + _changeAudioDevice = false; + _audioDevice = ""; + _setAudioVolume = false; + _audioVolume = -1; + _audioPermanence = ShortcutPermanence.Temporary; + } + + if (captureDevices != null && captureDevices.Count > 0) + { + // Save the Capture features + if (rb_change_capture.Checked) + { + _changeCaptureDevice = true; + _captureDevice = cb_capture_device.Text; + } + else + { + _changeCaptureDevice = false; + _captureDevice = ""; + } + + + if (rb_set_capture_volume.Checked) + { + _setCaptureVolume = true; + _captureVolume = nud_capture_volume.Value; + } + else + { + _setCaptureVolume = false; + _captureVolume = -1; + } + + // Check the microphone permanence requirements + if (rb_switch_capture_temp.Checked) + _capturePermanence = ShortcutPermanence.Temporary; + + if (rb_switch_capture_permanent.Checked) + _capturePermanence = ShortcutPermanence.Permanent; + + } + else + { + // No active capture devices found, so we force the save to disable changing the capture device + logger.Warn($"ShortcutForm/btn_save_Click: No active capture devices found, so forcing the save to disable changing the capture device for this shortcut."); + _changeCaptureDevice = false; + _captureDevice = ""; + _setCaptureVolume = false; + _captureVolume = -1; + _capturePermanence = ShortcutPermanence.Temporary; + } + + } + // Otherwise we force set the audio settings to no change + // just to be sure + else + { + _changeAudioDevice = false; + _audioDevice = ""; + _setAudioVolume = false; + _audioVolume = -1; + _changeCaptureDevice = false; + _captureDevice = ""; + _setCaptureVolume = false; + _captureVolume = -1; + _audioPermanence = ShortcutPermanence.Temporary; + _capturePermanence = ShortcutPermanence.Temporary; + } // Save the start program 1 StartProgram myStartProgram = new StartProgram @@ -631,164 +692,212 @@ namespace DisplayMagician.UIForms // Populate all the Audio devices in the audio devices list. // Set the Audio device to the shortcut audio device only if // the Change Audio radiobutton is set - rb_change_audio.Checked = _shortcutToEdit.ChangeAudioDevice; - cb_audio_device.Items.Clear(); - audioDevices = audioController.GetPlaybackDevices().ToList(); - - // If the shortcut is to change the audio device - if (_shortcutToEdit.ChangeAudioDevice) + if (audioController != null) { - // Then we need to populate the list - bool foundAudioDevice = false; - foreach (CoreAudioDevice audioDevice in audioDevices) + rb_change_audio.Checked = _shortcutToEdit.ChangeAudioDevice; + cb_audio_device.Items.Clear(); + + try { - if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.Active) + audioDevices = audioController.GetPlaybackDevices(DeviceState.Active).ToList(); + } + catch (Exception ex) + { + logger.Warn(ex, $"ShortcutForm/ShortcutForm_Load: Exception while trying to get active playback devices."); + } + + if (audioDevices != null && audioDevices.Count > 0) + { + // If the shortcut is to change the audio device + if (_shortcutToEdit.ChangeAudioDevice) { - int index = cb_audio_device.Items.Add(audioDevice.FullName); - // Set the audio device to the default device by default - if (audioDevice.FullName.Equals(_shortcutToEdit.AudioDevice)) + // Then we need to populate the list + bool foundAudioDevice = false; + foreach (CoreAudioDevice audioDevice in audioDevices) { - foundAudioDevice = true; - selectedAudioDevice = audioDevice; + + int index = cb_audio_device.Items.Add(audioDevice.FullName); + // Set the audio device to the default device by default + if (audioDevice.FullName.Equals(_shortcutToEdit.AudioDevice)) + { + foundAudioDevice = true; + selectedAudioDevice = audioDevice; + cb_audio_device.SelectedIndex = index; + if (_shortcutToEdit.SetAudioVolume && _shortcutToEdit.AudioVolume >= 0 && _shortcutToEdit.AudioVolume <= 100) + { + nud_audio_volume.Value = _shortcutToEdit.AudioVolume; + rb_set_audio_volume.Checked = true; + } + else + { + nud_audio_volume.Value = Convert.ToDecimal(audioDevice.Volume); + rb_set_audio_volume.Checked = false; + } + } + } + + // We need to handle the edgecase where the selected audio device + // isn't currently plugged in. We don't want to break the shortcut + // as it could be plugged in when it comes time to actually run + // the shortcut, so we need to just add it to the list to not break + // the UI. + + if (!foundAudioDevice) + { + int index = cb_audio_device.Items.Add(_shortcutToEdit.AudioDevice); cb_audio_device.SelectedIndex = index; + selectedAudioDevice = null; if (_shortcutToEdit.SetAudioVolume && _shortcutToEdit.AudioVolume >= 0 && _shortcutToEdit.AudioVolume <= 100) { - nud_audio_volume.Value = _shortcutToEdit.AudioVolume; rb_set_audio_volume.Checked = true; + nud_audio_volume.Value = _shortcutToEdit.AudioVolume; } else { - nud_audio_volume.Value = Convert.ToDecimal(audioDevice.Volume); - rb_set_audio_volume.Checked = false; + rb_keep_audio_volume.Checked = true; + nud_audio_volume.Value = 50; } } } - } - - // We need to handle the edgecase where the selected audio device - // isn't currently plugged in. We don't want to break the shortcut - // as it could be plugged in when it comes time to actually run - // the shortcut, so we need to just add it to the list to not break - // the UI. - - if (!foundAudioDevice) - { - int index = cb_audio_device.Items.Add(_shortcutToEdit.AudioDevice); - cb_audio_device.SelectedIndex = index; - selectedAudioDevice = null; - if (_shortcutToEdit.SetAudioVolume && _shortcutToEdit.AudioVolume >= 0 && _shortcutToEdit.AudioVolume <= 100) - { - rb_set_audio_volume.Checked = true; - nud_audio_volume.Value = _shortcutToEdit.AudioVolume; - } else { - rb_keep_audio_volume.Checked = true; - nud_audio_volume.Value = 50; - } - } - } - else - { - // Then we need to populate the list - foreach (CoreAudioDevice audioDevice in audioDevices) - { - if (audioDevice.State == AudioSwitcher.AudioApi.DeviceState.Active) - { - int index = cb_audio_device.Items.Add(audioDevice.FullName); - // Set the audio device to the default device by default - if (audioDevice.IsDefaultDevice) + // Then we need to populate the list + foreach (CoreAudioDevice audioDevice in audioDevices) { - selectedAudioDevice = audioDevice; - cb_audio_device.SelectedIndex = index; - nud_audio_volume.Value = Convert.ToDecimal(audioDevice.Volume); + int index = cb_audio_device.Items.Add(audioDevice.FullName); + // Set the audio device to the default device by default + if (audioDevice.IsDefaultDevice) + { + selectedAudioDevice = audioDevice; + cb_audio_device.SelectedIndex = index; + nud_audio_volume.Value = Convert.ToDecimal(audioDevice.Volume); + } } + rb_keep_audio_volume.Checked = true; } + } - rb_keep_audio_volume.Checked = true; - } - - - // Populate all the Capture devices in the capture devices list. - // Set the Capture device to the shortcut capture device only if - // the Change Capture radiobutton is set - rb_change_capture.Checked = _shortcutToEdit.ChangeCaptureDevice; - cb_capture_device.Items.Clear(); - captureDevices = audioController.GetCaptureDevices().ToList(); - - // If the shortcut is to change the capture device - if (_shortcutToEdit.ChangeCaptureDevice) - { - // Then we need to populate the list - bool foundCaptureDevice = false; - foreach (CoreAudioDevice captureDevice in captureDevices) + else { - if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.Active) + // There are no active audio devices found + // so we hide all audio changing controls + gb_audio_settings.Visible = false; + lbl_no_active_audio_devices.Visible = true; + logger.Warn($"ShortcutForm/ShortcutForm_Load: No active playback devices so hiding the audio output controls."); + } + + + // Populate all the Capture devices in the capture devices list. + // Set the Capture device to the shortcut capture device only if + // the Change Capture radiobutton is set + rb_change_capture.Checked = _shortcutToEdit.ChangeCaptureDevice; + cb_capture_device.Items.Clear(); + + try + { + captureDevices = audioController.GetCaptureDevices(DeviceState.Active).ToList(); + } + catch (Exception ex) + { + logger.Warn(ex, $"ShortcutForm/ShortcutForm_Load: Exception while trying to get active capture devices."); + } + + if (captureDevices != null && captureDevices.Count > 0) + { + // If the shortcut is to change the capture device + if (_shortcutToEdit.ChangeCaptureDevice) { - int index = cb_capture_device.Items.Add(captureDevice.FullName); - // Set the capture device to the default device by default - if (captureDevice.FullName.Equals(_shortcutToEdit.CaptureDevice)) + // Then we need to populate the list + bool foundCaptureDevice = false; + foreach (CoreAudioDevice captureDevice in captureDevices) { - foundCaptureDevice = true; - selectedCaptureDevice = captureDevice; + int index = cb_capture_device.Items.Add(captureDevice.FullName); + // Set the capture device to the default device by default + if (captureDevice.FullName.Equals(_shortcutToEdit.CaptureDevice)) + { + foundCaptureDevice = true; + selectedCaptureDevice = captureDevice; + cb_capture_device.SelectedIndex = index; + if (_shortcutToEdit.SetCaptureVolume && _shortcutToEdit.CaptureVolume >= 0 && _shortcutToEdit.CaptureVolume <= 100) + { + nud_capture_volume.Value = _shortcutToEdit.CaptureVolume; + rb_set_capture_volume.Checked = true; + } + else + { + nud_capture_volume.Value = Convert.ToDecimal(captureDevice.Volume); + rb_set_capture_volume.Checked = false; + } + } + } + + // We need to handle the edgecase where the selected capture device + // isn't currently plugged in. We don't want to break the shortcut + // as it could be plugged in when it comes time to actually run + // the shortcut, so we need to just add it to the list to not break + // the UI. + + if (!foundCaptureDevice) + { + int index = cb_capture_device.Items.Add(_shortcutToEdit.CaptureDevice); cb_capture_device.SelectedIndex = index; + selectedCaptureDevice = null; if (_shortcutToEdit.SetCaptureVolume && _shortcutToEdit.CaptureVolume >= 0 && _shortcutToEdit.CaptureVolume <= 100) { - nud_capture_volume.Value = _shortcutToEdit.CaptureVolume; rb_set_capture_volume.Checked = true; + nud_capture_volume.Value = _shortcutToEdit.CaptureVolume; } else { - nud_capture_volume.Value = Convert.ToDecimal(captureDevice.Volume); - rb_set_capture_volume.Checked = false; + rb_keep_capture_volume.Checked = true; + nud_capture_volume.Value = 50; } } } - } - - // We need to handle the edgecase where the selected capture device - // isn't currently plugged in. We don't want to break the shortcut - // as it could be plugged in when it comes time to actually run - // the shortcut, so we need to just add it to the list to not break - // the UI. - - if (!foundCaptureDevice) - { - int index = cb_capture_device.Items.Add(_shortcutToEdit.CaptureDevice); - cb_capture_device.SelectedIndex = index; - selectedCaptureDevice = null; - if (_shortcutToEdit.SetCaptureVolume && _shortcutToEdit.CaptureVolume >= 0 && _shortcutToEdit.CaptureVolume <= 100) - { - rb_set_capture_volume.Checked = true; - nud_capture_volume.Value = _shortcutToEdit.CaptureVolume; - } else { + // Then we need to populate the list + foreach (CoreAudioDevice captureDevice in captureDevices) + { + int index = cb_capture_device.Items.Add(captureDevice.FullName); + // Set the capture device to the default device by default + if (captureDevice.IsDefaultDevice) + { + selectedCaptureDevice = captureDevice; + cb_capture_device.SelectedIndex = index; + nud_capture_volume.Value = Convert.ToDecimal(captureDevice.Volume); + } + } rb_keep_capture_volume.Checked = true; - nud_capture_volume.Value = 50; } + } + else + { + // There are no active audio devices found + // so we hide all audio changing controls + gb_capture_settings.Visible = false; + lbl_no_active_capture_devices.Visible = true; + logger.Warn($"ShortcutForm/ShortcutForm_Load: No active capture devices so hiding the microphone input controls."); + } + } else { - // Then we need to populate the list - foreach (CoreAudioDevice captureDevice in captureDevices) - { - if (captureDevice.State == AudioSwitcher.AudioApi.DeviceState.Active) - { - int index = cb_capture_device.Items.Add(captureDevice.FullName); - // Set the capture device to the default device by default - if (captureDevice.IsDefaultDevice) - { - selectedCaptureDevice = captureDevice; - cb_capture_device.SelectedIndex = index; - nud_capture_volume.Value = Convert.ToDecimal(captureDevice.Volume); - } - } - } - rb_keep_capture_volume.Checked = true; - } + // Audio Controller == null, so the audio device isn't supported by AudioSwitcher.CoreAudio! + // We just have to disable the switching functionality at present :( + // Hopefully I find another library that works with everything including RealTek Audio + gb_audio_settings.Visible = false; + gb_capture_settings.Visible = false; + lbl_disabled_shortcut_audio_chipset.Visible = true; + // We also force the audio settings to off, just in case + rb_change_audio.Checked = false; + rb_set_audio_volume.Checked = false; + rb_change_capture.Checked = false; + rb_set_capture_volume.Checked = false; + } + // Populate a full list of games // Start with the Steam Games From 26d2e4272346211d86c07cf66147341a075c79c3 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 12:03:51 +1200 Subject: [PATCH 07/16] Added some extra exception handling Added extra exception handling for the imagelistview in the shortcut form just in case there is an issue at some point. --- DisplayMagician/UIForms/ShortcutForm.cs | 33 ++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/DisplayMagician/UIForms/ShortcutForm.cs b/DisplayMagician/UIForms/ShortcutForm.cs index 130f423..4e72317 100644 --- a/DisplayMagician/UIForms/ShortcutForm.cs +++ b/DisplayMagician/UIForms/ShortcutForm.cs @@ -58,16 +58,24 @@ namespace DisplayMagician.UIForms // Set the profileAdaptor we need to load images from Profiles // into the Profiles ImageListView - _profileAdaptor = new ProfileAdaptor(); + try + { + _profileAdaptor = new ProfileAdaptor(); - _shortcutToEdit = shortcutToEdit; + _shortcutToEdit = shortcutToEdit; - // Style the Saved Profiles list - ilv_saved_profiles.MultiSelect = false; - ilv_saved_profiles.ThumbnailSize = new Size(100, 100); - ilv_saved_profiles.AllowDrag = false; - ilv_saved_profiles.AllowDrop = false; - ilv_saved_profiles.SetRenderer(new ProfileILVRenderer()); + // Style the Saved Profiles list + ilv_saved_profiles.MultiSelect = false; + ilv_saved_profiles.ThumbnailSize = new Size(100, 100); + ilv_saved_profiles.AllowDrag = false; + ilv_saved_profiles.AllowDrop = false; + ilv_saved_profiles.SetRenderer(new ProfileILVRenderer()); + + } + catch(Exception ex) + { + logger.Error(ex, $"ShortcutForm/ShortcutForm: Exception while trying to setup the game ImageListView and set the render."); + } lbl_profile_shown.Text = "No Display Profiles available"; lbl_profile_shown_subtitle.Text = "Please go back to the main window, click on 'Display Profiles', and save a new Display Profile. Then come back here."; @@ -302,7 +310,6 @@ namespace DisplayMagician.UIForms if (rb_switch_display_permanent.Checked) _displayPermanence = ShortcutPermanence.Permanent; - // If we can get access to the audio chipset then // we try to get the settings if (audioController != null) @@ -467,9 +474,11 @@ namespace DisplayMagician.UIForms // If we're launching a game if (rb_launcher.Checked) { + logger.Trace($"ShortcutForm/btn_save_Click: We're saving a game!"); // If the game is a SteamGame - if(txt_game_launcher.Text == SupportedGameLibrary.Steam.ToString()) + if (txt_game_launcher.Text == SupportedGameLibrary.Steam.ToString()) { + logger.Trace($"ShortcutForm/btn_save_Click: We're saving a Steam game!"); // Find the SteamGame _gameToUse = new GameStruct { @@ -504,6 +513,7 @@ namespace DisplayMagician.UIForms // If the game is a SteamGame else if (txt_game_launcher.Text == SupportedGameLibrary.Uplay.ToString()) { + logger.Trace($"ShortcutForm/btn_save_Click: We're saving a Uplay game!"); // Find the UplayGame _gameToUse = new GameStruct { @@ -538,6 +548,7 @@ namespace DisplayMagician.UIForms } else if (rb_standalone.Checked) { + logger.Trace($"ShortcutForm/btn_save_Click: We're saving a standalone executable!"); _executableToUse = new Executable { ExecutableArguments = txt_args_executable.Text, @@ -579,7 +590,7 @@ namespace DisplayMagician.UIForms } else { - + logger.Trace($"ShortcutForm/btn_save_Click: We're not saving any game or executable to start!"); _shortcutToEdit.UpdateNoGameShortcut( txt_shortcut_save_name.Text, _profileToUse, From 96749e8ba823f43821ce27666513794efddffba5 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 12:25:48 +1200 Subject: [PATCH 08/16] Fixed Desktop link without icon Logic for determining the shortcut icon name was flawed, and wouldn't work. Moved to a new icon naming scheme using shortcut UUID to make it simpler to update. Icon is written every time that the shortcut is saved. --- DisplayMagician/ShortcutItem.cs | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/DisplayMagician/ShortcutItem.cs b/DisplayMagician/ShortcutItem.cs index beff4ab..06b36cf 100644 --- a/DisplayMagician/ShortcutItem.cs +++ b/DisplayMagician/ShortcutItem.cs @@ -1809,17 +1809,8 @@ namespace DisplayMagician public void ReplaceShortcutIconInCache() { string newShortcutIconFilename; - if (_category == ShortcutCategory.Application) - { - // Work out the name of the shortcut we'll save. - newShortcutIconFilename = Path.Combine(Program.AppShortcutPath, String.Concat(@"executable-", _profileToUse.UUID, "-", Path.GetFileNameWithoutExtension(_executableNameAndPath), @".ico")); - - } - else - { - // Work out the name of the shortcut we'll save. - newShortcutIconFilename = Path.Combine(Program.AppShortcutPath, String.Concat(_gameLibrary.ToString().ToLower(CultureInfo.InvariantCulture), @"-", _profileToUse.UUID, "-", _gameAppId.ToString(), @".ico")); - } + // Work out the name of the shortcut we'll save. + newShortcutIconFilename = Path.Combine(Program.AppShortcutPath, $"{UUID}.ico"); // If the new shortcut icon should be named differently // then change the name of it @@ -1837,18 +1828,8 @@ namespace DisplayMagician public void SaveShortcutIconToCache() { - // Only add this set of options if the shortcut is to an standalone application - if (_category == ShortcutCategory.Application) - { - // Work out the name of the shortcut we'll save. - _savedShortcutIconCacheFilename = Path.Combine(Program.AppShortcutPath, String.Concat(@"executable-", _profileToUse.UUID, "-", Path.GetFileNameWithoutExtension(_executableNameAndPath), @".ico")); - - } - else - { - // Work out the name of the shortcut we'll save. - _savedShortcutIconCacheFilename = Path.Combine(Program.AppShortcutPath, String.Concat(_gameLibrary.ToString().ToLower(CultureInfo.InvariantCulture),@"-", _profileToUse.UUID, "-", _gameAppId.ToString(), @".ico")); - } + // Work out the name of the shortcut we'll save. + _savedShortcutIconCacheFilename = Path.Combine(Program.AppShortcutPath, $"{UUID}.ico"); MultiIcon shortcutIcon; try @@ -1859,7 +1840,7 @@ namespace DisplayMagician } catch (Exception ex) { - Console.WriteLine($"ShortcutRepository/SaveShortcutIconToCache exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); + logger.Error(ex, $"ShortcutRepository/SaveShortcutIconToCache: Exception while trying to save the Shortcut ivon."); // If we fail to create an icon based on the original executable or game // Then we use the standard DisplayMagician profile one. @@ -2276,6 +2257,7 @@ namespace DisplayMagician shortcutFileName = Path.ChangeExtension(shortcutFileName, @"lnk"); // And we use the Icon from the shortcutIconCache + SaveShortcutIconToCache(); shortcutIconFileName = SavedShortcutIconCacheFilename; // If the user supplied a file From b83478a0315cba75c1c7bd599a19a15a850e050d Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 16:28:31 +1200 Subject: [PATCH 09/16] Fixed audio volume setting Modified some logic so that the audio device volume and capture device volume will still be applied even if the current device is selected. Previous logic incorrectly would only change the volume if the audio device was also changed. Volume is always evaluated even if the audio device doesn't have to change (unless don't change audio device or don't change capture device are selected). --- DisplayMagician/ShortcutRepository.cs | 98 +++++++++++++++------------ 1 file changed, 56 insertions(+), 42 deletions(-) diff --git a/DisplayMagician/ShortcutRepository.cs b/DisplayMagician/ShortcutRepository.cs index 3ddc086..e1e3737 100644 --- a/DisplayMagician/ShortcutRepository.cs +++ b/DisplayMagician/ShortcutRepository.cs @@ -640,34 +640,41 @@ namespace DisplayMagician logger.Debug($"ShortcutRepository/RunShortcut: We need to change to the {shortcutToUse.AudioDevice} audio device."); needToChangeAudioDevice = true; } - else - { - logger.Debug($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.AudioDevice} audio device so no need to change audio devices."); - } + } - logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.AudioDevice} audio device."); - - foreach (CoreAudioDevice audioDevice in activeAudioDevices) + if (needToChangeAudioDevice) { - if (audioDevice.FullName.Equals(shortcutToUse.AudioDevice)) + logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.AudioDevice} audio device."); + + foreach (CoreAudioDevice audioDevice in activeAudioDevices) { - // use the Audio Device - audioDevice.SetAsDefault(); - - if (shortcutToUse.SetAudioVolume) + if (audioDevice.FullName.Equals(shortcutToUse.AudioDevice)) { - logger.Debug($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.AudioDevice} audio level to {shortcutToUse.AudioVolume}%."); - Task myTask = new Task(() => - { - audioDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.AudioVolume)); - }); - myTask.Start(); - myTask.Wait(2000); + // use the Audio Device + audioDevice.SetAsDefault(); } - } } + else + { + logger.Info($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.AudioDevice} audio device so no need to change audio devices."); + } + + if (shortcutToUse.SetAudioVolume) + { + logger.Info($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.AudioDevice} volume level to {shortcutToUse.AudioVolume}%."); + Task myTask = new Task(() => + { + _audioController.DefaultPlaybackDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.AudioVolume)); + }); + myTask.Start(); + myTask.Wait(2000); + } + else + { + logger.Info($"ShortcutRepository/RunShortcut: We don't need to set the {shortcutToUse.AudioDevice} volume level."); + } } else { @@ -705,38 +712,45 @@ namespace DisplayMagician logger.Debug($"ShortcutRepository/RunShortcut: We need to change to the {shortcutToUse.CaptureDevice} capture (microphone) device."); needToChangeCaptureDevice = true; } - else - { - logger.Debug($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.CaptureDevice} capture (microphone) device so no need to change capture devices."); - } } - logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.CaptureDevice} capture (microphone) device."); - - foreach (CoreAudioDevice captureDevice in activeCaptureDevices) + if (needToChangeCaptureDevice) { - if (captureDevice.FullName.Equals(shortcutToUse.CaptureDevice)) + logger.Info($"ShortcutRepository/RunShortcut: Changing to the {shortcutToUse.CaptureDevice} capture (microphone) device."); + + foreach (CoreAudioDevice captureDevice in activeCaptureDevices) { - // use the Audio Device - captureDevice.SetAsDefault(); - - if (shortcutToUse.SetCaptureVolume) + if (captureDevice.FullName.Equals(shortcutToUse.CaptureDevice)) { - logger.Debug($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.CaptureDevice} audio level to {shortcutToUse.CaptureVolume}%."); - Task myTask = new Task(() => - { - captureDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.CaptureVolume)); - }); - myTask.Start(); - myTask.Wait(2000); + // use the Audio Device + captureDevice.SetAsDefault(); } - } } + else + { + logger.Info($"ShortcutRepository/RunShortcut: We're already using the {shortcutToUse.CaptureDevice} capture (microphone) device so no need to change capture devices."); + } + + if (shortcutToUse.SetCaptureVolume) + { + logger.Info($"ShortcutRepository/RunShortcut: Setting {shortcutToUse.CaptureDevice} capture (microphone) level to {shortcutToUse.CaptureVolume}%."); + Task myTask = new Task(() => + { + _audioController.DefaultCaptureDevice.SetVolumeAsync(Convert.ToDouble(shortcutToUse.CaptureVolume)); + }); + myTask.Start(); + myTask.Wait(2000); + } + else + { + logger.Info($"ShortcutRepository/RunShortcut: We don't need to set the {shortcutToUse.CaptureDevice} capture (microphone) volume level."); + } + } else { - logger.Info($"ShortcutRepository/RunShortcut: Shortcut does not require changing Capture Device."); + logger.Info($"ShortcutRepository/RunShortcut: Shortcut does not require changing capture (microphone) device."); } } else @@ -819,7 +833,7 @@ namespace DisplayMagician } else { - logger.Debug($"ShortcutRepository/RunShortcut: No programs to start before the main game or executable"); + logger.Info($"ShortcutRepository/RunShortcut: No programs to start before the main game or executable"); } // Add a status notification icon in the status area From 8c132a79f5e1cb9189f9a031dc11d319015d91f3 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 19:19:42 +1200 Subject: [PATCH 10/16] [WIP] Partially working uplay scanning Updated Uplay library scanning to work properly, but it requires access to the HKEY_LOCAL_MACHINE reg key, which only works with adrministrative rights. I really don't want to need that, so I'll be trying to find an alternative way to get the information I need from the file system. --- DisplayMagician/GameLibraries/UplayLibrary.cs | 94 ++++++++++++------- 1 file changed, 62 insertions(+), 32 deletions(-) diff --git a/DisplayMagician/GameLibraries/UplayLibrary.cs b/DisplayMagician/GameLibraries/UplayLibrary.cs index 714ecaf..7a08875 100644 --- a/DisplayMagician/GameLibraries/UplayLibrary.cs +++ b/DisplayMagician/GameLibraries/UplayLibrary.cs @@ -411,16 +411,18 @@ namespace DisplayMagician.GameLibraries logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Config File Path = {uplayConfigFilePath }"); string uplayConfigFileString = File.ReadAllText(uplayConfigFilePath); uplayConfigFileString = uplayConfigFileString.Remove(0, 12); + string[] dividingText = { "version: 2.0" }; + List uplayConfigFile = uplayConfigFileString.Split(dividingText,StringSplitOptions.RemoveEmptyEntries).ToList(); // Split the file into records at the SOH unicode character - List uplayConfigFile = uplayConfigFileString.Split((Char)1).ToList(); + //List uplayConfigFile = uplayConfigFileString.Split((Char)1).ToList(); // Go through every record and attempt to parse it foreach (string uplayEntry in uplayConfigFile) { // Skip any Uplay entry records that don't start with 'version:' - if (!uplayEntry.StartsWith("version:",StringComparison.OrdinalIgnoreCase)) - continue; + //if (!uplayEntry.StartsWith("version:",StringComparison.OrdinalIgnoreCase)) + // continue; - logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Entry (that don't start with version) = {uplayEntry}"); + logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Entry that starts with 'version: 2.0') = {uplayEntry}"); //Split the record into entrylines string[] delimeters = { "\r\n" }; @@ -479,10 +481,12 @@ namespace DisplayMagician.GameLibraries bool gotGameFileName = false; string gameId = ""; bool gotGameId = false; + string gameRegistryKey = ""; + bool gotGameRegistryKey = false; for (int i = 0; i <= 50; i++) { // Stop this loop once we have both filname and gameid - if (gotGameFileName && gotGameId && gotGameIconPath && gotGameName) + 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}"); break; @@ -535,43 +539,69 @@ namespace DisplayMagician.GameLibraries mc = Regex.Matches(uplayEntryLines[i], @"Installs\\(\d+)\\InstallDir"); gameId = mc[0].Groups[1].ToString(); gotGameId = true; - logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameId = {gameId}"); + //mc = Regex.Matches(uplayEntryLines[i], @"(HKEY_LOCAL_MACHINE.*?\\InstallDir)"); + mc = Regex.Matches(uplayEntryLines[i], @"(HKEY_LOCAL_MACHINE.*?)\\InstallDir"); + gameRegistryKey = mc[0].Groups[1].ToString(); + gotGameRegistryKey = true; + logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameId = {gameId} and gameRegistryKey = {gameRegistryKey}"); } } logger.Trace($"UplayLibrary/LoadInstalledGames: gameId = {gameId}"); logger.Trace($"UplayLibrary/LoadInstalledGames: gameFileName = {gameFileName}"); logger.Trace($"UplayLibrary/LoadInstalledGames: gameGameIconPath = {uplayGameAppInfo.GameUplayIconPath}"); + logger.Trace($"UplayLibrary/LoadInstalledGames: gameRegistryKey = {gameRegistryKey}"); - // Now we need to lookup the game install path in registry using the gameId - string registryUplayGameInstallsKey = registryUplayInstallsKey + "\\" + gameId; - logger.Trace($"UplayLibrary/LoadInstalledGames: registryUplayGameInstallsKey = {registryUplayGameInstallsKey}"); - RegistryKey uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(registryUplayGameInstallsKey, RegistryKeyPermissionCheck.ReadSubTree); - foreach (string regKeyName in uplayGameInstallKey.GetValueNames()) + if (gotGameRegistryKey) { - logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameInstallKey[{regKeyName}] = {uplayGameInstallKey.GetValue(regKeyName)}"); - } + // Now we need to lookup the game install path in registry using the gameId + using (RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)) + using (RegistryKey uplayGameInstallKey = hklm.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) + { + if (uplayGameInstallKey == null) + continue; - // From that we lookup the actual game path - string gameInstallDir = uplayGameInstallKey.GetValue("InstallDir", "").ToString(); - logger.Trace($"UplayLibrary/LoadInstalledGames: gameInstallDir found through first method (forward slashes) = {gameInstallDir}"); - if (!String.IsNullOrWhiteSpace(gameInstallDir)) - { - 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); - logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameID = {uplayGameAppInfo.GameID }"); - } - else { - logger.Warn($"UplayLibrary/LoadInstalledGames: gameInstallDir is null or all whitespace!"); - } + // check if null (means the game isn't installed any more!) + // if it's null then skip! + /* if (uplayGameInstallKey == null) + { + // if we can't find it in the default location, then we try within WOW6432Node instead + gameRegistryKey = gameRegistryKey.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft"); + uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree); + if (uplayGameInstallKey == null) + continue; + } - // 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}"); + */ + foreach (string regKeyName in uplayGameInstallKey.GetValueNames()) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameInstallKey[{regKeyName}] = {uplayGameInstallKey.GetValue(regKeyName)}"); + } + + // From that we lookup the actual game path + string gameInstallDir = uplayGameInstallKey.GetValue("InstallDir", "").ToString(); + logger.Trace($"UplayLibrary/LoadInstalledGames: gameInstallDir found through first method (forward slashes) = {gameInstallDir}"); + if (!String.IsNullOrWhiteSpace(gameInstallDir)) + { + 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); + logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameAppInfo.GameID = {uplayGameAppInfo.GameID }"); + } + else + { + logger.Warn($"UplayLibrary/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! + _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}"); + } + } + } logger.Info($"UplayLibrary/LoadInstalledGames: Found {_allUplayGames.Count} installed Uplay games"); From b8f1007cd133584e97bbf95a63413478e43849cf Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 19:49:32 +1200 Subject: [PATCH 11/16] Fixed UplayLibrary reading again This time I know it works as I have checked games are found even if saved in different folders on different drives, and even when Ubiconnect is installed in a non-default location. It even copes when games are uninstalled and their remnants are left in registry. --- DisplayMagician/GameLibraries/UplayLibrary.cs | 34 +++++++------------ 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/DisplayMagician/GameLibraries/UplayLibrary.cs b/DisplayMagician/GameLibraries/UplayLibrary.cs index 7a08875..d7d5b77 100644 --- a/DisplayMagician/GameLibraries/UplayLibrary.cs +++ b/DisplayMagician/GameLibraries/UplayLibrary.cs @@ -403,9 +403,6 @@ namespace DisplayMagician.GameLibraries // Look in HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\Ubisoft\\Launcher and check the InstallDir key // That returns the location of the install dir : E:\Program Files (x86)\Ubisoft\Ubisoft Game Launcher\ - //RegistryKey uplayInstallKey = Registry.CurrentUser.OpenSubKey(registryUplayInstallsKey, RegistryKeyPermissionCheck.ReadSubTree); - //string uplayInstallDir = uplayInstallKey.GetValue("InstallDir", "C:\\Program Files (x86)\\Ubisoft\\Ubisoft Game Launcher\\").ToString(); - // Access {installdir}\\cache\\configuration\\configurations file string uplayConfigFilePath = _uplayPath + @"cache\configuration\configurations"; logger.Trace($"UplayLibrary/LoadInstalledGames: Uplay Config File Path = {uplayConfigFilePath }"); @@ -539,9 +536,9 @@ namespace DisplayMagician.GameLibraries mc = Regex.Matches(uplayEntryLines[i], @"Installs\\(\d+)\\InstallDir"); gameId = mc[0].Groups[1].ToString(); gotGameId = true; - //mc = Regex.Matches(uplayEntryLines[i], @"(HKEY_LOCAL_MACHINE.*?\\InstallDir)"); - mc = Regex.Matches(uplayEntryLines[i], @"(HKEY_LOCAL_MACHINE.*?)\\InstallDir"); - gameRegistryKey = mc[0].Groups[1].ToString(); + mc = Regex.Matches(uplayEntryLines[i], @"HKEY_LOCAL_MACHINE\\(.*?)\\InstallDir"); + gameRegistryKey = mc[0].Groups[1].ToString(); + gameRegistryKey = gameRegistryKey.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft"); gotGameRegistryKey = true; logger.Trace($"UplayLibrary/LoadInstalledGames: Found gameId = {gameId} and gameRegistryKey = {gameRegistryKey}"); } @@ -554,25 +551,18 @@ namespace DisplayMagician.GameLibraries if (gotGameRegistryKey) { - // Now we need to lookup the game install path in registry using the gameId - using (RegistryKey hklm = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64)) - using (RegistryKey uplayGameInstallKey = hklm.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) + // 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 uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) { + // If the key doesn't exist we skip it as the game isn't installed any longer! if (uplayGameInstallKey == null) + { + logger.Trace($"UplayLibrary/LoadInstalledGames: Skipping Uplay Game {uplayGameAppInfo.GameName} as it isn't installed at the moment (it was uninstalled at some point)"); continue; + } - // check if null (means the game isn't installed any more!) - // if it's null then skip! - /* if (uplayGameInstallKey == null) - { - // if we can't find it in the default location, then we try within WOW6432Node instead - gameRegistryKey = gameRegistryKey.Replace(@"Ubisoft", @"WOW6432Node\Ubisoft"); - uplayGameInstallKey = Registry.LocalMachine.OpenSubKey(gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree); - if (uplayGameInstallKey == null) - continue; - } - - */ + // If we get here, then we have a real game. foreach (string regKeyName in uplayGameInstallKey.GetValueNames()) { logger.Trace($"UplayLibrary/LoadInstalledGames: uplayGameInstallKey[{regKeyName}] = {uplayGameInstallKey.GetValue(regKeyName)}"); @@ -580,7 +570,7 @@ namespace DisplayMagician.GameLibraries // From that we lookup the actual game path string gameInstallDir = uplayGameInstallKey.GetValue("InstallDir", "").ToString(); - logger.Trace($"UplayLibrary/LoadInstalledGames: gameInstallDir found through first method (forward slashes) = {gameInstallDir}"); + logger.Trace($"UplayLibrary/LoadInstalledGames: gameInstallDir found = {gameInstallDir}"); if (!String.IsNullOrWhiteSpace(gameInstallDir)) { uplayGameAppInfo.GameInstallDir = Path.GetFullPath(gameInstallDir).TrimEnd('\\'); From 066a0e30f5e6e48630194a0a07fdbe7d1d2816e6 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 20:08:46 +1200 Subject: [PATCH 12/16] Fixed Steam Update detection (probably) Have likely fixed the steam update detection but I'm not able to test at the moment as nothing needs updating! --- DisplayMagician/GameLibraries/SteamGame.cs | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/DisplayMagician/GameLibraries/SteamGame.cs b/DisplayMagician/GameLibraries/SteamGame.cs index 2fc88bb..f4740d0 100644 --- a/DisplayMagician/GameLibraries/SteamGame.cs +++ b/DisplayMagician/GameLibraries/SteamGame.cs @@ -121,32 +121,32 @@ namespace DisplayMagician.GameLibraries { try { - using ( - var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) + using (var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree)) { - if ((int)key?.GetValue(@"Updating", 0) == 1) + if (key != null) { - return true; - } - return false; + int updateValue; + int.TryParse(key.GetValue(@"Updating", 0).ToString(),out updateValue); + if (updateValue == 1) + { + return true; + } + } } } catch (SecurityException ex) { - Console.WriteLine($"SteamGame/IsUpdating securityexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, $"SteamGame/IsUpdating: SecurityException when trying to open {_gameRegistryKey} registry key"); } catch (IOException ex) { - // Extract some information from this exception, and then - // throw it to the parent method. - Console.WriteLine($"SteamGame/IsUpdating ioexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}"); - if (ex.Source != null) - Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message); - throw; + logger.Warn(ex, $"SteamGame/IsUpdating: IOException when trying to open {_gameRegistryKey} registry key"); } + catch (Exception ex) + { + logger.Warn(ex, $"SteamGame/IsUpdating: Exception when trying to open {_gameRegistryKey} registry key"); + } + return false; } } From 325a15bf6d46148e1212b8afbd205e4e27137899 Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 21:36:03 +1200 Subject: [PATCH 13/16] Fixed game process detection Reworked the Uplay and Steam game detection to make them more reliable. Found a couple of logic errors that were causing issues with process detection. Also moved away from accessing process.MainModule as it was causing exceptions. Now just using process name as it is simple and fast. --- DisplayMagician/DisplayMagician.csproj | 1 + DisplayMagician/GameLibraries/SteamGame.cs | 8 +- DisplayMagician/GameLibraries/UplayGame.cs | 11 +- DisplayMagician/ProcessCommandLine.cs | 246 ++++++++++++++++++ DisplayMagician/ShortcutRepository.cs | 56 ++-- .../UIForms/ShortcutLibraryForm.cs | 1 + 6 files changed, 290 insertions(+), 33 deletions(-) create mode 100644 DisplayMagician/ProcessCommandLine.cs diff --git a/DisplayMagician/DisplayMagician.csproj b/DisplayMagician/DisplayMagician.csproj index 39d817d..fd35243 100644 --- a/DisplayMagician/DisplayMagician.csproj +++ b/DisplayMagician/DisplayMagician.csproj @@ -107,6 +107,7 @@ + True diff --git a/DisplayMagician/GameLibraries/SteamGame.cs b/DisplayMagician/GameLibraries/SteamGame.cs index f4740d0..992751f 100644 --- a/DisplayMagician/GameLibraries/SteamGame.cs +++ b/DisplayMagician/GameLibraries/SteamGame.cs @@ -85,7 +85,9 @@ namespace DisplayMagician.GameLibraries { try { - if (gameProcess.MainModule.FileName.StartsWith(_steamGameExePath)) + //if (gameProcess.MainModule.FileName.StartsWith(_steamGameExePath)) + // numGameProcesses++; + if (gameProcess.ProcessName.Equals(_steamGameProcessName)) numGameProcesses++; } catch (Exception ex) @@ -98,7 +100,9 @@ namespace DisplayMagician.GameLibraries if (filePath == null) { // if we hit this bit then GameUtils.GetMainModuleFilepath failed, - // so we just skip that process + // so we just assume that the process is a game process + // as it matched the original process search + numGameProcesses++; continue; } else diff --git a/DisplayMagician/GameLibraries/UplayGame.cs b/DisplayMagician/GameLibraries/UplayGame.cs index 59532a3..f64f722 100644 --- a/DisplayMagician/GameLibraries/UplayGame.cs +++ b/DisplayMagician/GameLibraries/UplayGame.cs @@ -85,20 +85,22 @@ namespace DisplayMagician.GameLibraries foreach (Process gameProcess in gameProcesses) { try - { - if (gameProcess.MainModule.FileName.StartsWith(_uplayGameExePath)) + { + if (gameProcess.ProcessName.Equals(_uplayGameProcessName)) numGameProcesses++; } catch (Exception ex) { - logger.Debug(ex, $"UplayGame/IsRunning: Accessing Process.MainModule caused exception. Trying GameUtils.GetMainModuleFilepath instead"); + logger.Debug(ex, $"UplayGame/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 skip that process + // so we just assume that the process is a game process + // as it matched the original process search + numGameProcesses++; continue; } else @@ -116,6 +118,7 @@ namespace DisplayMagician.GameLibraries } } + // Have to do much more research to figure out how to detect when Uplay is updating a game /*public override bool IsUpdating { get diff --git a/DisplayMagician/ProcessCommandLine.cs b/DisplayMagician/ProcessCommandLine.cs new file mode 100644 index 0000000..abe5846 --- /dev/null +++ b/DisplayMagician/ProcessCommandLine.cs @@ -0,0 +1,246 @@ +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( + IntPtr hProcess, IntPtr lpBaseAddress, out TStruct val) + { + val = default; + var structSize = Marshal.SizeOf(); + var mem = Marshal.AllocHGlobal(structSize); + try + { + if (Win32Native.ReadProcessMemory( + hProcess, lpBaseAddress, mem, (uint)structSize, out var len) && + (len == structSize)) + { + val = Marshal.PtrToStructure(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(); + 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(memPBI); + if (pbiInfo.PebBaseAddress != IntPtr.Zero) + { + if (ReadStructFromProcessMemory(hProcess, + pbiInfo.PebBaseAddress, out var pebInfo)) + { + if (ReadStructFromProcessMemory( + 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 CommandLineToArgs(string commandLine) + { + if (string.IsNullOrEmpty(commandLine)) { return Array.Empty(); } + + 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); + } + } + } +} diff --git a/DisplayMagician/ShortcutRepository.cs b/DisplayMagician/ShortcutRepository.cs index e1e3737..f1f6cff 100644 --- a/DisplayMagician/ShortcutRepository.cs +++ b/DisplayMagician/ShortcutRepository.cs @@ -139,7 +139,7 @@ namespace DisplayMagician #region Class Methods public static bool AddShortcut(ShortcutItem shortcut) { - logger.Debug($"ShortcutRepository/AddShortcut: Adding shortcut {shortcut.Name} to our shortcut repository"); + logger.Trace($"ShortcutRepository/AddShortcut: Adding shortcut {shortcut.Name} to our shortcut repository"); if (!(shortcut is ShortcutItem)) return false; @@ -162,7 +162,7 @@ namespace DisplayMagician public static bool RemoveShortcut(ShortcutItem shortcut) { - logger.Debug($"ShortcutRepository/RemoveShortcut: Removing shortcut {shortcut.Name} if it exists in our shortcut repository"); + logger.Trace($"ShortcutRepository/RemoveShortcut: Removing shortcut {shortcut.Name} if it exists in our shortcut repository"); if (!(shortcut is ShortcutItem)) return false; @@ -189,12 +189,12 @@ namespace DisplayMagician { SaveShortcuts(); IsValidRefresh(); - logger.Debug($"ShortcutRepository/RemoveShortcut: Our shortcut repository does contain a shortcut we were looking for"); + logger.Trace($"ShortcutRepository/RemoveShortcut: Our shortcut repository does contain a shortcut we were looking for"); return true; } else if (numRemoved == 0) { - logger.Debug($"ShortcutRepository/RemoveShortcut: Our shortcut repository doesn't contain a shortcut we were looking for"); + logger.Trace($"ShortcutRepository/RemoveShortcut: Our shortcut repository doesn't contain a shortcut we were looking for"); return false; } @@ -206,7 +206,7 @@ namespace DisplayMagician public static bool RemoveShortcut(string shortcutNameOrUuid) { - logger.Debug($"ShortcutRepository/RemoveShortcut2: Removing shortcut {shortcutNameOrUuid} if it exists in our shortcut repository"); + logger.Trace($"ShortcutRepository/RemoveShortcut2: Removing shortcut {shortcutNameOrUuid} if it exists in our shortcut repository"); if (String.IsNullOrWhiteSpace(shortcutNameOrUuid)) { @@ -245,12 +245,12 @@ namespace DisplayMagician { SaveShortcuts(); IsValidRefresh(); - logger.Debug($"ShortcutRepository/RemoveShortcut2: Our shortcut repository does contain a shortcut with Name or UUID {shortcutNameOrUuid}"); + logger.Trace($"ShortcutRepository/RemoveShortcut2: Our shortcut repository does contain a shortcut with Name or UUID {shortcutNameOrUuid}"); return true; } else if (numRemoved == 0) { - logger.Debug($"ShortcutRepository/RemoveShortcut2: Our shortcut repository doesn't contain a shortcut with Name or UUID {shortcutNameOrUuid}"); + logger.Trace($"ShortcutRepository/RemoveShortcut2: Our shortcut repository doesn't contain a shortcut with Name or UUID {shortcutNameOrUuid}"); return false; } else @@ -262,7 +262,7 @@ namespace DisplayMagician public static bool ContainsShortcut(ShortcutItem shortcut) { - logger.Debug($"ShortcutRepository/ContainsShortcut: Checking whether {shortcut.Name} exists in our shortcut repository"); + logger.Trace($"ShortcutRepository/ContainsShortcut: Checking whether {shortcut.Name} exists in our shortcut repository"); if (!(shortcut is ShortcutItem)) return false; @@ -271,7 +271,7 @@ namespace DisplayMagician { if (testShortcut.UUID.Equals(shortcut.UUID, StringComparison.OrdinalIgnoreCase)) { - logger.Debug($"ShortcutRepository/ContainsShortcut: {shortcut.Name} does exist in our shortcut repository"); + logger.Trace($"ShortcutRepository/ContainsShortcut: {shortcut.Name} does exist in our shortcut repository"); return true; } } @@ -282,7 +282,7 @@ namespace DisplayMagician public static bool ContainsShortcut(string shortcutNameOrUuid) { - logger.Debug($"ShortcutRepository/ContainsShortcut2: Checking whether {shortcutNameOrUuid} exists in our shortcut repository"); + logger.Trace($"ShortcutRepository/ContainsShortcut2: Checking whether {shortcutNameOrUuid} exists in our shortcut repository"); if (String.IsNullOrWhiteSpace(shortcutNameOrUuid)) { @@ -297,7 +297,7 @@ namespace DisplayMagician { if (testShortcut.UUID.Equals(shortcutNameOrUuid, StringComparison.OrdinalIgnoreCase)) { - logger.Debug($"ShortcutRepository/ContainsShortcut2: Shortcut with UUID {shortcutNameOrUuid} does exist in our shortcut repository"); + logger.Trace($"ShortcutRepository/ContainsShortcut2: Shortcut with UUID {shortcutNameOrUuid} does exist in our shortcut repository"); return true; } } @@ -309,14 +309,14 @@ namespace DisplayMagician { if (testShortcut.Name.Equals(shortcutNameOrUuid, StringComparison.OrdinalIgnoreCase)) { - logger.Debug($"ShortcutRepository/ContainsShortcut2: Shortcut with name {shortcutNameOrUuid} does exist in our shortcut repository"); + logger.Trace($"ShortcutRepository/ContainsShortcut2: Shortcut with name {shortcutNameOrUuid} does exist in our shortcut repository"); return true; } } } - logger.Debug($"ShortcutRepository/ContainsShortcut2: Shortcut with name {shortcutNameOrUuid} doesn't exist in our shortcut repository"); + logger.Trace($"ShortcutRepository/ContainsShortcut2: Shortcut with name {shortcutNameOrUuid} doesn't exist in our shortcut repository"); return false; } @@ -324,7 +324,7 @@ namespace DisplayMagician public static ShortcutItem GetShortcut(string shortcutNameOrUuid) { - logger.Debug($"ShortcutRepository/GetShortcut: Finding and returning {shortcutNameOrUuid} if it exists in our shortcut repository"); + logger.Trace($"ShortcutRepository/GetShortcut: Finding and returning {shortcutNameOrUuid} if it exists in our shortcut repository"); if (String.IsNullOrWhiteSpace(shortcutNameOrUuid)) { @@ -339,7 +339,7 @@ namespace DisplayMagician { if (testShortcut.UUID.Equals(shortcutNameOrUuid, StringComparison.OrdinalIgnoreCase)) { - logger.Debug($"ShortcutRepository/GetShortcut: Returning shortcut with UUID {shortcutNameOrUuid}"); + logger.Trace($"ShortcutRepository/GetShortcut: Returning shortcut with UUID {shortcutNameOrUuid}"); return testShortcut; } } @@ -351,14 +351,14 @@ namespace DisplayMagician { if (testShortcut.Name.Equals(shortcutNameOrUuid, StringComparison.OrdinalIgnoreCase)) { - logger.Debug($"ShortcutRepository/GetShortcut: Returning shortcut with Name {shortcutNameOrUuid}"); + logger.Trace($"ShortcutRepository/GetShortcut: Returning shortcut with Name {shortcutNameOrUuid}"); return testShortcut; } } } - logger.Debug($"ShortcutRepository/GetShortcut: No shortcut was found to return with UUI or Name {shortcutNameOrUuid}"); + logger.Trace($"ShortcutRepository/GetShortcut: No shortcut was found to return with UUID or Name {shortcutNameOrUuid}"); return null; } @@ -943,7 +943,7 @@ namespace DisplayMagician // Now look for the thing we're supposed to monitor // and wait until it starts up List processesToMonitor = new List(); - for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500) + for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500) { // Look for the processes with the ProcessName we sorted out earlier processesToMonitor = Process.GetProcessesByName(processNameToLookFor).ToList(); @@ -1077,7 +1077,7 @@ namespace DisplayMagician Thread.Sleep(500); // Wait for Steam game to update if needed - for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500) + for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500) { if (!steamGameToRun.IsUpdating) @@ -1218,17 +1218,21 @@ namespace DisplayMagician // Wait for Uplay to start List uplayProcesses = null; - for (int secs = 0; secs >= (shortcutToUse.StartTimeout * 1000); secs += 500) + for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500) { - // Look for the processes with the ProcessName we sorted out earlier - uplayProcesses = Process.GetProcessesByName("upc").ToList(); + // 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()); // If we have found one or more processes then we should be good to go // so let's break if (uplayProcesses.Count > 0) { - logger.Debug($"ShortcutRepository/RunShortcut: Found {uplayProcesses.Count} 'upc' processes have started"); + Thread.Sleep(500); + logger.Debug($"ShortcutRepository/RunShortcut: Found {uplayProcesses.Count} 'UplayGameLauncher' processes have started"); break; } @@ -1238,13 +1242,11 @@ namespace DisplayMagician } - // Delay 5secs - Thread.Sleep(5000); - logger.Debug($"ShortcutRepository/RunShortcut: Pausing for 5 seconds to let the Uplay process start the game."); + //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) + for (int secs = 0; secs <= (shortcutToUse.StartTimeout * 1000); secs += 500) { if (uplayGameToRun.IsRunning) diff --git a/DisplayMagician/UIForms/ShortcutLibraryForm.cs b/DisplayMagician/UIForms/ShortcutLibraryForm.cs index e2ffc64..996bfe7 100644 --- a/DisplayMagician/UIForms/ShortcutLibraryForm.cs +++ b/DisplayMagician/UIForms/ShortcutLibraryForm.cs @@ -330,6 +330,7 @@ namespace DisplayMagician.UIForms // Create a MaskForm that will cover the ShortcutLibrary Window to lock // the controls and inform the user that the game is running.... MaskedForm maskedForm = MaskedForm.Show(this, message); + maskedForm.BringToFront(); // Get the MainForm so we can access the NotifyIcon on it. MainForm mainForm = (MainForm)this.Owner; From 4c58920e61ec2cbb9c6b890adbdc205d943bbf2c Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 21:51:51 +1200 Subject: [PATCH 14/16] Attempt to fix shortcut library drawing This is the first attempt at fixing the shortcut library drawing issue. When the app is frozen waiting for some games/apps to finish, the ImageListView refreshes, but doesn't refresh with any icons, so it all looks a bit pants. This is my first attempt at fixing that. --- DisplayMagician/UIForms/ShortcutLibraryForm.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DisplayMagician/UIForms/ShortcutLibraryForm.cs b/DisplayMagician/UIForms/ShortcutLibraryForm.cs index 996bfe7..e83804a 100644 --- a/DisplayMagician/UIForms/ShortcutLibraryForm.cs +++ b/DisplayMagician/UIForms/ShortcutLibraryForm.cs @@ -332,12 +332,17 @@ namespace DisplayMagician.UIForms MaskedForm maskedForm = MaskedForm.Show(this, message); maskedForm.BringToFront(); + ilv_saved_shortcuts.SuspendLayout(); + ilv_saved_shortcuts.Refresh(); + // Get the MainForm so we can access the NotifyIcon on it. MainForm mainForm = (MainForm)this.Owner; // Run the shortcut ShortcutRepository.RunShortcut(_selectedShortcut, mainForm.notifyIcon); + ilv_saved_shortcuts.ResumeLayout(); + maskedForm.Close(); } else From 0c4023fa64f831f84de38d9cee6813cb1209e01e Mon Sep 17 00:00:00 2001 From: Terry MacDonald Date: Sat, 10 Apr 2021 22:21:56 +1200 Subject: [PATCH 15/16] Update to v1.0.4 --- DisplayMagician/Properties/AssemblyInfo.cs | 4 ++-- DisplayMagicianLogReporter/Properties/AssemblyInfo.cs | 4 ++-- .../Includes/DisplayMagicianVariables.wxi | 9 +-------- DisplayMagicianShared/Properties/AssemblyInfo.cs | 4 ++-- DisplayMagicianShellExtension/Properties/AssemblyInfo.cs | 4 ++-- docs/update/index.json | 6 +++--- 6 files changed, 12 insertions(+), 19 deletions(-) diff --git a/DisplayMagician/Properties/AssemblyInfo.cs b/DisplayMagician/Properties/AssemblyInfo.cs index d77b7de..87e6357 100644 --- a/DisplayMagician/Properties/AssemblyInfo.cs +++ b/DisplayMagician/Properties/AssemblyInfo.cs @@ -37,8 +37,8 @@ using System.Runtime.InteropServices; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.3.1")] -[assembly: AssemblyFileVersion("1.0.3.1")] +[assembly: AssemblyVersion("1.0.4.0")] +[assembly: AssemblyFileVersion("1.0.4.0")] [assembly: NeutralResourcesLanguage("en")] [assembly: CLSCompliant(true)] \ No newline at end of file diff --git a/DisplayMagicianLogReporter/Properties/AssemblyInfo.cs b/DisplayMagicianLogReporter/Properties/AssemblyInfo.cs index 67be439..211abb2 100644 --- a/DisplayMagicianLogReporter/Properties/AssemblyInfo.cs +++ b/DisplayMagicianLogReporter/Properties/AssemblyInfo.cs @@ -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.3.0")] -[assembly: AssemblyFileVersion("1.0.3.0")] \ No newline at end of file +[assembly: AssemblyVersion("1.0.4.0")] +[assembly: AssemblyFileVersion("1.0.4.0")] \ No newline at end of file diff --git a/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi b/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi index 34efacc..7d0e64a 100644 --- a/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi +++ b/DisplayMagicianSetup/Includes/DisplayMagicianVariables.wxi @@ -6,18 +6,11 @@ --> - + - - - - - - -