2020-07-23 06:31:00 +00:00
using HeliosPlus.GameLibraries ;
using HeliosPlus.InterProcess ;
using HeliosPlus.Resources ;
using HeliosPlus.Shared ;
2020-06-01 10:25:52 +00:00
using Newtonsoft.Json ;
2020-07-23 23:06:33 +00:00
using NvAPIWrapper.Mosaic ;
using NvAPIWrapper.Native.Mosaic ;
2020-06-01 10:25:52 +00:00
using System ;
using System.Collections.Generic ;
2020-07-23 06:31:00 +00:00
using System.Diagnostics ;
2020-06-01 10:25:52 +00:00
using System.Drawing.IconLib ;
using System.IO ;
using System.Linq ;
using System.Text ;
2020-06-15 09:57:46 +00:00
using System.Text.RegularExpressions ;
2020-07-23 06:31:00 +00:00
using System.Threading ;
2020-06-01 10:25:52 +00:00
using System.Threading.Tasks ;
using System.Windows.Forms ;
namespace HeliosPlus
{
2020-07-21 07:50:41 +00:00
public static class ShortcutRepository
2020-06-01 10:25:52 +00:00
{
#region Class Variables
// Common items to the class
2020-08-07 03:59:23 +00:00
private static List < ShortcutItem > _allShortcuts = new List < ShortcutItem > ( ) ;
private static bool _shortcutsLoaded = false ;
2020-06-01 10:25:52 +00:00
// Other constants that are useful
2020-08-18 22:16:04 +00:00
private static string AppShortcutStoragePath = Path . Combine ( Program . AppDataPath , $"Shortcuts" ) ;
private static string _shortcutStorageJsonFileName = Path . Combine ( AppShortcutStoragePath , $"Shortcuts_{Version.ToString(2)}.json" ) ;
2020-07-21 11:40:33 +00:00
private static string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$" ;
2020-06-01 10:25:52 +00:00
#endregion
#region Class Constructors
2020-07-21 07:50:41 +00:00
static ShortcutRepository ( )
2020-06-01 10:25:52 +00:00
{
2020-08-18 22:16:04 +00:00
try
{
NvAPIWrapper . NVIDIA . Initialize ( ) ;
// 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 ( Exception ex )
{
Console . WriteLine ( $"ShortcutItem/Instansiation exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
// ignored
}
2020-06-01 10:25:52 +00:00
// Load the Shortcuts from storage
2020-06-15 09:57:46 +00:00
LoadShortcuts ( ) ;
2020-06-01 10:25:52 +00:00
}
2020-07-21 07:50:41 +00:00
2020-06-01 10:25:52 +00:00
#endregion
#region Class Properties
2020-06-07 08:48:45 +00:00
public static List < ShortcutItem > AllShortcuts
2020-06-01 10:25:52 +00:00
{
get
{
2020-08-07 03:59:23 +00:00
if ( ! _shortcutsLoaded )
2020-06-01 10:25:52 +00:00
// Load the Shortcuts from storage
2020-06-15 09:57:46 +00:00
LoadShortcuts ( ) ;
2020-08-07 03:59:23 +00:00
2020-06-01 10:25:52 +00:00
return _allShortcuts ;
}
}
public static int ShortcutCount
{
get
{
2020-08-07 03:59:23 +00:00
if ( ! _shortcutsLoaded )
// Load the Shortcuts from storage
LoadShortcuts ( ) ;
2020-06-01 10:25:52 +00:00
return _allShortcuts . Count ;
}
}
2020-07-23 23:06:33 +00:00
public static Version Version
{
get = > new Version ( 1 , 0 , 0 ) ;
}
2020-06-01 10:25:52 +00:00
#endregion
#region Class Methods
2020-06-07 08:48:45 +00:00
public static bool AddShortcut ( ShortcutItem shortcut )
2020-06-01 10:25:52 +00:00
{
2020-06-07 08:48:45 +00:00
if ( ! ( shortcut is ShortcutItem ) )
2020-06-01 10:25:52 +00:00
return false ;
// Doublecheck if it already exists
// Because then we just update the one that already exists
if ( ContainsShortcut ( shortcut ) )
{
// We update the existing Shortcut with the data over
2020-06-15 09:57:46 +00:00
ShortcutItem shortcutToUpdate = GetShortcut ( shortcut . UUID ) ;
2020-06-01 10:25:52 +00:00
shortcut . CopyTo ( shortcutToUpdate ) ;
}
else
{
// Add the shortcut to the list of shortcuts
_allShortcuts . Add ( shortcut ) ;
}
//Doublecheck it's been added
if ( ContainsShortcut ( shortcut ) )
{
// Generate the Shortcut Icon ready to be used
SaveShortcutIconToCache ( shortcut ) ;
// Save the shortcuts JSON as it's different
SaveShortcuts ( ) ;
return true ;
}
else
return false ;
}
2020-06-07 08:48:45 +00:00
public static bool RemoveShortcut ( ShortcutItem shortcut )
2020-06-01 10:25:52 +00:00
{
2020-06-07 08:48:45 +00:00
if ( ! ( shortcut is ShortcutItem ) )
2020-06-01 10:25:52 +00:00
return false ;
// Remove the Shortcut Icons from the Cache
2020-07-23 23:06:33 +00:00
List < ShortcutItem > shortcutsToRemove = _allShortcuts . FindAll ( item = > item . UUID . Equals ( shortcut . UUID , StringComparison . InvariantCultureIgnoreCase ) ) ;
2020-06-07 08:48:45 +00:00
foreach ( ShortcutItem shortcutToRemove in shortcutsToRemove )
2020-06-01 10:25:52 +00:00
{
try
{
File . Delete ( shortcutToRemove . SavedShortcutIconCacheFilename ) ;
}
2020-07-15 08:11:38 +00:00
catch ( Exception ex )
2020-06-01 10:25:52 +00:00
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutRepository/RemoveShortcut exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-15 08:11:38 +00:00
2020-06-01 10:25:52 +00:00
// TODO check and report
}
}
// Remove the shortcut from the list.
2020-07-23 23:06:33 +00:00
int numRemoved = _allShortcuts . RemoveAll ( item = > item . UUID . Equals ( shortcut . UUID , StringComparison . InvariantCultureIgnoreCase ) ) ;
2020-06-01 10:25:52 +00:00
if ( numRemoved = = 1 )
{
SaveShortcuts ( ) ;
return true ;
}
else if ( numRemoved = = 0 )
return false ;
else
throw new ShortcutRepositoryException ( ) ;
}
2020-06-15 09:57:46 +00:00
public static bool RemoveShortcut ( string shortcutNameOrUuid )
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
if ( String . IsNullOrWhiteSpace ( shortcutNameOrUuid ) )
2020-06-01 10:25:52 +00:00
return false ;
2020-06-15 09:57:46 +00:00
List < ShortcutItem > shortcutsToRemove ;
int numRemoved ;
2020-06-01 10:25:52 +00:00
2020-07-21 11:40:33 +00:00
//string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
2020-06-15 09:57:46 +00:00
Match match = Regex . Match ( shortcutNameOrUuid , uuidV4Regex , RegexOptions . IgnoreCase ) ;
if ( match . Success )
2020-06-01 10:25:52 +00:00
{
2020-07-23 23:06:33 +00:00
shortcutsToRemove = _allShortcuts . FindAll ( item = > item . UUID . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) ) ;
numRemoved = _allShortcuts . RemoveAll ( item = > item . UUID . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) ) ;
2020-06-01 10:25:52 +00:00
}
else
2020-06-15 09:57:46 +00:00
{
2020-07-23 23:06:33 +00:00
shortcutsToRemove = _allShortcuts . FindAll ( item = > item . Name . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) ) ;
numRemoved = _allShortcuts . RemoveAll ( item = > item . Name . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) ) ;
2020-06-15 09:57:46 +00:00
}
2020-06-01 10:25:52 +00:00
// Remove the Shortcut Icons from the Cache
2020-06-07 08:48:45 +00:00
foreach ( ShortcutItem shortcutToRemove in shortcutsToRemove )
2020-06-01 10:25:52 +00:00
{
try
{
File . Delete ( shortcutToRemove . SavedShortcutIconCacheFilename ) ;
}
2020-07-15 08:11:38 +00:00
catch ( Exception ex )
2020-06-01 10:25:52 +00:00
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutRepository/RemoveShortcut exception 2: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-15 08:11:38 +00:00
2020-06-01 10:25:52 +00:00
// TODO check and report
}
}
if ( numRemoved = = 1 )
{
SaveShortcuts ( ) ;
return true ;
2020-06-15 09:57:46 +00:00
}
2020-06-01 10:25:52 +00:00
else if ( numRemoved = = 0 )
return false ;
else
throw new ShortcutRepositoryException ( ) ;
2020-06-15 09:57:46 +00:00
2020-06-01 10:25:52 +00:00
}
2020-06-07 08:48:45 +00:00
public static bool ContainsShortcut ( ShortcutItem shortcut )
2020-06-01 10:25:52 +00:00
{
2020-06-07 08:48:45 +00:00
if ( ! ( shortcut is ShortcutItem ) )
2020-06-01 10:25:52 +00:00
return false ;
2020-06-07 08:48:45 +00:00
foreach ( ShortcutItem testShortcut in _allShortcuts )
2020-06-01 10:25:52 +00:00
{
2020-07-23 23:06:33 +00:00
if ( testShortcut . UUID . Equals ( shortcut . UUID , StringComparison . InvariantCultureIgnoreCase ) )
2020-06-01 10:25:52 +00:00
return true ;
}
return false ;
}
2020-06-15 09:57:46 +00:00
public static bool ContainsShortcut ( string shortcutNameOrUuid )
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
if ( String . IsNullOrWhiteSpace ( shortcutNameOrUuid ) )
2020-06-01 10:25:52 +00:00
return false ;
2020-07-21 11:40:33 +00:00
//string uuidV4Regex = @"(?im)^[{(]?[0-9A-F]{8}[-]?(?:[0-9A-F]{4}[-]?){3}[0-9A-F]{12}[)}]?$";
2020-06-15 09:57:46 +00:00
Match match = Regex . Match ( shortcutNameOrUuid , uuidV4Regex , RegexOptions . IgnoreCase ) ;
if ( match . Success )
{
foreach ( ShortcutItem testShortcut in _allShortcuts )
{
2020-07-23 23:06:33 +00:00
if ( testShortcut . UUID . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) )
2020-06-15 09:57:46 +00:00
return true ;
}
2020-06-01 10:25:52 +00:00
2020-06-15 09:57:46 +00:00
}
else
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
foreach ( ShortcutItem testShortcut in _allShortcuts )
{
2020-07-23 23:06:33 +00:00
if ( testShortcut . Name . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) )
2020-06-15 09:57:46 +00:00
return true ;
}
2020-06-01 10:25:52 +00:00
}
return false ;
}
2020-06-15 09:57:46 +00:00
public static ShortcutItem GetShortcut ( string shortcutNameOrUuid )
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
if ( String . IsNullOrWhiteSpace ( shortcutNameOrUuid ) )
2020-06-01 10:25:52 +00:00
return null ;
2020-07-21 11:40:33 +00:00
//string uuidV4Regex = @"/^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i";
2020-06-15 09:57:46 +00:00
Match match = Regex . Match ( shortcutNameOrUuid , uuidV4Regex , RegexOptions . IgnoreCase ) ;
if ( match . Success )
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
foreach ( ShortcutItem testShortcut in _allShortcuts )
{
2020-07-23 23:06:33 +00:00
if ( testShortcut . UUID . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) )
2020-06-15 09:57:46 +00:00
return testShortcut ;
}
}
else
{
foreach ( ShortcutItem testShortcut in _allShortcuts )
{
2020-07-23 23:06:33 +00:00
if ( testShortcut . Name . Equals ( shortcutNameOrUuid , StringComparison . InvariantCultureIgnoreCase ) )
2020-06-15 09:57:46 +00:00
return testShortcut ;
}
2020-06-01 10:25:52 +00:00
}
return null ;
2020-06-15 09:57:46 +00:00
2020-06-01 10:25:52 +00:00
}
2020-06-15 09:57:46 +00:00
public static bool RenameShortcutProfile ( ProfileItem newProfile )
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
if ( ! ( newProfile is ProfileItem ) )
return false ;
2020-06-01 10:25:52 +00:00
2020-06-15 09:57:46 +00:00
foreach ( ShortcutItem testShortcut in ShortcutRepository . AllShortcuts )
2020-06-01 10:25:52 +00:00
{
2020-07-23 23:06:33 +00:00
if ( testShortcut . ProfileUUID . Equals ( newProfile . UUID , StringComparison . InvariantCultureIgnoreCase ) & & testShortcut . AutoName )
2020-06-15 09:57:46 +00:00
{
testShortcut . ProfileToUse = newProfile ;
testShortcut . AutoSuggestShortcutName ( ) ;
}
2020-06-01 10:25:52 +00:00
}
2020-06-15 09:57:46 +00:00
SaveShortcuts ( ) ;
2020-06-01 10:25:52 +00:00
2020-06-15 09:57:46 +00:00
return true ;
2020-06-01 10:25:52 +00:00
}
private static bool LoadShortcuts ( )
{
if ( File . Exists ( _shortcutStorageJsonFileName ) )
{
var json = File . ReadAllText ( _shortcutStorageJsonFileName , Encoding . Unicode ) ;
if ( ! string . IsNullOrWhiteSpace ( json ) )
{
2020-06-07 08:48:45 +00:00
List < ShortcutItem > shortcuts = new List < ShortcutItem > ( ) ;
2020-06-01 10:25:52 +00:00
try
{
2020-06-07 08:48:45 +00:00
_allShortcuts = JsonConvert . DeserializeObject < List < ShortcutItem > > ( json , new JsonSerializerSettings
2020-06-01 10:25:52 +00:00
{
MissingMemberHandling = MissingMemberHandling . Ignore ,
NullValueHandling = NullValueHandling . Ignore ,
DefaultValueHandling = DefaultValueHandling . Include ,
TypeNameHandling = TypeNameHandling . Auto
} ) ;
}
catch ( Exception ex )
{
// ignored
Console . WriteLine ( $"Unable to load Shortcuts from JSON file {_shortcutStorageJsonFileName}: " + ex . Message ) ;
}
// Lookup all the Profile Names in the Saved Profiles
2020-06-07 08:48:45 +00:00
foreach ( ShortcutItem updatedShortcut in _allShortcuts )
2020-06-01 10:25:52 +00:00
{
2020-06-14 04:20:52 +00:00
foreach ( ProfileItem profile in ProfileRepository . AllProfiles )
2020-06-01 10:25:52 +00:00
{
2020-06-15 09:57:46 +00:00
if ( profile . Equals ( updatedShortcut . ProfileToUse ) )
2020-06-01 10:25:52 +00:00
{
// And assign the matching Profile if we find it.
updatedShortcut . ProfileToUse = profile ;
updatedShortcut . IsPossible = true ;
break ;
}
}
}
}
}
2020-08-07 03:59:23 +00:00
_shortcutsLoaded = true ;
2020-06-01 10:25:52 +00:00
return true ;
}
private static bool SaveShortcuts ( )
{
2020-08-18 22:16:04 +00:00
if ( ! Directory . Exists ( AppShortcutStoragePath ) )
2020-06-01 10:25:52 +00:00
{
try
{
2020-08-18 22:16:04 +00:00
Directory . CreateDirectory ( AppShortcutStoragePath ) ;
2020-06-01 10:25:52 +00:00
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutRepository/SaveShortcuts exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-15 08:11:38 +00:00
2020-08-18 22:16:04 +00:00
Console . WriteLine ( $"Unable to create Shortcut folder {AppShortcutStoragePath}: " + ex . Message ) ;
2020-06-01 10:25:52 +00:00
}
}
try
{
var json = JsonConvert . SerializeObject ( _allShortcuts , Formatting . Indented , new JsonSerializerSettings
{
NullValueHandling = NullValueHandling . Include ,
DefaultValueHandling = DefaultValueHandling . Populate ,
TypeNameHandling = TypeNameHandling . Auto
} ) ;
if ( ! string . IsNullOrWhiteSpace ( json ) )
{
File . WriteAllText ( _shortcutStorageJsonFileName , json , Encoding . Unicode ) ;
return true ;
}
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutRepository/SaveShortcuts exception 2: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-15 08:11:38 +00:00
2020-06-01 10:25:52 +00:00
Console . WriteLine ( $"Unable to save Shortcut JSON file {_shortcutStorageJsonFileName}: " + ex . Message ) ;
}
return false ;
}
2020-06-07 08:48:45 +00:00
private static void SaveShortcutIconToCache ( ShortcutItem shortcut )
2020-06-01 10:25:52 +00:00
{
// Only add the rest of the options if the permanence is temporary
if ( shortcut . Permanence = = ShortcutPermanence . Temporary )
{
// Only add this set of options if the shortcut is to an standalone application
if ( shortcut . Category = = ShortcutCategory . Application )
{
// Work out the name of the shortcut we'll save.
2020-08-18 22:16:04 +00:00
shortcut . SavedShortcutIconCacheFilename = Path . Combine ( AppShortcutStoragePath , String . Concat ( @"executable-" , shortcut . ProfileToUse . UUID , "-" , Path . GetFileNameWithoutExtension ( shortcut . ExecutableNameAndPath ) , @".ico" ) ) ;
2020-06-01 10:25:52 +00:00
}
// Only add the rest of the options if the temporary switch radio button is set
// and if the game launching radio button is set
else if ( shortcut . Permanence = = ShortcutPermanence . Temporary )
{
// TODO need to make this work so at least one game library is installed
// i.e. if (!SteamGame.SteamInstalled && !UplayGame.UplayInstalled )
if ( shortcut . GameLibrary = = SupportedGameLibrary . Steam )
{
// Work out the name of the shortcut we'll save.
2020-08-18 22:16:04 +00:00
shortcut . SavedShortcutIconCacheFilename = Path . Combine ( AppShortcutStoragePath , String . Concat ( @"steam-" , shortcut . ProfileToUse . UUID , "-" , shortcut . GameAppId . ToString ( ) , @".ico" ) ) ;
2020-06-01 10:25:52 +00:00
}
else if ( shortcut . GameLibrary = = SupportedGameLibrary . Uplay )
{
// Work out the name of the shortcut we'll save.
2020-08-18 22:16:04 +00:00
shortcut . SavedShortcutIconCacheFilename = Path . Combine ( AppShortcutStoragePath , String . Concat ( @"uplay-" , shortcut . ProfileToUse . UUID , "-" , shortcut . GameAppId . ToString ( ) , @".ico" ) ) ;
2020-06-01 10:25:52 +00:00
}
}
}
// Only add the rest of the options if the shortcut is permanent
else
{
// Work out the name of the shortcut we'll save.
2020-08-18 22:16:04 +00:00
shortcut . SavedShortcutIconCacheFilename = Path . Combine ( AppShortcutStoragePath , String . Concat ( @"permanent-" , shortcut . ProfileToUse . UUID , @".ico" ) ) ;
2020-06-01 10:25:52 +00:00
}
MultiIcon shortcutIcon ;
try
{
2020-06-07 08:48:45 +00:00
//shortcutIcon = new ProfileIcon(shortcut.ProfileToUse).ToIconOverlay(shortcut.OriginalIconPath);
shortcutIcon = shortcut . ToIconOverlay ( ) ;
2020-06-01 10:25:52 +00:00
shortcutIcon . Save ( shortcut . SavedShortcutIconCacheFilename , MultiIconFormat . ICO ) ;
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutRepository/SaveShortcutIconToCache exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-15 08:11:38 +00:00
2020-06-01 10:25:52 +00:00
// If we fail to create an icon based on the original executable or game
// Then we use the standard HeliosPlus profile one.
2020-06-07 08:48:45 +00:00
shortcutIcon = shortcut . ProfileToUse . ProfileIcon . ToIcon ( ) ;
2020-06-01 10:25:52 +00:00
shortcutIcon . Save ( shortcut . SavedShortcutIconCacheFilename , MultiIconFormat . ICO ) ;
}
}
2020-07-23 06:31:00 +00:00
// ReSharper disable once CyclomaticComplexity
public static void RunShortcut ( ShortcutItem shortcutToUse )
{
// Do some validation to make sure the shortcut is sensible
// And that we have enough to try and action within the shortcut
2020-07-23 23:06:33 +00:00
// including checking the Profile in the shortcut is possible
2020-07-23 06:31:00 +00:00
// (in other words check everything in the shortcut is still valid)
2020-07-23 23:06:33 +00:00
if ( ! ( shortcutToUse is ShortcutItem ) )
return ;
2020-07-23 06:31:00 +00:00
( bool valid , string reason ) = shortcutToUse . IsValid ( ) ;
if ( ! valid )
{
2020-07-23 23:06:33 +00:00
throw new Exception ( string . Format ( "ShortcutRepository/SaveShortcutIconToCache exception: Unable to run the shortcut '{0}': {1}" , shortcutToUse . Name , reason ) ) ;
2020-07-23 06:31:00 +00:00
}
// Remember the profile we are on now
ProfileItem rollbackProfile = ProfileRepository . CurrentProfile ;
2020-07-23 23:06:33 +00:00
// Apply the Profile!
if ( ! ApplyProfile ( shortcutToUse . ProfileToUse ) )
2020-07-23 06:31:00 +00:00
{
throw new Exception ( Language . Cannot_change_active_profile ) ;
}
// Now run the pre-start applications
// TODO: Add the prestart applications
// Now start the main game, and wait if we have to
if ( shortcutToUse . Category . Equals ( ShortcutCategory . Application ) )
{
// Start the executable
Process process = null ;
if ( shortcutToUse . ExecutableArgumentsRequired )
process = System . Diagnostics . Process . Start ( shortcutToUse . ExecutableNameAndPath , shortcutToUse . ExecutableArguments ) ;
else
process = System . Diagnostics . Process . Start ( shortcutToUse . ExecutableNameAndPath ) ;
// Create a list of processes to monitor
Process [ ] processesToMonitor = Array . Empty < Process > ( ) ;
// Work out if we are monitoring another process other than the main executable
if ( shortcutToUse . ProcessNameToMonitorUsesExecutable )
{
// If we are monitoring the same executable we started, then lets do that
processesToMonitor = new [ ] { process } ;
}
else
{
// Now wait a little while for all the processes we want to monitor to start up
var ticks = 0 ;
while ( ticks < shortcutToUse . ExecutableTimeout * 1000 )
{
// Look for the processes with the ProcessName we want (which in Windows is the filename without the extension)
processesToMonitor = System . Diagnostics . Process . GetProcessesByName ( Path . GetFileNameWithoutExtension ( shortcutToUse . DifferentExecutableToMonitor ) ) ;
// TODO: Fix this logic error that will only ever wait for the first process....
if ( processesToMonitor . Length > 0 )
{
break ;
}
Thread . Sleep ( 300 ) ;
ticks + = 300 ;
}
// If none started up before the timeout, then ignore the
if ( processesToMonitor . Length = = 0 )
{
processesToMonitor = new [ ] { process } ;
}
}
// Store the process to monitor for later
IPCService . GetInstance ( ) . HoldProcessId = processesToMonitor . FirstOrDefault ( ) ? . Id ? ? 0 ;
IPCService . GetInstance ( ) . Status = InstanceStatus . OnHold ;
// Add a status notification icon in the status area
NotifyIcon notify = null ;
try
{
notify = new NotifyIcon
{
Icon = Properties . Resources . HeliosPlus ,
Text = string . Format (
Language . Waiting_for_the_0_to_terminate ,
processesToMonitor [ 0 ] . ProcessName ) ,
Visible = true
} ;
Application . DoEvents ( ) ;
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutItem/Run exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-23 06:31:00 +00:00
// ignored
}
// Wait for the monitored process to exit
foreach ( var p in processesToMonitor )
{
try
{
p . WaitForExit ( ) ;
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutItem/Run exception 2: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-23 06:31:00 +00:00
// ignored
}
}
// Remove the status notification icon from the status area
// once we've existed the game
if ( notify ! = null )
{
notify . Visible = false ;
notify . Dispose ( ) ;
Application . DoEvents ( ) ;
}
}
else if ( shortcutToUse . Category . Equals ( ShortcutCategory . Game ) )
{
// If the game is a Steam Game we check for that
if ( shortcutToUse . GameLibrary . Equals ( SupportedGameLibrary . Steam ) )
{
// We now need to get the SteamGame info
SteamGame steamGameToRun = SteamLibrary . GetSteamGame ( shortcutToUse . GameAppId ) ;
// If the GameAppID matches a Steam game, then lets run it
if ( steamGameToRun is SteamGame )
{
// Prepare to start the steam game using the URI interface
// as used by Steam for it's own desktop shortcuts.
var address = $"steam://rungameid/{steamGameToRun.GameId}" ;
if ( shortcutToUse . GameArgumentsRequired )
{
address + = "/" + shortcutToUse . GameArguments ;
}
// Start the URI Handler to run Steam
var steamProcess = System . Diagnostics . Process . Start ( address ) ;
// Wait for Steam game to update if needed
var ticks = 0 ;
while ( ticks < shortcutToUse . GameTimeout * 1000 )
{
if ( steamGameToRun . IsRunning )
{
break ;
}
Thread . Sleep ( 300 ) ;
if ( ! steamGameToRun . IsUpdating )
{
ticks + = 300 ;
}
}
// Store the Steam Process ID for later
IPCService . GetInstance ( ) . HoldProcessId = steamProcess ? . Id ? ? 0 ;
IPCService . GetInstance ( ) . Status = InstanceStatus . OnHold ;
// Add a status notification icon in the status area
NotifyIcon notify = null ;
try
{
notify = new NotifyIcon
{
Icon = Properties . Resources . HeliosPlus ,
Text = string . Format (
Language . Waiting_for_the_0_to_terminate ,
steamGameToRun . GameName ) ,
Visible = true
} ;
Application . DoEvents ( ) ;
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"Program/SwitchToSteamGame exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-23 06:31:00 +00:00
// ignored
}
// Wait for the game to exit
if ( steamGameToRun . IsRunning )
{
while ( true )
{
if ( ! steamGameToRun . IsRunning )
{
break ;
}
Thread . Sleep ( 300 ) ;
}
}
// Remove the status notification icon from the status area
// once we've existed the game
if ( notify ! = null )
{
notify . Visible = false ;
notify . Dispose ( ) ;
Application . DoEvents ( ) ;
}
}
}
// If the game is a Uplay Game we check for that
/ * else if ( GameLibrary . Equals ( SupportedGameLibrary . Uplay ) )
{
// We need to look up details about the game
if ( ! UplayGame . IsInstalled ( GameAppId ) )
{
return ( false , string . Format ( "The Uplay Game with AppID '{0}' is not installed on this computer." , GameAppId ) ) ;
}
} * /
}
// Change back to the original profile if it is different
if ( ! ProfileRepository . IsActiveProfile ( rollbackProfile ) )
{
2020-07-23 23:06:33 +00:00
if ( ! ApplyProfile ( rollbackProfile ) )
2020-07-23 06:31:00 +00:00
{
throw new Exception ( Language . Cannot_change_active_profile ) ;
}
}
}
2020-07-24 01:11:42 +00:00
public static bool ApplyProfile ( ProfileItem profile )
2020-07-23 06:31:00 +00:00
{
// If we're already on the wanted profile then no need to change!
if ( ProfileRepository . IsActiveProfile ( profile ) )
return true ;
2020-07-26 08:52:46 +00:00
// We need to check if the profile is valid
if ( ! profile . IsPossible )
return false ;
2020-07-23 06:31:00 +00:00
var instanceStatus = IPCService . GetInstance ( ) . Status ;
try
{
IPCService . GetInstance ( ) . Status = InstanceStatus . Busy ;
var failed = false ;
2020-07-23 23:06:33 +00:00
// Now lets start by changing the display topology
Task applyProfileTopologyTask = Task . Run ( ( ) = >
2020-07-23 06:31:00 +00:00
{
2020-07-23 23:06:33 +00:00
Console . WriteLine ( "ShortcutRepository/SaveShortcutIconToCache : Applying Profile Topology" + profile . Name ) ;
ApplyTopology ( profile ) ;
} ) ;
applyProfileTopologyTask . Wait ( ) ;
2020-07-23 06:31:00 +00:00
2020-07-23 23:06:33 +00:00
// And then change the path information
Task applyProfilePathInfoTask = Task . Run ( ( ) = >
{
Console . WriteLine ( "ShortcutRepository/SaveShortcutIconToCache : Applying Profile Topology" + profile . Name ) ;
ApplyPathInfo ( profile ) ;
} ) ;
applyProfilePathInfoTask . Wait ( ) ;
2020-07-23 06:31:00 +00:00
return false ;
}
finally
{
IPCService . GetInstance ( ) . Status = instanceStatus ;
}
}
2020-07-23 23:06:33 +00:00
2020-07-24 01:11:42 +00:00
private static void ApplyTopology ( ProfileItem profile )
2020-07-23 23:06:33 +00:00
{
Debug . Print ( "ShortcutRepository.ApplyTopology()" ) ;
if ( profile = = null )
return ;
try
{
var surroundTopologies =
profile . Viewports . SelectMany ( viewport = > viewport . TargetDisplays )
. Select ( target = > target . SurroundTopology )
. Where ( topology = > topology ! = null )
. Select ( topology = > topology . ToGridTopology ( ) )
. ToArray ( ) ;
if ( surroundTopologies . Length = = 0 )
{
var currentTopologies = GridTopology . GetGridTopologies ( ) ;
if ( currentTopologies . Any ( topology = > topology . Rows * topology . Columns > 1 ) )
{
surroundTopologies =
GridTopology . GetGridTopologies ( )
. SelectMany ( topology = > topology . Displays )
. Select ( displays = > new GridTopology ( 1 , 1 , new [ ] { displays } ) )
. ToArray ( ) ;
}
}
if ( surroundTopologies . Length > 0 )
{
GridTopology . SetGridTopologies ( surroundTopologies , SetDisplayTopologyFlag . MaximizePerformance ) ;
}
}
catch ( Exception ex )
{
2020-07-24 04:51:48 +00:00
Console . WriteLine ( $"ShortcutRepository/ApplyTopology exception: {ex.Message}: {ex.StackTrace} - {ex.InnerException}" ) ;
2020-07-23 23:06:33 +00:00
// ignored
}
}
2020-07-24 01:11:42 +00:00
private static void ApplyPathInfo ( ProfileItem profile )
2020-07-23 23:06:33 +00:00
{
Debug . Print ( "ShortcutRepository.ApplyPathInfo()" ) ;
if ( profile = = null )
return ;
if ( ! profile . IsPossible )
{
throw new InvalidOperationException (
$"ShortcutRepository/ApplyPathInfo exception: Problem applying the '{profile.Name}' Display Profile! The display configuration changed since this profile is created. Please re-create this profile." ) ;
}
var pathInfos = profile . Viewports . Select ( viewport = > viewport . ToPathInfo ( ) ) . Where ( info = > info ! = null ) . ToArray ( ) ;
WindowsDisplayAPI . DisplayConfig . PathInfo . ApplyPathInfos ( pathInfos , true , true , true ) ;
}
2020-06-01 10:25:52 +00:00
#endregion
}
[global::System.Serializable]
public class ShortcutRepositoryException : Exception
{
public ShortcutRepositoryException ( ) { }
public ShortcutRepositoryException ( string message ) : base ( message ) { }
public ShortcutRepositoryException ( string message , Exception inner ) : base ( message , inner ) { }
protected ShortcutRepositoryException (
System . Runtime . Serialization . SerializationInfo info ,
System . Runtime . Serialization . StreamingContext context ) : base ( info , context ) { }
}
}