public HidAttributes GetHidAttributes(SafeFileHandle safeFileHandle)
        {
            var isSuccess = HidD_GetAttributes(safeFileHandle, out var hidAttributes);

            _ = WindowsHelpers.HandleError(isSuccess, $"Could not get Hid Attributes (Call {nameof(HidD_GetAttributes)})", Logger);
            return(hidAttributes);
        }
        private WindowsUsbInterface GetInterface(SafeFileHandle interfaceHandle)
        {
            //TODO: We need to get the read/write size from a different API call...

            //TODO: Where is the logger/tracer?
            var isSuccess = WinUsbApiCalls.WinUsb_QueryInterfaceSettings(interfaceHandle, 0, out var interfaceDescriptor);

            var retVal = new WindowsUsbInterface(interfaceHandle, interfaceDescriptor.bInterfaceNumber, Logger, ReadBufferSizeProtected, WriteBufferSizeProtected);

            _ = WindowsHelpers.HandleError(isSuccess, "Couldn't query interface", Logger);

            Logger.LogInformation(
                "Found Interface Number: {interfaceNumber} Endpoint count: {endpointCount} Class: {class} Subclass: {subClass}",
                interfaceDescriptor.bInterfaceNumber,
                interfaceDescriptor.bNumEndpoints,
                interfaceDescriptor.bInterfaceClass,
                interfaceDescriptor.bInterfaceSubClass);

            for (byte i = 0; i < interfaceDescriptor.bNumEndpoints; i++)
            {
                isSuccess = WinUsbApiCalls.WinUsb_QueryPipe(interfaceHandle, 0, i, out var pipeInfo);
                _         = WindowsHelpers.HandleError(isSuccess, "Couldn't query endpoint", Logger);

                Logger.LogInformation("Found PipeId: {pipeId} PipeType: {pipeType} MaxPacketSize: {maxPacketSize}", pipeInfo.PipeId, pipeInfo.PipeType, pipeInfo.MaximumPacketSize);

                //TODO: We are dropping the max packet size here...

                retVal.UsbInterfaceEndpoints.Add(new WindowsUsbInterfaceEndpoint(pipeInfo.PipeId, pipeInfo.PipeType, pipeInfo.MaximumPacketSize));
            }

            return(retVal);
        }
示例#3
0
        private void UpdateFileAssociationsButtonState()
        {
            if (CurrentOS.IsWindows)
            {
                #if WIN32
                btnAssociateFiles.Visible = true;
                btnAssociateFiles.Enabled = true;
                var fileAssociation = new TangraFileAssociations();

                if (fileAssociation.Registered)
                {
                    btnAssociateFiles.Text = "Re-Associate files with Tangra";
                }
                else
                {
                    btnAssociateFiles.Text = "Associate files with Tangra";

                    if (!fileAssociation.CanRegisterWithoutElevation)
                    {
                        btnAssociateFiles.FlatStyle = FlatStyle.System;
                        WindowsHelpers.SendMessage(btnAssociateFiles.Handle, WindowsHelpers.BCM_SETSHIELD, 0, (IntPtr)1);
                    }
                }

                if (fileAssociation.CanRegisterWithoutElevation)
                {
                    btnAssociateFiles.Tag = fileAssociation;
                }
                #endif
            }
            else
            {
                btnAssociateFiles.Visible = false;
            }
        }
 public object Convert(object value, Type targetType, object parameter, string language)
 {
     if (_elementTheme == ElementTheme.Dark)
     {
         return((bool)value ? WindowsHelpers.GetSolidColorBrush("#FF5C7AB7") : WindowsHelpers.GetSolidColorBrush("#FF232323"));
     }
     return((bool)value ? WindowsHelpers.GetSolidColorBrush("#FFC6D8FB") : WindowsHelpers.GetSolidColorBrush("#FFd4e1ee"));
 }
 private void InitializeSettings()
 {
     if (!WindowsHelpers.IsSupportedVirtualDesktopVersion())
     {
         Logger.Instance.LogMessage(TracingLevel.INFO, $"Invalid Virtual Desktop Version");
         Connection.SetTitleAsync("Update\nWindows");
         return;
     }
     FetchAllVirtualDesktops();
 }
