DisplayMagician/DisplayMagician/ShortcutItem.cs
Terry MacDonald 28ec42b92d [WIP] Working process priority UI
And also saving and loading. Now only implementation
to go.
2021-07-25 16:41:26 +12:00

1622 lines
62 KiB
C#

using DisplayMagician.GameLibraries;
using DisplayMagician.Resources;
using DisplayMagicianShared;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.IconLib;
using System.Drawing.Imaging;
using System.Globalization;
using System.IO;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using IWshRuntimeLibrary;
using AudioSwitcher.AudioApi.CoreAudio;
using AudioSwitcher.AudioApi;
using TsudaKageyu;
namespace DisplayMagician
{
public enum ShortcutPermanence : int
{
Permanent = 0,
Temporary = 1,
}
public enum ShortcutCategory : int
{
Application = 0,
Game = 1,
NoGame = 2,
}
public enum ShortcutValidity : int
{
Valid = 0,
Warning = 1,
Error = 2,
}
public enum ProcessPriority : int
{
High = 2,
AboveNormal = 1,
Normal = 0,
BelowNormal =-1,
Idle = -24,
}
public struct StartProgram
{
public int Priority;
public bool Disabled;
public ProcessPriority ProcessPriority;
public string Executable;
public string Arguments;
public bool ExecutableArgumentsRequired;
public bool CloseOnFinish;
public bool DontStartIfAlreadyRunning;
}
public struct Executable
{
public string DifferentExecutableToMonitor;
public string ExecutableNameAndPath;
public int ExecutableTimeout;
public string ExecutableArguments;
public bool ExecutableArgumentsRequired;
public bool ProcessNameToMonitorUsesExecutable;
public ProcessPriority ProcessPriority;
}
public struct GameStruct
{
public Game GameToPlay;
public int StartTimeout;
public string GameArguments;
public bool GameArgumentsRequired;
public string DifferentGameExeToMonitor;
public bool MonitorDifferentGameExe;
public ProcessPriority ProcessPriority;
}
public struct ShortcutError
{
public string Name;
public ShortcutValidity Validity;
public string Message;
}
public class ShortcutItem : IComparable
{
private string _profileUuid = "";
private ProfileItem _profileToUse;
private string _uuid = "";
private string _name = "";
private ShortcutCategory _category = ShortcutCategory.Game;
private string _differentExecutableToMonitor;
private string _executableNameAndPath = "";
private string _executableArguments;
private bool _executableArgumentsRequired = false;
private bool _processNameToMonitorUsesExecutable = true;
private ProcessPriority _processPriority = ProcessPriority.Normal;
private string _gameAppId;
private string _gameName;
private SupportedGameLibraryType _gameLibrary = SupportedGameLibraryType.Unknown;
private int _startTimeout = 20;
private string _gameArguments;
private bool _gameArgumentsRequired;
private string _differentGameExeToMonitor;
private bool _monitorDifferentGameExe = false;
private string _audioDevice;
private bool _changeAudioDevice;
private bool _setAudioVolume = false;
private decimal _audioVolume = -1;
private string _captureDevice;
private bool _changeCaptureDevice;
private bool _setCaptureVolume = false;
private decimal _captureVolume = -1;
private ShortcutPermanence _displayPermanence = ShortcutPermanence.Temporary;
private ShortcutPermanence _audioPermanence = ShortcutPermanence.Temporary;
private ShortcutPermanence _capturePermanence = ShortcutPermanence.Temporary;
private Keys _hotkey = Keys.None;
private bool _autoName = true;
private ShortcutValidity _isValid;
private List<ShortcutError> _shortcutErrors = new List<ShortcutError>();
private List<StartProgram> _startPrograms;
private Bitmap _shortcutBitmap, _originalBitmap;
[JsonIgnore]
#pragma warning disable CS3008 // Identifier is not CLS-compliant
public string _originalIconPath;
[JsonIgnore]
public string _savedShortcutIconCacheFilename;
#pragma warning restore CS3008 // Identifier is not CLS-compliant
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
public ShortcutItem()
{
// Create a new UUID for the shortcut if one wasn't created already
if (String.IsNullOrWhiteSpace(_uuid))
_uuid = Guid.NewGuid().ToString("D");
// If there are no GameLibraries then choose executable instead
if (!(UplayLibrary.GetLibrary().IsGameLibraryInstalled &&
SteamLibrary.GetLibrary().IsGameLibraryInstalled &&
OriginLibrary.GetLibrary().IsGameLibraryInstalled))
{
_gameLibrary = SupportedGameLibraryType.Unknown;
_gameName = "";
_gameArguments = "";
_category = ShortcutCategory.Application;
}
// Autocreate a name for the shortcut if AutoName is on
// (and if we have a profile to use)
if (AutoName && _profileToUse is ProfileItem)
{
// If Autoname is on, and then lets autoname it!
// That populates all the right things
AutoSuggestShortcutName();
}
//RefreshValidity();
}
public static Version Version
{
get => new Version(1, 0);
}
public string UUID
{
get
{
return _uuid;
}
set
{
string uuidV4Regex = @"[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}";
Match match = Regex.Match(value, uuidV4Regex, RegexOptions.IgnoreCase);
if (match.Success)
_uuid = value;
}
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public bool AutoName
{
get
{
return _autoName;
}
set
{
_autoName = value;
}
}
[JsonIgnore]
#pragma warning disable CS3003 // Type is not CLS-compliant
public ProfileItem ProfileToUse {
#pragma warning restore CS3003 // Type is not CLS-compliant
get
{
return _profileToUse;
}
set
{
if (value is ProfileItem)
{
_profileToUse = value;
_profileUuid = _profileToUse.UUID;
// We should try to set the Profile
// And we rename the shortcut if the AutoName is on
if (AutoName)
AutoSuggestShortcutName();
}
}
}
public string ProfileUUID {
get
{
return _profileUuid;
}
set
{
_profileUuid = value;
// We try to find and set the ProfileTouse
foreach (ProfileItem profileToTest in ProfileRepository.AllProfiles)
{
if (profileToTest.UUID.Equals(_profileUuid, StringComparison.OrdinalIgnoreCase))
_profileToUse = profileToTest;
}
}
}
public ShortcutPermanence DisplayPermanence
{
get
{
return _displayPermanence;
}
set
{
_displayPermanence = value;
}
}
public ShortcutPermanence AudioPermanence
{
get
{
return _audioPermanence;
}
set
{
_audioPermanence = value;
}
}
public ShortcutPermanence CapturePermanence
{
get
{
return _capturePermanence;
}
set
{
_capturePermanence = value;
}
}
public ShortcutCategory Category
{
get
{
return _category;
}
set
{
_category = value;
}
}
public ProcessPriority ProcessPriority
{
get
{
return _processPriority;
}
set
{
_processPriority = value;
}
}
public string DifferentExecutableToMonitor
{
get
{
return _differentExecutableToMonitor;
}
set
{
_differentExecutableToMonitor = value;
}
}
public string ExecutableNameAndPath
{
get
{
return _executableNameAndPath;
}
set
{
_executableNameAndPath = value;
// If the executableNameandPath is set then we also want to update the originalIconPath
// so it's the path to the application. This will kick of the icon grabbing processes
if (Category.Equals(ShortcutCategory.Application))
_originalIconPath = value;
}
}
public string ExecutableArguments
{
get
{
return _executableArguments;
}
set
{
_executableArguments = value;
}
}
public bool ExecutableArgumentsRequired
{
get
{
return _executableArgumentsRequired;
}
set
{
_executableArgumentsRequired = value;
}
}
public bool ProcessNameToMonitorUsesExecutable
{
get
{
return _processNameToMonitorUsesExecutable;
}
set
{
_processNameToMonitorUsesExecutable = value;
}
}
public string GameAppId
{
get
{
return _gameAppId;
}
set
{
_gameAppId = value;
}
}
public string GameName
{
get
{
return _gameName;
}
set
{
_gameName = value;
}
}
public SupportedGameLibraryType GameLibrary
{
get
{
return _gameLibrary;
}
set
{
_gameLibrary = value;
}
}
#pragma warning disable CS3003 // Type is not CLS-compliant
public Keys Hotkey
#pragma warning restore CS3003 // Type is not CLS-compliant
{
get
{
return _hotkey;
}
set
{
_hotkey = value;
}
}
public int StartTimeout
{
get
{
return _startTimeout;
}
set
{
_startTimeout = value;
}
}
public string GameArguments
{
get
{
return _gameArguments;
}
set
{
_gameArguments = value;
}
}
public bool GameArgumentsRequired
{
get
{
return _gameArgumentsRequired;
}
set
{
_gameArgumentsRequired = value;
}
}
public string DifferentGameExeToMonitor
{
get
{
return _differentGameExeToMonitor;
}
set
{
_differentGameExeToMonitor = value;
}
}
public bool MonitorDifferentGameExe
{
get
{
return _monitorDifferentGameExe;
}
set
{
_monitorDifferentGameExe = value;
}
}
public string AudioDevice
{
get
{
return _audioDevice;
}
set
{
_audioDevice = value;
}
}
public bool ChangeAudioDevice
{
get
{
return _changeAudioDevice;
}
set
{
_changeAudioDevice = value;
}
}
public decimal AudioVolume
{
get
{
return _audioVolume;
}
set
{
_audioVolume = value;
}
}
public bool SetAudioVolume
{
get
{
return _setAudioVolume;
}
set
{
_setAudioVolume = value;
}
}
public string CaptureDevice
{
get
{
return _captureDevice;
}
set
{
_captureDevice = value;
}
}
public bool ChangeCaptureDevice
{
get
{
return _changeCaptureDevice;
}
set
{
_changeCaptureDevice = value;
}
}
public decimal CaptureVolume
{
get
{
return _captureVolume;
}
set
{
_captureVolume = value;
}
}
public bool SetCaptureVolume
{
get
{
return _setCaptureVolume;
}
set
{
_setCaptureVolume = value;
}
}
public List<StartProgram> StartPrograms
{
get
{
return _startPrograms;
}
set
{
_startPrograms = value;
}
}
public string OriginalIconPath {
get
{
return _originalIconPath;
}
set
{
_originalIconPath = value;
// And we do the same for the OriginalBitmap
//_originalLargeBitmap = ToLargeBitmap(_originalIconPath);
}
}
[JsonConverter(typeof(CustomBitmapConverter))]
public Bitmap OriginalLargeBitmap
{
get
{
return _originalBitmap;
}
set
{
_originalBitmap = value;
// And we do the same for the Bitmap overlay, but only if the ProfileToUse is set
//if (_profileToUse is ProfileItem)
// _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256);
}
}
[JsonConverter(typeof(CustomBitmapConverter))]
public Bitmap ShortcutBitmap
{
get
{
return _shortcutBitmap;
}
set
{
_shortcutBitmap = value;
}
}
public string SavedShortcutIconCacheFilename
{
get
{
return _savedShortcutIconCacheFilename;
}
set
{
_savedShortcutIconCacheFilename = value;
}
}
[JsonIgnore]
public ShortcutValidity IsValid
{
get
{
return _isValid;
}
set
{
_isValid = value;
}
}
[JsonIgnore]
public List<ShortcutError> Errors
{
get
{
return _shortcutErrors;
}
set
{
_shortcutErrors = value;
}
}
public void UpdateNoGameShortcut(
string name,
#pragma warning disable CS3001 // Argument type is not CLS-compliant
ProfileItem profile,
#pragma warning restore CS3001 // Argument type is not CLS-compliant
ShortcutPermanence displayPermanence,
ShortcutPermanence audioPermanence,
ShortcutPermanence capturePermanence,
string originalIconPath,
bool changeAudioDevice = false,
string audioDevice = "",
bool setAudioVolume = false,
decimal audioVolume = -1,
bool changeCaptureDevice = false,
string captureDevice = "",
bool setCaptureVolume = false,
decimal captureVolume = -1,
List<StartProgram> startPrograms = null,
bool autoName = true,
Keys hotkey = Keys.None,
string uuid = ""
)
{
if (!String.IsNullOrWhiteSpace(uuid))
_uuid = uuid;
_name = name;
_category = ShortcutCategory.NoGame;
_profileToUse = profile;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
_audioVolume = audioVolume;
_changeCaptureDevice = changeCaptureDevice;
_captureDevice = captureDevice;
_setCaptureVolume = setCaptureVolume;
_captureVolume = captureVolume;
_displayPermanence = displayPermanence;
_audioPermanence = audioPermanence;
_capturePermanence = capturePermanence;
_autoName = autoName;
_startPrograms = startPrograms;
_originalIconPath = originalIconPath;
_hotkey = hotkey;
// Now we need to find and populate the profileUuid
_profileUuid = profile.UUID;
_originalBitmap = profile.ProfileBitmap;
_shortcutBitmap = profile.ProfileBitmap;
ReplaceShortcutIconInCache();
RefreshValidity();
}
public void UpdateGameShortcut(
string name,
#pragma warning disable CS3001 // Argument type is not CLS-compliant
ProfileItem profile,
#pragma warning restore CS3001 // Argument type is not CLS-compliant
GameStruct game,
ShortcutPermanence displayPermanence,
ShortcutPermanence audioPermanence,
ShortcutPermanence capturePermanence,
string originalIconPath,
bool changeAudioDevice = false,
string audioDevice = "",
bool setAudioVolume = false,
decimal audioVolume = -1,
bool changeCaptureDevice = false,
string captureDevice = "",
bool setCaptureVolume = false,
decimal captureVolume = -1,
List<StartProgram> startPrograms = null,
bool autoName = true,
string uuid = "",
Keys hotkey = Keys.None
)
{
// Create a new UUID for the shortcut if one wasn't created already
if (!String.IsNullOrWhiteSpace(uuid))
_uuid = uuid;
_name = name;
_profileToUse = profile;
_category = ShortcutCategory.Game;
_gameAppId = game.GameToPlay.Id;
_gameName = game.GameToPlay.Name;
_gameLibrary = game.GameToPlay.GameLibrary;
_startTimeout = game.StartTimeout;
_gameArguments = game.GameArguments;
_gameArgumentsRequired = game.GameArgumentsRequired;
_differentGameExeToMonitor = game.DifferentGameExeToMonitor;
_monitorDifferentGameExe = game.MonitorDifferentGameExe;
_processPriority = game.ProcessPriority;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
_audioVolume = audioVolume;
_changeCaptureDevice = changeCaptureDevice;
_captureDevice = captureDevice;
_setCaptureVolume = setCaptureVolume;
_captureVolume = captureVolume;
_displayPermanence = displayPermanence;
_audioPermanence = audioPermanence;
_capturePermanence = capturePermanence;
_autoName = autoName;
_startPrograms = startPrograms;
_originalIconPath = originalIconPath;
_hotkey = hotkey;
// Now we need to find and populate the profileUuid
_profileUuid = profile.UUID;
// We create the OriginalBitmap
// Find the game bitmap that matches the game name we just got
foreach (var aGame in DisplayMagician.GameLibraries.GameLibrary.AllInstalledGamesInAllLibraries)
{
if (aGame.Name.Equals(_gameName))
{
_originalBitmap = aGame.GameBitmap;
}
}
// We create the ShortcutBitmap from the OriginalBitmap
// (We only do it if there is a valid profile)
if (_profileToUse is ProfileItem)
_shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256);
ReplaceShortcutIconInCache();
RefreshValidity();
}
public void UpdateExecutableShortcut(
string name,
#pragma warning disable CS3001 // Argument type is not CLS-compliant
ProfileItem profile,
#pragma warning restore CS3001 // Argument type is not CLS-compliant
Executable executable,
ShortcutPermanence displayPermanence,
ShortcutPermanence audioPermanence,
ShortcutPermanence capturePermanence,
string originalIconPath,
bool changeAudioDevice = false,
string audioDevice = "",
bool setAudioVolume = false,
decimal audioVolume = -1,
bool changeCaptureDevice = false,
string captureDevice = "",
bool setCaptureVolume = false,
decimal captureVolume = -1,
List<StartProgram> startPrograms = null,
bool autoName = true,
Keys hotkey = Keys.None,
string uuid = ""
)
{
if (!String.IsNullOrWhiteSpace(uuid))
_uuid = uuid;
_name = name;
_profileToUse = profile;
_category = ShortcutCategory.Application;
_differentExecutableToMonitor = executable.DifferentExecutableToMonitor;
_executableNameAndPath = executable.ExecutableNameAndPath;
_startTimeout = executable.ExecutableTimeout;
_executableArguments = executable.ExecutableArguments;
_executableArgumentsRequired = executable.ExecutableArgumentsRequired;
_processNameToMonitorUsesExecutable = executable.ProcessNameToMonitorUsesExecutable;
_processPriority = executable.ProcessPriority;
_changeAudioDevice = changeAudioDevice;
_audioDevice = audioDevice;
_setAudioVolume = setAudioVolume;
_audioVolume = audioVolume;
_changeCaptureDevice = changeCaptureDevice;
_captureDevice = captureDevice;
_setCaptureVolume = setCaptureVolume;
_captureVolume = captureVolume;
_displayPermanence = displayPermanence;
_audioPermanence = audioPermanence;
_capturePermanence = capturePermanence;
_autoName = autoName;
_startPrograms = startPrograms;
_originalIconPath = originalIconPath;
_hotkey = hotkey;
// Now we need to find and populate the profileUuid
_profileUuid = profile.UUID;
// We create the OriginalBitmap from the IconPath
//_originalLargeBitmap = ToLargeBitmap(_originalIconPath);
// We create the OriginalBitmap
_originalBitmap = ImageUtils.GetMeABitmapFromFile(_originalIconPath);
// We create the ShortcutBitmap from the OriginalBitmap
// (We only do it if there is a valid profile)
//if (_profileToUse is ProfileItem)
// _shortcutBitmap = ToBitmapOverlay(_originalLargeBitmap, _profileToUse.ProfileTightestBitmap, 256, 256);
_shortcutBitmap = ToBitmapOverlay(_originalBitmap, _profileToUse.ProfileTightestBitmap, 256, 256);
ReplaceShortcutIconInCache();
RefreshValidity();
}
public bool CopyTo (ShortcutItem shortcut, bool overwriteUUID = true)
{
if (!(shortcut is ShortcutItem))
return false;
if (overwriteUUID)
shortcut.UUID = UUID;
// Copy all the shortcut data over to the other Shortcut
shortcut.Name = Name;
shortcut.ProfileToUse = ProfileToUse;
shortcut.ProfileUUID = ProfileUUID;
shortcut.DisplayPermanence = DisplayPermanence;
shortcut.AudioPermanence = AudioPermanence;
shortcut.CapturePermanence = CapturePermanence;
shortcut.Category = Category;
shortcut.DifferentExecutableToMonitor = DifferentExecutableToMonitor;
shortcut.ExecutableNameAndPath = ExecutableNameAndPath;
shortcut.ExecutableArguments = ExecutableArguments;
shortcut.ExecutableArgumentsRequired = ExecutableArgumentsRequired;
shortcut.ProcessNameToMonitorUsesExecutable = ProcessNameToMonitorUsesExecutable;
shortcut.ProcessPriority = ProcessPriority;
shortcut.GameAppId = GameAppId;
shortcut.GameName = GameName;
shortcut.GameLibrary = GameLibrary;
shortcut.StartTimeout = StartTimeout;
shortcut.GameArguments = GameArguments;
shortcut.GameArgumentsRequired = GameArgumentsRequired;
shortcut.OriginalIconPath = OriginalIconPath;
shortcut.OriginalLargeBitmap = OriginalLargeBitmap;
shortcut.ShortcutBitmap = ShortcutBitmap;
shortcut.SavedShortcutIconCacheFilename = SavedShortcutIconCacheFilename;
shortcut.IsValid = IsValid;
shortcut.Errors.AddRange(Errors);
shortcut.StartPrograms = StartPrograms;
shortcut.ChangeAudioDevice = ChangeAudioDevice;
shortcut.AudioDevice = AudioDevice;
shortcut.SetAudioVolume = SetAudioVolume;
shortcut.AudioVolume = AudioVolume;
shortcut.ChangeCaptureDevice = ChangeCaptureDevice;
shortcut.CaptureDevice = CaptureDevice;
shortcut.SetCaptureVolume = SetCaptureVolume;
shortcut.CaptureVolume = CaptureVolume;
shortcut.Hotkey = Hotkey;
// Save the shortcut incon to the icon cache
shortcut.ReplaceShortcutIconInCache();
shortcut.RefreshValidity();
return true;
}
public void ReplaceShortcutIconInCache()
{
string newShortcutIconFilename;
// Work out the name of the shortcut we'll save.
newShortcutIconFilename = Path.Combine(Program.AppShortcutPath, $"{UUID}.ico");
logger.Trace($"ShortcutItem/ReplaceShortcutIconInCache: New shortcut Icon filename is {newShortcutIconFilename}.");
// If the new shortcut icon should be named differently
// then change the name of it
if (!newShortcutIconFilename.Equals(_savedShortcutIconCacheFilename))
{
logger.Trace($"ShortcutItem/ReplaceShortcutIconInCache: New shortcut Icon filename {newShortcutIconFilename} is different to the old shortcut Icon filename {_savedShortcutIconCacheFilename}.");
if (System.IO.File.Exists(_savedShortcutIconCacheFilename))
{
logger.Trace($"ShortcutItem/ReplaceShortcutIconInCache: Deleting old shortcut Icon filename {_savedShortcutIconCacheFilename}.");
System.IO.File.Delete(_savedShortcutIconCacheFilename);
}
logger.Trace($"ShortcutItem/ReplaceShortcutIconInCache: Creating the new shortcut Icon filename {newShortcutIconFilename} (calling SaveShortcutIconToCache).");
SaveShortcutIconToCache();
}
else
{
logger.Trace($"ShortcutItem/ReplaceShortcutIconInCache: New shortcut Icon filename {newShortcutIconFilename} matches old shortcut Icon filename {_savedShortcutIconCacheFilename} so skipping the rename.");
}
}
public void SaveShortcutIconToCache()
{
// Work out the name of the shortcut we'll save.
_savedShortcutIconCacheFilename = Path.Combine(Program.AppShortcutPath, $"{UUID}.ico");
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Planning on saving shortcut icon to cache as {_savedShortcutIconCacheFilename}.");
MultiIcon shortcutIcon;
try
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Creating IconOverlay.");
shortcutIcon = ToIconOverlay();
if (shortcutIcon != null)
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Saving shortcut icon to cache with {_savedShortcutIconCacheFilename} as the name.");
shortcutIcon.Save(_savedShortcutIconCacheFilename, MultiIconFormat.ICO);
}
else
{
// If we fail to create an icon based on the original executable or game
// Then we use the one appropriate for the game library
SingleIcon si = shortcutIcon.Add("icon");
Bitmap bm = null;
if (_gameLibrary == SupportedGameLibraryType.Steam)
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Using the Steam icon as the icon instead.");
bm = ToBitmapOverlay(Properties.Resources.Steam, _profileToUse.ProfileIcon.ToBitmap(),256,256);
}
else if (_gameLibrary == SupportedGameLibraryType.Uplay)
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Using the Uplay icon as the icon instead.");
bm = ToBitmapOverlay(Properties.Resources.Uplay, _profileToUse.ProfileIcon.ToBitmap(), 256, 256);
}
else if (_gameLibrary == SupportedGameLibraryType.Origin)
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Using the Origin icon as the icon instead.");
bm = ToBitmapOverlay(Properties.Resources.Origin, _profileToUse.ProfileIcon.ToBitmap(), 256, 256);
}
else if (_gameLibrary == SupportedGameLibraryType.Epic)
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Using the Epic icon as the icon instead.");
bm = ToBitmapOverlay(Properties.Resources.Epic, _profileToUse.ProfileIcon.ToBitmap(), 256, 256);
}
else if (_gameLibrary == SupportedGameLibraryType.GOG)
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Using the GOG icon as the icon instead.");
bm = ToBitmapOverlay(Properties.Resources.GOG, _profileToUse.ProfileIcon.ToBitmap(), 256, 256);
}
else
{
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Unknown Game Library, so using the DisplayMagician icon as the icon instead.");
bm = ToBitmapOverlay(Properties.Resources.DisplayMagician.ToBitmap(), _profileToUse.ProfileIcon.ToBitmap(), 256, 256);
}
si.Add(bm);
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Saving the replacement icon for Shortcut '{Name}' to {_savedShortcutIconCacheFilename}.");
shortcutIcon.Save(_savedShortcutIconCacheFilename, MultiIconFormat.ICO);
}
}
catch (Exception ex)
{
logger.Warn(ex, $"ShortcutItem/SaveShortcutIconToCache: Exception while trying to save the Shortcut icon.");
// If we fail to create an icon any other way, then we use the default profile icon
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Using the Display Profile icon for {_profileToUse.Name} as the icon instead.");
shortcutIcon = _profileToUse.ProfileIcon.ToIcon();
logger.Trace($"ShortcutItem/SaveShortcutIconToCache: Saving the Display Profile icon for {_profileToUse.Name} to {_savedShortcutIconCacheFilename}.");
shortcutIcon.Save(_savedShortcutIconCacheFilename, MultiIconFormat.ICO);
}
}
public Bitmap ToBitmapOverlay(Bitmap originalBitmap, Bitmap overlayBitmap, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb)
{
if (originalBitmap == null)
{
if (_category == ShortcutCategory.Application)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the executable icon as the icon instead.");
originalBitmap = ImageUtils.GetMeABitmapFromFile(_executableNameAndPath);
}
else if (_category == ShortcutCategory.Game)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: OriginalBitmap is null, so we'll try to make the BitmapOverlay using GameLibrary Icon.");
if (_gameLibrary == SupportedGameLibraryType.Steam)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the Steam icon as the icon instead.");
originalBitmap = Properties.Resources.Steam;
}
else if (_gameLibrary == SupportedGameLibraryType.Uplay)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the Uplay icon as the icon instead.");
originalBitmap = Properties.Resources.Uplay;
}
else if (_gameLibrary == SupportedGameLibraryType.Origin)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the Origin icon as the icon instead.");
originalBitmap = Properties.Resources.Origin;
}
else if (_gameLibrary == SupportedGameLibraryType.Epic)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the Epic icon as the icon instead.");
originalBitmap = Properties.Resources.Epic;
}
else if (_gameLibrary == SupportedGameLibraryType.GOG)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the GOG icon as the icon instead.");
originalBitmap = Properties.Resources.GOG;
}
else
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Unknown Game Library, so using the DisplayMagician icon as the icon instead.");
originalBitmap = Properties.Resources.DisplayMagician.ToBitmap();
}
}
else
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Using the profile icon as the icon instead.");
originalBitmap = _profileToUse.ProfileBitmap;
}
}
if (overlayBitmap == null)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: overlayBitmap is null, so we'll just return the original bitmap without a profile overlay.");
return originalBitmap;
}
if (width <= 0 || width > 256)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Width is out of range so setting to 256.");
width = 256;
}
if (height <= 0 || height > 256)
{
logger.Trace($"ShortcutItem/ToBitmapOverlay: Height is out of range so setting to 256.");
height = 256;
}
return ImageUtils.ToBitmapOverlay(originalBitmap, overlayBitmap, width, height, format);
}
#pragma warning disable CS3002 // Return type is not CLS-compliant
public MultiIcon ToIconOverlay()
#pragma warning restore CS3002 // Return type is not CLS-compliant
{
return ImageUtils.ToIconOverlay(_originalBitmap, ProfileToUse.ProfileTightestBitmap);
}
public void RefreshValidity()
{
// Do some validation checks to make sure the shortcut is sensible
// And that we have enough to try and action within the shortcut
// (in other words check everything in the shortcut is still valid)
Errors.Clear();
ShortcutValidity worstError = ShortcutValidity.Valid;
// Does the profile we want to Use still exist?
if (!ProfileRepository.ContainsProfile(ProfileUUID))
{
logger.Warn($"ShortcutItem/RefreshValidity: The profile UUID {ProfileUUID} isn't in the ProfileRepository");
ShortcutError error = new ShortcutError();
error.Name = "ProfileNotExist";
error.Validity = ShortcutValidity.Error;
error.Message = $"The profile does not exist (probably deleted) and cannot be used.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
// Is the profile still valid right now? i.e. are all the screens available?
if (ProfileToUse != null && !ProfileToUse.IsPossible)
{
logger.Warn($"ShortcutItem/RefreshValidity: The profile {ProfileToUse} isn't possible to use right now!");
ShortcutError error = new ShortcutError();
error.Name = "InvalidProfile";
error.Validity = ShortcutValidity.Warning;
error.Message = $"The profile '{ProfileToUse.Name}' is not valid right now and cannot be used.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Warning;
}
// Is the main application still installed?
if (Category.Equals(ShortcutCategory.Application))
{
// We need to check if the Application still exists
if (!System.IO.File.Exists(ExecutableNameAndPath))
{
logger.Warn($"ShortcutItem/RefreshValidity: The Application executable {ExecutableNameAndPath} DOES NOT exist");
ShortcutError error = new ShortcutError();
error.Name = "InvalidExecutableNameAndPath";
error.Validity = ShortcutValidity.Error;
error.Message = $"The application executable '{ExecutableNameAndPath}' does not exist, or cannot be accessed by DisplayMagician.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
else
{
logger.Trace($"ShortcutItem/RefreshValidity: The Application executable {ExecutableNameAndPath} exists");
}
}
else if (Category.Equals(ShortcutCategory.Game))
{
GameLibrary gameLibraryToUse = null;
// If the game is a Steam Game we check for that
if (GameLibrary.Equals(SupportedGameLibraryType.Steam))
{
logger.Trace($"ShortcutItem/RefreshValidity: The game library is Steam");
// We now need to get the SteamGame info
gameLibraryToUse = SteamLibrary.GetLibrary();
}
// If the game is a Uplay Uplay Game we check for that
else if (GameLibrary.Equals(SupportedGameLibraryType.Uplay))
{
logger.Trace($"ShortcutItem/RefreshValidity: The game library is Uplay");
// We now need to get the Uplay Game info
gameLibraryToUse = UplayLibrary.GetLibrary();
}
// If the game is an Origin Game we check for that
else if (GameLibrary.Equals(SupportedGameLibraryType.Origin))
{
logger.Trace($"ShortcutItem/RefreshValidity: The game library is Origin");
// We now need to get the Uplay Game info
gameLibraryToUse = OriginLibrary.GetLibrary();
}
// If the game is an Epic Game we check for that
else if (GameLibrary.Equals(SupportedGameLibraryType.Epic))
{
logger.Trace($"ShortcutItem/RefreshValidity: The game library is Epic");
// We now need to get the Epic Game info
gameLibraryToUse = EpicLibrary.GetLibrary();
}
// If the game is an GOG Game we check for that
else if (GameLibrary.Equals(SupportedGameLibraryType.GOG))
{
logger.Trace($"ShortcutItem/RefreshValidity: The game library is GOG");
// We now need to get the GOG Game info
gameLibraryToUse = GogLibrary.GetLibrary();
}
else
{
gameLibraryToUse = null;
logger.Warn($"ShortcutItem/RefreshValidity: The game shortcut uses an unsupported game library! (You've probably downgraded DisplayMagician to an earlier version)");
ShortcutError error = new ShortcutError();
error.Name = $"UnknownGameLibrary";
error.Validity = ShortcutValidity.Error;
error.Message = $"The game shortcut uses an unsupported game library.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
if (gameLibraryToUse != null)
{
// Check if Gamelibrary is installed and error if it isn't
if (!gameLibraryToUse.IsGameLibraryInstalled)
{
logger.Warn($"ShortcutItem/RefreshValidity: The game library is not installed!");
ShortcutError error = new ShortcutError();
error.Name = $"{gameLibraryToUse.GameLibraryName}NotInstalled";
error.Validity = ShortcutValidity.Error;
error.Message = $"{gameLibraryToUse.GameLibraryName} is not installed on this computer.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
// We need to look up details about the game
if (!gameLibraryToUse.ContainsGameById(GameAppId))
{
logger.Warn($"ShortcutItem/RefreshValidity: The game library does not have Game ID {GameAppId} installed!");
ShortcutError error = new ShortcutError();
error.Name = "{gameLibraryToUse.GameLibraryName}GameNotInstalled";
error.Validity = ShortcutValidity.Error;
error.Message = $"The {gameLibraryToUse.GameLibraryName} Game with AppID '{GameAppId}' is not installed on this computer.";
_shortcutErrors.Add(error);
if (worstError != ShortcutValidity.Error)
worstError = ShortcutValidity.Error;
}
}
}
// Check the Audio Device is still valid (if one is specified)
CoreAudioController audioController = ShortcutRepository.AudioController;
if (ChangeAudioDevice)
{
IEnumerable<CoreAudioDevice> audioDevices = null;
if (audioController != null)
{
try
{
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)
{
logger.Trace($"ShortcutItem/RefreshValidity: Detected audio playback device {audioDevice.FullName}");
if (audioDevice.FullName.Equals(AudioDevice))
{
logger.Trace($"ShortcutItem/RefreshValidity: Detected audio playback device {audioDevice.FullName} is the one we want!");
if (audioDevice.State == DeviceState.Disabled)
{
logger.Warn($"ShortcutRepository/RefreshValidity: Detected audio playback device {audioDevice.FullName} is the one we want, but it is 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)
{
logger.Warn($"ShortcutRepository/RefreshValidity: Detected audio playback device {audioDevice.FullName} is the one we want, but it is not present!");
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)
{
logger.Warn($"ShortcutRepository/RefreshValidity: Detected audio playback device {audioDevice.FullName} is the one we want, but it is 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
{
logger.Error($"ShortcutRepository/RefreshValidity: The audio device chipset is not supported by DisplayMagician!");
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)
{
IEnumerable<CoreAudioDevice> captureDevices = null;
if (audioController != null)
{
try
{
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)
{
logger.Trace($"ShortcutItem/RefreshValidity: Detected capture device {captureDevice.FullName}");
if (captureDevice.FullName.Equals(CaptureDevice))
{
logger.Trace($"ShortcutItem/RefreshValidity: Detected capture device {captureDevice.FullName} is the one we want!");
if (captureDevice.State == DeviceState.Disabled)
{
logger.Warn($"ShortcutRepository/RefreshValidity: Detected capture device {captureDevice.FullName} is the one we want, but it is 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)
{
logger.Warn($"ShortcutRepository/RefreshValidity: Detected capture device {captureDevice.FullName} is the one we want, but it is not present!");
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)
{
logger.Warn($"ShortcutRepository/RefreshValidity: Detected capture device {captureDevice.FullName} is the one we want, but it is 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
{
logger.Error($"ShortcutRepository/RefreshValidity: The capture device chipset is not supported by DisplayMagician!");
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;
}
}
// TODO Do all the specified pre-start apps still exist?
// Save the worst error level to IsValid property
IsValid = worstError;
}
// ReSharper disable once FunctionComplexityOverflow
// ReSharper disable once CyclomaticComplexity
public bool CreateShortcut(string shortcutFileName)
{
string programName = Path.GetFileNameWithoutExtension(ExecutableNameAndPath);
string shortcutDescription = string.Empty;
string shortcutIconFileName;
var shortcutArgs = new List<string>
{
// Add the SwitchProfile command as the first argument to start to switch to another profile
$"{DisplayMagicianStartupAction.RunShortcut}",
$"\"{UUID}\""
};
// Only add the rest of the options if the permanence is temporary
if (DisplayPermanence == ShortcutPermanence.Temporary)
{
// Only add this set of options if the shortcut is to an standalone application
if (Category == ShortcutCategory.Application)
{
// Prepare text for the shortcut description field
shortcutDescription = string.Format(Language.Execute_application_with_profile, programName, ProfileToUse.Name);
}
// 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 (DisplayPermanence == ShortcutPermanence.Temporary)
{
// Prepare text for the shortcut description field
shortcutDescription = string.Format(Language.Execute_application_with_profile, GameName, ProfileToUse.Name);
}
}
// Only add the rest of the options if the permanent switch radio button is set
else
{
// Prepare text for the shortcut description field
shortcutDescription = string.Format(Language.Switching_display_profile_to_profile, ProfileToUse.Name);
}
// Now we are ready to create a shortcut based on the filename the user gave us
shortcutFileName = Path.ChangeExtension(shortcutFileName, @"lnk");
// And we use the Icon from the shortcutIconCache
SaveShortcutIconToCache();
shortcutIconFileName = SavedShortcutIconCacheFilename;
// If the user supplied a file
if (shortcutFileName != null)
{
try
{
// Remove the old file if it exists to replace it
if (System.IO.File.Exists(shortcutFileName))
{
System.IO.File.Delete(shortcutFileName);
}
WshShell shell = new WshShell();
IWshShortcut shortcut = (IWshShortcut)shell.CreateShortcut(shortcutFileName);
shortcut.TargetPath = Application.ExecutablePath;
shortcut.Arguments = string.Join(" ", shortcutArgs);
shortcut.Description = shortcutDescription;
shortcut.WorkingDirectory = Path.GetDirectoryName(Application.ExecutablePath) ??
string.Empty;
shortcut.IconLocation = shortcutIconFileName;
shortcut.Save();
}
catch (Exception ex)
{
logger.Warn(ex, $"ShortcutItem/CreateShortcut: Execption while creating desktop shortcut!");
// Clean up a failed attempt
if (System.IO.File.Exists(shortcutFileName))
{
System.IO.File.Delete(shortcutFileName);
}
}
}
// Return a status on how it went
// true if it was a success or false if it was not
return shortcutFileName != null && System.IO.File.Exists(shortcutFileName);
}
public void AutoSuggestShortcutName()
{
if (AutoName && _profileToUse is ProfileItem)
{
if (Category.Equals(ShortcutCategory.Game) && GameName.Length > 0)
{
_name = $"{GameName} ({_profileToUse.Name})";
}
else if (Category.Equals(ShortcutCategory.Application) && ExecutableNameAndPath.Length > 0)
{
string baseName = Path.GetFileNameWithoutExtension(ExecutableNameAndPath);
_name = $"{baseName} ({_profileToUse.Name})";
}
else
{
if (DisplayPermanence.Equals(ShortcutPermanence.Permanent))
_name = $"{_profileToUse.Name}";
else if (DisplayPermanence.Equals(ShortcutPermanence.Temporary))
_name = $"{_profileToUse.Name} (Temporary)";
}
}
}
public int CompareTo(object obj)
{
if (!(obj is ShortcutItem)) throw new ArgumentException("Object to CompareTo is not a Shortcut"); ;
ShortcutItem otherShortcut = (ShortcutItem) obj;
return this.Name.CompareTo(otherShortcut.Name);
}
}
#region JsonConverterBitmap
internal class CustomBitmapConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
//convert from byte to bitmap (deserialize)
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string image = (string)reader.Value;
byte[] byteBuffer = Convert.FromBase64String(image);
MemoryStream memoryStream = new MemoryStream(byteBuffer)
{
Position = 0
};
return (Bitmap)Bitmap.FromStream(memoryStream);
}
//convert bitmap to byte (serialize)
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
Bitmap bitmap = (Bitmap)value;
ImageConverter converter = new ImageConverter();
writer.WriteValue((byte[])converter.ConvertTo(bitmap, typeof(byte[])));
}
public static System.Drawing.Imaging.ImageFormat GetImageFormat(Bitmap bitmap)
{
ImageFormat img = bitmap.RawFormat;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))
return System.Drawing.Imaging.ImageFormat.Jpeg;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Bmp))
return System.Drawing.Imaging.ImageFormat.Bmp;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Png))
return System.Drawing.Imaging.ImageFormat.Png;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Emf))
return System.Drawing.Imaging.ImageFormat.Emf;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Exif))
return System.Drawing.Imaging.ImageFormat.Exif;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Gif))
return System.Drawing.Imaging.ImageFormat.Gif;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Icon))
return System.Drawing.Imaging.ImageFormat.Icon;
if (img.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))
return System.Drawing.Imaging.ImageFormat.MemoryBmp;
if (img.Equals(System.Drawing.Imaging.ImageFormat.Tiff))
return System.Drawing.Imaging.ImageFormat.Tiff;
else
return System.Drawing.Imaging.ImageFormat.Wmf;
}
}
#endregion
}