Fixed Steam and Uplay game detection

Fixed an issue where Steam and Uplay don't detect the
game correctly. Now they find the processes themselves.

Also fixed ProgramSettings so that it generates a new
settings file on startup.

Also added LogLevel option to the ProgramSettings so that
I can start rolling out the NLog log statements to report
errors from the binary when it's installed on people's
PCs.
This commit is contained in:
Terry MacDonald 2020-12-09 20:47:30 +13:00
parent c0389cdba7
commit 0830ed58dd
5 changed files with 135 additions and 145 deletions

View File

@ -3,39 +3,15 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security;
using System.Drawing;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using DisplayMagician.Resources;
using DisplayMagician.Shared;
//using HtmlAgilityPack;
using Microsoft.Win32;
using Newtonsoft.Json;
//using VdfParser;
//using Gameloop.Vdf;
using System.Collections.ObjectModel;
using ValveKeyValue;
using System.Security.Cryptography;
using System.ServiceModel.Configuration;
using DisplayMagician.GameLibraries.SteamAppInfoParser;
using TsudaKageyu;
using System.Drawing.IconLib;
using System.Drawing.IconLib.Exceptions;
using System.Diagnostics;
namespace DisplayMagician.GameLibraries
{
public class SteamGame : Game
{
/*private static string SteamLibrary.SteamExe;
private static string SteamLibrary.SteamPath;
private static string _steamConfigVdfFile;
private static string _registrySteamKey = @"SOFTWARE\\Valve\\Steam";
private static string _registryAppsKey = $@"{_registrySteamKey}\\Apps";*/
private string _gameRegistryKey;
private uint _steamGameId;
private string _steamGameName;
@ -46,15 +22,6 @@ namespace DisplayMagician.GameLibraries
private string _steamGameIconPath;
private static List<SteamGame> _allInstalledSteamGames = null;
/*private struct SteamAppInfo
{
public uint GameID;
public string GameName;
public List<string> GameExes;
public string GameInstallDir;
public string GameSteamIconPath;
}*/
static SteamGame()
{
ServicePointManager.ServerCertificateValidationCallback +=
@ -104,47 +71,25 @@ namespace DisplayMagician.GameLibraries
public override string Directory
{
get => _steamGameExePath;
set => _steamGameExePath = value;
get => _steamGameDir;
set => _steamGameDir = value;
}
public override bool IsRunning
{
get
{
/*try
int numGameProcesses = 0;
List<Process> gameProcesses = Process.GetProcessesByName(_steamGameProcessName).ToList();
foreach (Process gameProcess in gameProcesses)
{
using (
var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree))
{
if ((int)key?.GetValue(@"Running", 0) == 1)
{
return true;
}
return false;
}
if (gameProcess.MainModule.FileName.StartsWith(_steamGameExePath))
numGameProcesses++;
}
catch (SecurityException ex)
{
Console.WriteLine($"SteamGame/IsRunning securityexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
if (ex.Source != null)
Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message);
throw;
}
catch (IOException ex)
{
// Extract some information from this exception, and then
// throw it to the parent method.
Console.WriteLine($"SteamGame/IsRunning ioexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
if (ex.Source != null)
Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message);
throw;
}*/
bool isRunning = Process.GetProcessesByName(_steamGameProcessName)
.FirstOrDefault(p => p.MainModule.FileName
.StartsWith(ExePath,StringComparison.OrdinalIgnoreCase)) != default(Process);
return isRunning;
if (numGameProcesses > 0)
return true;
else
return false;
}
}
@ -193,6 +138,7 @@ namespace DisplayMagician.GameLibraries
steamGame.Id = Id;
steamGame.Name = Name;
steamGame.ExePath = ExePath;
steamGame.Directory = Directory;
return true;
}

View File

@ -107,47 +107,25 @@ namespace DisplayMagician.GameLibraries
public override string Directory
{
get => _uplayGameExePath;
set => _uplayGameExePath = value;
get => _uplayGameDir;
set => _uplayGameDir = value;
}
public override bool IsRunning
{
get
{
/*try
int numGameProcesses = 0;
List<Process> gameProcesses = Process.GetProcessesByName(_uplayGameProcessName).ToList();
foreach (Process gameProcess in gameProcesses)
{
using (
var key = Registry.CurrentUser.OpenSubKey(_gameRegistryKey, RegistryKeyPermissionCheck.ReadSubTree))
{
if ((int)key?.GetValue(@"Running", 0) == 1)
{
return true;
}
return false;
}
if (gameProcess.MainModule.FileName.StartsWith(_uplayGameExePath))
numGameProcesses++;
}
catch (SecurityException ex)
{
Console.WriteLine($"UplayGame/IsRunning securityexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
if (ex.Source != null)
Console.WriteLine("SecurityException source: {0} - Message: {1}", ex.Source, ex.Message);
throw;
}
catch (IOException ex)
{
// Extract some information from this exception, and then
// throw it to the parent method.
Console.WriteLine($"UplayGame/IsRunning ioexception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
if (ex.Source != null)
Console.WriteLine("IOException source: {0} - Message: {1}", ex.Source, ex.Message);
throw;
}*/
bool isRunning = Process.GetProcessesByName(_uplayGameProcessName)
.FirstOrDefault(p => p.MainModule.FileName
.StartsWith(ExePath, StringComparison.OrdinalIgnoreCase)) != default(Process);
return isRunning;
if (numGameProcesses > 0)
return true;
else
return false;
}
}
@ -196,6 +174,7 @@ namespace DisplayMagician.GameLibraries
uplayGame.Id = Id;
uplayGame.Name = Name;
uplayGame.ExePath = ExePath;
uplayGame.Directory = Directory;
return true;
}

View File

@ -1,25 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using McMaster.Extensions.CommandLineUtils;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using DisplayMagician.InterProcess;
using DisplayMagician.Resources;
using DisplayMagician.GameLibraries;
using DisplayMagician.Shared;
using DisplayMagician.UIForms;
using System.Net.NetworkInformation;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Diagnostics.Contracts;
namespace DisplayMagician {
@ -60,7 +53,7 @@ namespace DisplayMagician {
// Targets where to log to: File and Console
string date = DateTime.Now.ToString("yyyyMMdd.HHmmss");
string AppLogFilename = Path.Combine(Program.AppLogPath, $"DisplayMagician-{date}.log");
string AppLogFilename = Path.Combine(Program.AppLogPath, $"DisplayMagician.log");
// Create the Shortcut Icon Cache if it doesn't exist so that it's avilable for all the program
if (!Directory.Exists(AppLogPath))
@ -80,9 +73,34 @@ namespace DisplayMagician {
};
var logconsole = new NLog.Targets.ConsoleTarget("logconsole");
// Rules for mapping loggers to targets
// Load the program settings
AppProgramSettings = ProgramSettings.LoadSettings();
// Rules for mapping loggers to targets
NLog.LogLevel logLevel = null;
switch (AppProgramSettings.LogLevel)
{
case "Trace":
logLevel = NLog.LogLevel.Trace;
break;
case "Info":
logLevel = NLog.LogLevel.Info;
break;
case "Warn":
logLevel = NLog.LogLevel.Warn;
break;
case "Error":
logLevel = NLog.LogLevel.Error;
break;
case "Debug":
logLevel = NLog.LogLevel.Debug;
break;
default:
logLevel = NLog.LogLevel.Warn;
break;
}
config.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, logconsole);
config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Fatal, logfile);
config.AddRule(logLevel, NLog.LogLevel.Fatal, logfile);
// Apply config
NLog.LogManager.Configuration = config;
@ -103,8 +121,6 @@ namespace DisplayMagician {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Load the program settings
AppProgramSettings = ProgramSettings.LoadSettings();
var app = new CommandLineApplication();

View File

@ -5,9 +5,11 @@ using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NLog;
namespace DisplayMagician
{
public class ProgramSettings
{
#region Class Variables
@ -19,6 +21,7 @@ namespace DisplayMagician
#region Instance Variables
private bool _minimiseOnStart = false;
private string _logLevel = NLog.LogLevel.Warn.ToString();
#endregion
#region Class Properties
@ -38,6 +41,45 @@ namespace DisplayMagician
}
}
public string LogLevel
{
get
{
return _logLevel;
}
set
{
switch (value.ToLower())
{
case "trace":
_logLevel = NLog.LogLevel.Trace.ToString();
break;
case "debug":
_logLevel = NLog.LogLevel.Debug.ToString();
break;
case "info":
_logLevel = NLog.LogLevel.Info.ToString();
break;
case "warn":
_logLevel = NLog.LogLevel.Warn.ToString();
break;
case "Error":
_logLevel = NLog.LogLevel.Error.ToString();
break;
default:
_logLevel = NLog.LogLevel.Warn.ToString();
break;
}
// Because a value has changed, we need to save the setting
// to remember it for later.
if (_programSettingsLoaded)
SaveSettings();
}
}
public static Version FileVersion
{
get => new Version(1, 0, 0);
@ -76,6 +118,11 @@ namespace DisplayMagician
}
}
}
else
{
programSettings = new ProgramSettings();
programSettings.SaveSettings();
}
// If there isn't any settings in the file then create a new ProgramSettings object
if (programSettings == null)