示例#6
0
        private void RemoteService_ShutdownRequested(object sender, ShutdownRequestedEventArgs e)
        {
            if ((DateTime.Now - _lastShutdownRequest).TotalSeconds < 30)
            {
                return;
            }

            _exit = true;
            WindowsHelpers.Shutdown();
            Application.Exit();
        }
示例#7
0
 /// <summary>
 /// Sets the icon image source
 /// </summary>
 public void SetIconImageSource()
 {
     try
     {
         IconImageSource = IconSource == null ? null : WindowsHelpers.GetIconOrThumbnail(IconSource, ShellThumbnailSize.Small).ToImageSource();
         IconImageSource?.Freeze();
     }
     catch (Exception ex)
     {
         Logger.Warn(ex, "Getting jump list icon image source");
     }
 }
        private static ConnectedDeviceDefinition GetDeviceDefinition(SafeFileHandle defaultInterfaceHandle, string deviceId, ILogger logger)
        {
            var bufferLength = (uint)Marshal.SizeOf(typeof(USB_DEVICE_DESCRIPTOR));

#pragma warning disable IDE0059 // Unnecessary assignment of a value
            var isSuccess2 = WinUsbApiCalls.WinUsb_GetDescriptor(defaultInterfaceHandle, WinUsbApiCalls.DEFAULT_DESCRIPTOR_TYPE, 0, WinUsbApiCalls.EnglishLanguageID, out var _UsbDeviceDescriptor, bufferLength, out var lengthTransferred);
#pragma warning restore IDE0059 // Unnecessary assignment of a value
            _ = WindowsHelpers.HandleError(isSuccess2, "Couldn't get device descriptor", logger);

            string productName  = null;
            string serialNumber = null;
            string manufacturer = null;

            if (_UsbDeviceDescriptor.iProduct > 0)
            {
                productName = WinUsbApiCalls.GetDescriptor(
                    defaultInterfaceHandle,
                    _UsbDeviceDescriptor.iProduct,
                    "Couldn't get product name",
                    logger);
            }

            if (_UsbDeviceDescriptor.iSerialNumber > 0)
            {
                serialNumber = WinUsbApiCalls.GetDescriptor(
                    defaultInterfaceHandle,
                    _UsbDeviceDescriptor.iSerialNumber,
                    "Couldn't get serial number",
                    logger);
            }

            if (_UsbDeviceDescriptor.iManufacturer > 0)
            {
                manufacturer = WinUsbApiCalls.GetDescriptor(
                    defaultInterfaceHandle,
                    _UsbDeviceDescriptor.iManufacturer,
                    "Couldn't get manufacturer",
                    logger);
            }

            return(new ConnectedDeviceDefinition(
                       deviceId,
                       DeviceType.Usb,
                       productName: productName,
                       serialNumber: serialNumber,
                       manufacturer: manufacturer,
                       vendorId: _UsbDeviceDescriptor.idVendor,
                       productId: _UsbDeviceDescriptor.idProduct,
                       writeBufferSize: _UsbDeviceDescriptor.bMaxPacketSize0,
                       readBufferSize: _UsbDeviceDescriptor.bMaxPacketSize0
                       ));
        }
示例#9
0
    /// <summary>
    /// Gets the image source for the specified path
    /// </summary>
    /// <param name="path">The path to get the image source for</param>
    /// <returns>The image source</returns>
    private static ImageSource GetImageSource(FileSystemPath path)
    {
        lock (IconCache)
        {
            if (IconCache.ContainsKey(path.FullPath))
            {
                return(IconCache[path.FullPath]);
            }

            ImageSource image = WindowsHelpers.GetIconOrThumbnail(path, ShellThumbnailSize.Small).ToImageSource();
            image.Freeze();

            IconCache.Add(path.FullPath, image);

            return(image);
        }
    }