View File

@ -29,6 +29,7 @@ namespace DisplayMagician
private static string _shortcutStorageJsonFileName = Path.Combine(AppShortcutStoragePath, $"Shortcuts_{Version.ToString(2)}.json");
private static string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
private static CoreAudioController _audioController = null;
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
#endregion
#region Class Constructors
@ -48,7 +49,8 @@ namespace DisplayMagician
}
catch (Exception ex)
{
Console.WriteLine($"ShortcutItem/Instansiation exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
//Console.WriteLine($"ShortcutItem/Instansiation exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
logger.Error(ex, $"ShortcutRepository/Instansiation exception during class construction");
// ignored
}
@ -413,6 +415,7 @@ namespace DisplayMagician
(bool valid, string reason) = shortcutToUse.IsValid();
if (!valid)
{
logger.Error($"ShortcutRepository/RunShortcut error. shortcutToUse isn't valid");
MessageBox.Show(
$"Unable to run the shortcut '{shortcutToUse.Name}': {reason}",
@"Cannot run the Shortcut",
@ -443,6 +446,7 @@ namespace DisplayMagician
if (!Program.ApplyProfile(shortcutToUse.ProfileToUse))
{
Console.WriteLine($"ERROR - Cannot apply '{shortcutToUse.ProfileToUse.Name}' Display Profile");
logger.Error($"ShortcutRepository/RunShortcut cannot apply '{shortcutToUse.ProfileToUse.Name}' Display Profile");
}
}
@ -516,7 +520,7 @@ namespace DisplayMagician
// This means we need to save the state if the temporaryIcon
// is false.
// Conversely, if temporaryIcon is true, then we need
// to create a NotifyIncon as MainFOrm isn't running to create
// to create a NotifyIncon as MainForm isn't running to create
// one for us already!
if (notifyIcon == null)
temporaryNotifyIcon = true;
@ -539,6 +543,7 @@ namespace DisplayMagician
catch (Exception ex)
{
Console.WriteLine($"ShortcutRepository/RunShortcut exception: Trying to {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
logger.Error(ex, $"ShortcutRepository/RunShortcut exception setting NotifyIcon");
// ignored
}
}
@ -632,6 +637,7 @@ namespace DisplayMagician
catch (InvalidOperationException ex)
{
Console.WriteLine($"ShortcutRepository/RunShortcut exception 2: {ex.Message}: {ex.StackTrace} - {ex.InnerException}");
logger.Error(ex, $"ShortcutRepository/RunShortcut exception waiting for the monitored process to exit");
processExitCount++;
}
}
@ -662,6 +668,7 @@ namespace DisplayMagician
{
address += "/" + shortcutToUse.GameArguments;
}
logger.Debug($"ShortcutRepository/RunShortcut Steam launch address is {address}");
// Start the URI Handler to run Steam
Console.WriteLine($"Starting Steam Game: {steamGameToRun.Name}");
@ -695,24 +702,21 @@ namespace DisplayMagician
notifyIcon.Text = $"DisplayMagician: Running {steamGameToRun.Name.Substring(0, 41)}...";
Application.DoEvents();
// Wait 300ms for the game process to spawn
Thread.Sleep(300);
// Now check it's actually started
if (steamGameToRun.IsRunning)
{
// Wait for the game to exit
Console.WriteLine($"Waiting for {steamGameToRun.Name} to exit.");
while (true)
{
if (!steamGameToRun.IsRunning)
{
break;
}
Thread.Sleep(300);
// Wait for the game to exit
Console.WriteLine($"Waiting for {steamGameToRun.Name} to exit.");
logger.Info($"ShortcutRepository/RunShortcut - waiting for Steam Game {steamGameToRun.Name} to exit.");
while (true)
{
if (!steamGameToRun.IsRunning)
{
break;
}
Console.WriteLine($"{steamGameToRun.Name} has exited.");
Thread.Sleep(300);
}
Console.WriteLine($"{steamGameToRun.Name} has exited.");
logger.Info($"ShortcutRepository/RunShortcut - Steam Game {steamGameToRun.Name} has exited.");
}
@ -729,6 +733,7 @@ namespace DisplayMagician
// Prepare to start the steam game using the URI interface
// as used by Steam for it's own desktop shortcuts.
var address = $"uplay://launch/{uplayGameToRun.Id}";
logger.Debug($"ShortcutRepository/RunShortcut Uplay launch address is {address}");
if (shortcutToUse.GameArgumentsRequired)
{
address += "/" + shortcutToUse.GameArguments;
@ -760,28 +765,26 @@ namespace DisplayMagician
IPCService.GetInstance().Status = InstanceStatus.OnHold;
// Add a status notification icon in the status area
notifyIcon.Text = $"DisplayMagician: Running {uplayGameToRun.Name.Substring(0,41)}...";
if (uplayGameToRun.Name.Length <= 41)
notifyIcon.Text = $"DisplayMagician: Running {uplayGameToRun.Name}...";
else
notifyIcon.Text = $"DisplayMagician: Running {uplayGameToRun.Name.Substring(0, 41)}...";
Application.DoEvents();
// Wait 300ms for the game process to spawn
Thread.Sleep(300);
// Now check it's actually started
if (uplayGameToRun.IsRunning)
// Wait for the game to exit
Console.WriteLine($"Waiting for {uplayGameToRun.Name} to exit.");
logger.Info($"ShortcutRepository/RunShortcut - waiting for Uplay Game {uplayGameToRun.Name} to exit.");
while (true)
{
// Wait for the game to exit
Console.WriteLine($"Waiting for {uplayGameToRun.Name} to exit.");
while (true)
if (!uplayGameToRun.IsRunning)
{
if (!uplayGameToRun.IsRunning)
{
break;
}
Thread.Sleep(300);
break;
}
Console.WriteLine($"{uplayGameToRun.Name} has exited.");
}
Thread.Sleep(300);
}
Console.WriteLine($"{uplayGameToRun.Name} has exited.");
logger.Info($"ShortcutRepository/RunShortcut - Uplay Game {uplayGameToRun.Name} has exited.");
}
@ -884,5 +887,4 @@ namespace DisplayMagician
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
}