示例#10
0
        internal static string GetDescriptor(SafeFileHandle defaultInterfaceHandle, byte index, string errorMessage, ILogger logger)
        {
            logger ??= NullLogger.Instance;

            var buffer    = new byte[256];
            var isSuccess = WinUsb_GetDescriptor(defaultInterfaceHandle, USB_STRING_DESCRIPTOR_TYPE, index, EnglishLanguageID, buffer, (uint)buffer.Length, out var transfered);

            if (WindowsHelpers.HandleError(isSuccess, errorMessage, logger, false) != 0)
            {
                logger.LogWarning(errorMessage);
                return(null);
            }

            var descriptor = new string(Encoding.Unicode.GetChars(buffer, 2, (int)transfered));

            return(descriptor.Substring(0, descriptor.Length - 1));
        }
        public HidCollectionCapabilities GetHidCapabilities(SafeFileHandle readSafeFileHandle)
        {
            var isSuccess = HidD_GetPreparsedData(readSafeFileHandle, out var pointerToPreParsedData);

            _ = WindowsHelpers.HandleError(isSuccess, "Could not get pre parsed data", Logger);

            var result = HidP_GetCaps(pointerToPreParsedData, out var hidCollectionCapabilities);

            if (result != HIDP_STATUS_SUCCESS)
            {
                throw new ApiException($"Could not get Hid capabilities. Return code: {result}");
            }

            isSuccess = HidD_FreePreparsedData(ref pointerToPreParsedData);
            _         = WindowsHelpers.HandleError(isSuccess, "Could not release handle for getting Hid capabilities", Logger);

            return(hidCollectionCapabilities);
        }
示例#12
0
    public void CreateURLShortcut(FileSystemPath shortcutName, FileSystemPath destinationDirectory, string targetURL)
    {
        try
        {
            // Make sure the file extension is correct or else Windows won't treat it as an URL shortcut
            shortcutName = shortcutName.ChangeFileExtension(new FileExtension(".url"));

            // Delete if a shortcut with the same name already exists
            DeleteFile(destinationDirectory + shortcutName);

            // Create the shortcut
            WindowsHelpers.CreateURLShortcut(shortcutName, destinationDirectory, targetURL);
        }
        catch (Exception ex)
        {
            Logger.Warn(ex, "Creating URL shortcut {0}", destinationDirectory);

            throw;
        }
    }
示例#13
0
    public async Task OpenRegistryKeyAsync(string registryKeyPath)
    {
        if (!RegistryHelpers.KeyExists(registryKeyPath))
        {
            await Message.DisplayMessageAsync(Resources.File_RegKeyNotFound, Resources.File_RegKeyNotFoundHeader, MessageType.Error);

            return;
        }

        try
        {
            WindowsHelpers.OpenRegistryPath(registryKeyPath);
            Logger.Debug("The Registry key path {0} was opened", registryKeyPath);
        }
        catch (Exception ex)
        {
            Logger.Error(ex, "Opening Registry key path {0}", registryKeyPath);

            await Message.DisplayExceptionMessageAsync(ex, Resources.File_OpenRegKeyError, Resources.File_OpenRegKeyErrorHeader);
        }
    }
        /// <summary>
        /// Opens the specified path in Explorer
        /// </summary>
        /// <param name="location">The path</param>
        public async Task OpenExplorerLocationAsync(FileSystemPath location)
        {
            if (!location.Exists)
            {
                await Services.MessageUI.DisplayMessageAsync(Resources.File_LocationNotFound, Resources.File_OpenLocationErrorHeader, MessageType.Error);

                return;
            }

            try
            {
                WindowsHelpers.OpenExplorerPath(location);
                RL.Logger?.LogDebugSource($"The explorer location {location} was opened");
            }
            catch (Exception ex)
            {
                ex.HandleError("Opening explorer location", location);

                await Services.MessageUI.DisplayExceptionMessageAsync(ex, Resources.File_OpenLocationError, Resources.File_OpenLocationErrorHeader);
            }
        }
        /// <summary>
        /// Opens the specified registry key path in RegEdit
        /// </summary>
        /// <param name="registryKeyPath">The key path to open</param>
        /// <returns>The task</returns>
        public async Task OpenRegistryKeyAsync(string registryKeyPath)
        {
            if (!RegistryHelpers.KeyExists(registryKeyPath))
            {
                await Services.MessageUI.DisplayMessageAsync(Resources.File_RegKeyNotFound, Resources.File_RegKeyNotFoundHeader, MessageType.Error);

                return;
            }

            try
            {
                WindowsHelpers.OpenRegistryPath(registryKeyPath);
                RL.Logger?.LogDebugSource($"The Registry key path {registryKeyPath} was opened");
            }
            catch (Exception ex)
            {
                ex.HandleError("Opening Registry key path", registryKeyPath);

                await Services.MessageUI.DisplayExceptionMessageAsync(ex, Resources.File_OpenRegKeyError, Resources.File_OpenRegKeyErrorHeader);
            }
        }
示例#16
0
    public async Task OpenExplorerLocationAsync(FileSystemPath location)
    {
        if (!location.Exists)
        {
            await Message.DisplayMessageAsync(Resources.File_LocationNotFound, Resources.File_OpenLocationErrorHeader, MessageType.Error);

            return;
        }

        try
        {
            WindowsHelpers.OpenExplorerPath(location);
            Logger.Debug("The explorer location {0} was opened", location);
        }
        catch (Exception ex)
        {
            Logger.Error(ex, "Opening explorer location {0}", location);

            await Message.DisplayExceptionMessageAsync(ex, Resources.File_OpenLocationError, Resources.File_OpenLocationErrorHeader);
        }
    }
        /// <summary>
        /// Creates a file shortcut
        /// </summary>
        public void CreateFileShortcut(FileSystemPath ShortcutName, FileSystemPath DestinationDirectory, FileSystemPath TargetFile, string arguments = null)
        {
            try
            {
                // Make sure the file extension is correct or else Windows won't treat it as a shortcut
                ShortcutName = ShortcutName.ChangeFileExtension(new FileExtension(".lnk"));

                // Delete if a shortcut with the same name already exists
                DeleteFile(DestinationDirectory + ShortcutName);

                // Create the shortcut
                WindowsHelpers.CreateFileShortcut(ShortcutName, DestinationDirectory, TargetFile, arguments);

                RL.Logger?.LogInformationSource($"The shortcut {ShortcutName} was created");
            }
            catch (Exception ex)
            {
                ex.HandleUnexpected("Creating shortcut", DestinationDirectory);

                throw;
            }
        }
        public async override void KeyPressed(KeyPayload payload)
        {
            Logger.Instance.LogMessage(TracingLevel.INFO, $"Key Pressed {this.GetType()}");
            if (!WindowsHelpers.IsSupportedVirtualDesktopVersion())
            {
                Logger.Instance.LogMessage(TracingLevel.INFO, $"Key Pressed but invalid Virtual Desktop Version");
                await Connection.SetTitleAsync("Update\nWindows");

                await Connection.ShowAlert();

                return;
            }

            if (SwitchVirtualDesktop())
            {
                await Connection.ShowOk();
            }
            else
            {
                await Connection.ShowAlert();
            }
        }
示例#19
0
    public void CreateFileShortcut(FileSystemPath ShortcutName, FileSystemPath DestinationDirectory, FileSystemPath TargetFile, string arguments = null)
    {
        try
        {
            // Make sure the file extension is correct or else Windows won't treat it as a shortcut
            ShortcutName = ShortcutName.ChangeFileExtension(new FileExtension(".lnk"));

            // Delete if a shortcut with the same name already exists
            DeleteFile(DestinationDirectory + ShortcutName);

            // Create the shortcut
            WindowsHelpers.CreateFileShortcut(ShortcutName, DestinationDirectory, TargetFile, arguments);

            Logger.Info("The shortcut {0} was created", ShortcutName);
        }
        catch (Exception ex)
        {
            Logger.Warn(ex, "Creating shortcut {0}", DestinationDirectory);

            throw;
        }
    }
示例#20
0
 static AppViewModel()
 {
     // Get the current Window version
     WindowsVersion = WindowsHelpers.GetCurrentWindowsVersion();
 }
示例#21
0
        /// <summary>
        /// Searches the Win32 program shortcuts for matching game install directories
        /// </summary>
        /// <param name="shortcuts">The shortcut paths</param>
        /// <param name="programShortcutGameFinders">The shortcut game finders</param>
        /// <param name="programShortcutFinders">The shortcut finders</param>
        /// <returns>The task</returns>
        protected virtual async Task SearchWin32ShortcutsAsync(IEnumerable <string> shortcuts, List <GameFinderItemContainer> programShortcutGameFinders, List <FinderItem> programShortcutFinders)
        {
            // Enumerate each program
            foreach (var shortcut in shortcuts)
            {
                // Get the file name
                var file = Path.GetFileNameWithoutExtension(shortcut);

                // Make sure we got a file
                if (file == null)
                {
                    continue;
                }

                // Check matches towards other finder items
                foreach (var finderItem in programShortcutFinders.Where(x => file.IndexOf(x.ShortcutName, StringComparison.CurrentCultureIgnoreCase) > -1).ToArray())
                {
                    FileSystemPath targetDir;

                    try
                    {
                        // Attempt to get the shortcut target path
                        targetDir = WindowsHelpers.GetShortCutTarget(shortcut).Parent;
                    }
                    catch (Exception ex)
                    {
                        ex.HandleUnexpected("Getting start menu item shortcut target for game finder", shortcut);
                        continue;
                    }

                    // Add the item
                    var added = AddItem(finderItem, targetDir);

                    // Remove if added
                    if (added)
                    {
                        programShortcutFinders.Remove(finderItem);
                    }
                }

                // Handle each game match
                foreach (var gameMatch in programShortcutGameFinders.Where(x => file.IndexOf(x.FinderItem.ShortcutName, StringComparison.CurrentCultureIgnoreCase) > -1).ToArray())
                {
                    FileSystemPath targetDir;

                    try
                    {
                        // Attempt to get the shortcut target path
                        targetDir = WindowsHelpers.GetShortCutTarget(shortcut).Parent;
                    }
                    catch (Exception ex)
                    {
                        ex.HandleUnexpected("Getting start menu item shortcut target for game finder", shortcut);
                        continue;
                    }

                    // Add the game
                    var added = await AddGameAsync(gameMatch, targetDir);

                    // Remove if added
                    if (added)
                    {
                        programShortcutGameFinders.Remove(gameMatch);
                    }
                }

                // Break if no more games needed to be found
                if (!programShortcutGameFinders.Any() && !programShortcutFinders.Any())
                {
                    break;
                }
            }
        }
        private void Initialize()
        {
            using var logScope = Logger.BeginScope("DeviceId: {deviceId} Call: {call}", DeviceId, nameof(Initialize));

            try
            {
                Close();

                int errorCode;

                if (string.IsNullOrEmpty(DeviceId))
                {
                    throw new ValidationException(
                              $"{nameof(ConnectedDeviceDefinition)} must be specified before {nameof(InitializeAsync)} can be called.");
                }

                _DeviceHandle = APICalls.CreateFile(DeviceId,
                                                    FileAccessRights.GenericWrite | FileAccessRights.GenericRead,
                                                    APICalls.FileShareRead | APICalls.FileShareWrite, IntPtr.Zero, APICalls.OpenExisting,
                                                    APICalls.FileAttributeNormal | APICalls.FileFlagOverlapped, IntPtr.Zero);

                if (_DeviceHandle.IsInvalid)
                {
                    //TODO: is error code useful here?
                    errorCode = Marshal.GetLastWin32Error();
                    if (errorCode > 0)
                    {
                        throw new ApiException($"Device handle no good. Error code: {errorCode}");
                    }
                }

                Logger.LogInformation(Messages.SuccessMessageGotWriteAndReadHandle);

                var isSuccess = WinUsbApiCalls.WinUsb_Initialize(_DeviceHandle, out var interfaceHandle);
                _ = WindowsHelpers.HandleError(isSuccess, Messages.ErrorMessageCouldntIntializeDevice, Logger);

#pragma warning disable CA2000 //We need to hold on to this handle
                var defaultInterfaceHandle = new SafeFileHandle(interfaceHandle, false);
#pragma warning restore CA2000
                var connectedDeviceDefinition = GetDeviceDefinition(defaultInterfaceHandle, DeviceId, Logger);

                if (!WriteBufferSizeProtected.HasValue)
                {
                    if (!connectedDeviceDefinition.WriteBufferSize.HasValue)
                    {
                        throw new ValidationException("Write buffer size not specified");
                    }
                    WriteBufferSizeProtected = (ushort)connectedDeviceDefinition.WriteBufferSize.Value;
                }

                if (!ReadBufferSizeProtected.HasValue)
                {
                    if (!connectedDeviceDefinition.ReadBufferSize.HasValue)
                    {
                        throw new ValidationException("Read buffer size not specified");
                    }
                    ReadBufferSizeProtected = (ushort)connectedDeviceDefinition.ReadBufferSize.Value;
                }

                //Get the first (default) interface
#pragma warning disable CA2000 //Ths should be disposed later
                var defaultInterface = GetInterface(defaultInterfaceHandle);

                UsbInterfaces.Add(defaultInterface);

                byte i = 0;
                while (true)
                {
                    isSuccess = WinUsbApiCalls.WinUsb_GetAssociatedInterface(defaultInterfaceHandle, i,
                                                                             out var interfacePointer);
                    if (!isSuccess)
                    {
                        errorCode = Marshal.GetLastWin32Error();
                        if (errorCode == APICalls.ERROR_NO_MORE_ITEMS)
                        {
                            break;
                        }

                        throw new ApiException(
                                  $"Could not enumerate interfaces for device. Error code: {errorCode}");
                    }

                    var associatedInterface = GetInterface(interfacePointer);

                    //TODO: this is bad design. The handler should be taking care of this
                    UsbInterfaces.Add(associatedInterface);

                    i++;
                }

                RegisterDefaultInterfaces();
#pragma warning restore CA2000
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, Messages.ErrorMessageCouldntIntializeDevice);
                throw;
            }
        }
示例#23
0
    public Page_Games_GameViewModel GetDisplayViewModel()
    {
        try
        {
            if (IsAdded)
            {
                var actions = new List <OverflowButtonItemViewModel>();

                // Get the manager
                var manager = Game.GetManager(Game.GetGameType());

                // Add launch options if set to do so
                if (Game.GetLaunchMode() == UserData_GameLaunchMode.AsAdminOption)
                {
                    actions.Add(new OverflowButtonItemViewModel(Resources.GameDisplay_RunAsAdmin, GenericIconKind.GameDisplay_Admin, new AsyncRelayCommand(async() => await Game.GetManager().LaunchGameAsync(true))));

                    actions.Add(new OverflowButtonItemViewModel());
                }

                // Get the Game links
                var links = GetGameFileLinks?.Where(x => x.Path.FileExists).ToArray();

                // Add links if there are any
                if (links?.Any() ?? false)
                {
                    actions.AddRange(links.
                                     Select(x =>
                    {
                        // Get the path
                        string path = x.Path;

                        // Create the command
                        var command = new AsyncRelayCommand(async() => (await Services.File.LaunchFileAsync(path, arguments: x.Arguments))?.Dispose());

                        if (x.Icon != GenericIconKind.None)
                        {
                            return(new OverflowButtonItemViewModel(x.Header, x.Icon, command));
                        }

                        try
                        {
                            return(new OverflowButtonItemViewModel(x.Header, WindowsHelpers.GetIconOrThumbnail(x.Path, ShellThumbnailSize.Small).ToImageSource(), command));
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(ex, "Getting file icon for overflow button item");
                            return(new OverflowButtonItemViewModel(x.Header, x.Icon, command));
                        }
                    }));

                    actions.Add(new OverflowButtonItemViewModel());
                }

                // Get additional items
                var additionalItems = manager.GetAdditionalOverflowButtonItems;

                // Add the items if there are any
                if (additionalItems.Any())
                {
                    actions.AddRange(additionalItems);

                    actions.Add(new OverflowButtonItemViewModel());
                }

                // Add RayMap link
                if (RayMapURL != null)
                {
                    actions.Add(new OverflowButtonItemViewModel(Resources.GameDisplay_Raymap, GenericIconKind.GameDisplay_Map, new AsyncRelayCommand(async() => (await Services.File.LaunchFileAsync(RayMapURL))?.Dispose())));
                    actions.Add(new OverflowButtonItemViewModel());
                }

                // Add open archive
                if (HasArchives)
                {
                    actions.Add(new OverflowButtonItemViewModel(Resources.GameDisplay_Archives, GenericIconKind.GameDisplay_Archive, new AsyncRelayCommand(async() =>
                    {
                        using IArchiveDataManager archiveDataManager = GetArchiveDataManager;

                        try
                        {
                            // Show the archive explorer
                            await Services.UI.ShowArchiveExplorerAsync(archiveDataManager, GetArchiveFilePaths(Game.GetInstallDir()).Where(x => x.FileExists).ToArray());
                        }
                        catch (Exception ex)
                        {
                            Logger.Error(ex, "Archive explorer");

                            await Services.MessageUI.DisplayExceptionMessageAsync(ex, Resources.Archive_CriticalError);
                        }
                    }), UserLevel.Advanced));
                }

                // Add open location
                actions.Add(new OverflowButtonItemViewModel(Resources.GameDisplay_OpenLocation, GenericIconKind.GameDisplay_Location, new AsyncRelayCommand(async() =>
                {
                    // Get the install directory
                    var instDir = Game.GetInstallDir();

                    // Select the file in Explorer if it exists
                    if ((instDir + DefaultFileName).FileExists)
                    {
                        instDir += DefaultFileName;
                    }

                    // Open the location
                    await Services.File.OpenExplorerLocationAsync(instDir);

                    Logger.Trace("The Game {0} install location was opened", Game);
                }), UserLevel.Advanced));

                actions.Add(new OverflowButtonItemViewModel(UserLevel.Advanced));

                // Add Game options
                var optionsAction = new OverflowButtonItemViewModel(Resources.GameDisplay_Options, GenericIconKind.GameDisplay_Config, new AsyncRelayCommand(async() =>
                {
                    Logger.Trace("The Game {0} options dialog is opening...", Game);
                    await GameOptionsDialog.ShowAsync(Game);
                }));

                actions.Add(optionsAction);

                return(new Page_Games_GameViewModel(
                           game: Game,
                           displayName: DisplayName,
                           iconSource: IconSource,
                           isDemo: IsDemo,
                           mainAction: new ActionItemViewModel(Resources.GameDisplay_Launch, GenericIconKind.GameDisplay_Play, new AsyncRelayCommand(async() => await Game.GetManager().LaunchGameAsync(false))),
                           secondaryAction: optionsAction,
                           launchActions: actions));
            }
            else
            {
                var actions = new List <OverflowButtonItemViewModel>();

                OverflowButtonItemViewModel downloadItem = null;

                if (CanBeDownloaded)
                {
                    downloadItem = new OverflowButtonItemViewModel(Resources.GameDisplay_CloudInstall, GenericIconKind.GameDisplay_Download, new AsyncRelayCommand(async() => await DownloadGameAsync()));

                    if (CanBeLocated)
                    {
                        actions.Add(downloadItem);
                        actions.Add(new OverflowButtonItemViewModel());
                    }
                }

                // Get the purchase links
                var links = Game.
                            // Get all available managers
                            GetManagers().
                            // Get the purchase links
                            SelectMany(x => x.GetGamePurchaseLinks);

                // Add links
                actions.AddRange(links.
                                 Select(x =>
                {
                    // Get the path
                    string path = x.Path;

                    // Create the command
                    var command = new AsyncRelayCommand(async() => (await Services.File.LaunchFileAsync(path))?.Dispose());

                    // Return the item
                    return(new OverflowButtonItemViewModel(x.Header, x.Icon, command));
                }));

                // Add disc installer options for specific Games
                if (CanBeInstalledFromDisc)
                {
                    // Add separator if there are previous actions
                    if (actions.Any())
                    {
                        actions.Add(new OverflowButtonItemViewModel());
                    }

                    // Add disc installer action
                    actions.Add(new OverflowButtonItemViewModel(Resources.GameDisplay_DiscInstall, GenericIconKind.GameDisplay_DiscInstall, new AsyncRelayCommand(async() =>
                    {
                        // Show and run the installer
                        await Services.DialogBaseManager.ShowDialogWindowAsync(new GameInstaller_Window(Game));
                    })));
                }

                // If the last option is a separator, remove it
                if (actions.LastOrDefault()?.IsSeparator == true)
                {
                    actions.RemoveAt(actions.Count - 1);
                }

                // Create the main action
                var mainAction = CanBeLocated
                    ? new ActionItemViewModel(Resources.GameDisplay_Locate, GenericIconKind.GameDisplay_Location, new AsyncRelayCommand(async() => await LocateGameAsync()))
                    : downloadItem;

                // Return the view model
                return(new Page_Games_GameViewModel(Game, DisplayName, IconSource, IsDemo, mainAction, null, actions));
            }
        }
        catch (Exception ex)
        {
            Logger.Fatal(ex, "Getting game display view model");
            throw;
        }
    }