From 80f44271088bf9a02eab8b811e605312607d3c65 Mon Sep 17 00:00:00 2001 From: Sour Date: Tue, 22 Aug 2023 18:04:42 +0900 Subject: [PATCH] UI: Fixed crashes when attempting to open a file that's in use by another application --- UI/Controls/PaletteConfig.axaml.cs | 5 +++- UI/Controls/StateGridEntry.axaml.cs | 22 ++++++++------- .../ViewModels/NesHeaderEditViewModel.cs | 6 +++-- UI/Utilities/FileHelper.cs | 18 +++++++++++-- UI/Utilities/LoadRomHelper.cs | 16 ++++++----- UI/ViewModels/MainMenuViewModel.cs | 6 ++++- UI/ViewModels/NesConfigViewModel.cs | 27 ------------------- UI/ViewModels/UpdatePromptViewModel.cs | 11 ++++---- 8 files changed, 56 insertions(+), 55 deletions(-) diff --git a/UI/Controls/PaletteConfig.axaml.cs b/UI/Controls/PaletteConfig.axaml.cs index 62e68903..6b9aed23 100644 --- a/UI/Controls/PaletteConfig.axaml.cs +++ b/UI/Controls/PaletteConfig.axaml.cs @@ -123,7 +123,10 @@ namespace Mesen.Controls public void LoadPaletteFile(string filename) { - using FileStream paletteFile = File.OpenRead(filename); + using FileStream? paletteFile = FileHelper.OpenRead(filename); + if(paletteFile == null) { + return; + } byte[] paletteFileData = new byte[LargePaletteSize * 3 + 1]; int byteCount = paletteFile.Read(paletteFileData, 0, LargePaletteSize * 3 + 1); diff --git a/UI/Controls/StateGridEntry.axaml.cs b/UI/Controls/StateGridEntry.axaml.cs index 0d806f5f..85002be9 100644 --- a/UI/Controls/StateGridEntry.axaml.cs +++ b/UI/Controls/StateGridEntry.axaml.cs @@ -124,18 +124,20 @@ namespace Mesen.Controls if(Path.GetExtension(game.FileName) == "." + FileDialogHelper.MesenSaveStateExt) { img = EmuApi.GetSaveStatePreview(game.FileName); } else { - using FileStream fs = File.Open(game.FileName, FileMode.Open, FileAccess.Read, FileShare.Read); - ZipArchive zip = new ZipArchive(fs); - ZipArchiveEntry? entry = zip.GetEntry("Screenshot.png"); - if(entry != null) { - using Stream stream = entry.Open(); + using FileStream? fs = FileHelper.OpenRead(game.FileName); + if(fs != null) { + ZipArchive zip = new ZipArchive(fs); + ZipArchiveEntry? entry = zip.GetEntry("Screenshot.png"); + if(entry != null) { + using Stream stream = entry.Open(); - //Copy to a memory stream (to avoid what looks like a Skia or Avalonia issue?) - using MemoryStream ms = new MemoryStream(); - stream.CopyTo(ms); - ms.Seek(0, SeekOrigin.Begin); + //Copy to a memory stream (to avoid what looks like a Skia or Avalonia issue?) + using MemoryStream ms = new MemoryStream(); + stream.CopyTo(ms); + ms.Seek(0, SeekOrigin.Begin); - img = new Bitmap(ms); + img = new Bitmap(ms); + } } } } catch { } diff --git a/UI/Debugger/ViewModels/NesHeaderEditViewModel.cs b/UI/Debugger/ViewModels/NesHeaderEditViewModel.cs index fda830dc..aa9125c1 100644 --- a/UI/Debugger/ViewModels/NesHeaderEditViewModel.cs +++ b/UI/Debugger/ViewModels/NesHeaderEditViewModel.cs @@ -37,8 +37,10 @@ public class NesHeaderEditViewModel : DisposableViewModel string romPath = _romInfo.RomPath; try { //TODOv2, get header from core (to support for patches, etc.) - using(FileStream fileStream = File.OpenRead(romPath)) { - fileStream.Read(headerBytes, 0, 16); + using(FileStream? fileStream = FileHelper.OpenRead(romPath)) { + if(fileStream != null) { + fileStream.Read(headerBytes, 0, 16); + } } } catch { } diff --git a/UI/Utilities/FileHelper.cs b/UI/Utilities/FileHelper.cs index e899472c..f350b5e3 100644 --- a/UI/Utilities/FileHelper.cs +++ b/UI/Utilities/FileHelper.cs @@ -1,4 +1,5 @@ -using System; +using Avalonia.Threading; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -40,6 +41,13 @@ namespace Mesen.Utilities }); } + public static FileStream? OpenRead(string filepath) + { + return AttemptOperation(() => { + return File.Open(filepath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + }); + } + private static T? AttemptOperation(Func action) { int retry = 3; @@ -49,7 +57,13 @@ namespace Mesen.Utilities } catch(Exception ex) { retry--; if(retry == 0) { - MesenMsgBox.ShowException(ex); + if(Dispatcher.UIThread.CheckAccess()) { + MesenMsgBox.ShowException(ex); + } else { + Dispatcher.UIThread.Post(() => { + MesenMsgBox.ShowException(ex); + }); + } return default; } else { System.Threading.Thread.Sleep(50); diff --git a/UI/Utilities/LoadRomHelper.cs b/UI/Utilities/LoadRomHelper.cs index ecfdda2a..e7818224 100644 --- a/UI/Utilities/LoadRomHelper.cs +++ b/UI/Utilities/LoadRomHelper.cs @@ -119,13 +119,15 @@ namespace Mesen.Utilities private static bool IsPatchFile(string filename) { - using(FileStream stream = File.OpenRead(filename)) { - byte[] header = new byte[5]; - stream.Read(header, 0, 5); - if(header[0] == 'P' && header[1] == 'A' && header[2] == 'T' && header[3] == 'C' && header[4] == 'H') { - return true; - } else if((header[0] == 'U' || header[0] == 'B') && header[1] == 'P' && header[2] == 'S' && header[3] == '1') { - return true; + using(FileStream? stream = FileHelper.OpenRead(filename)) { + if(stream != null) { + byte[] header = new byte[5]; + stream.Read(header, 0, 5); + if(header[0] == 'P' && header[1] == 'A' && header[2] == 'T' && header[3] == 'C' && header[4] == 'H') { + return true; + } else if((header[0] == 'U' || header[0] == 'B') && header[1] == 'P' && header[2] == 'S' && header[3] == '1') { + return true; + } } } return false; diff --git a/UI/ViewModels/MainMenuViewModel.cs b/UI/ViewModels/MainMenuViewModel.cs index a20afc67..bc329ed9 100644 --- a/UI/ViewModels/MainMenuViewModel.cs +++ b/UI/ViewModels/MainMenuViewModel.cs @@ -1085,7 +1085,11 @@ namespace Mesen.ViewModels } try { - using(FileStream stream = File.Open(filename, FileMode.Open)) { + using(FileStream? stream = FileHelper.OpenRead(filename)) { + if(stream == null) { + return; + } + ZipArchive zip = new ZipArchive(stream); //Find the hires.txt file diff --git a/UI/ViewModels/NesConfigViewModel.cs b/UI/ViewModels/NesConfigViewModel.cs index c0d52065..ed1dc168 100644 --- a/UI/ViewModels/NesConfigViewModel.cs +++ b/UI/ViewModels/NesConfigViewModel.cs @@ -75,33 +75,6 @@ namespace Mesen.ViewModels }); } } - - public void LoadPaletteFile(string filename) - { - using(FileStream paletteFile = File.OpenRead(filename)) { - byte[] paletteFileData = new byte[512 * 3]; - int byteCount = paletteFile.Read(paletteFileData, 0, 512 * 3); - if(byteCount == 64 * 3 || byteCount == 512 * 3) { - UInt32[] paletteData = new UInt32[byteCount / 3]; - for(int i = 0; i < byteCount; i += 3) { - paletteData[i / 3] = ((UInt32)0xFF000000 | (UInt32)paletteFileData[i + 2] | (UInt32)(paletteFileData[i + 1] << 8) | (UInt32)(paletteFileData[i] << 16)); - } - Config.UserPalette = paletteData; - } - paletteFile.Close(); - } - } - - public void ExportPalette(string filename) - { - List bytePalette = new List(); - foreach(UInt32 value in Config.UserPalette) { - bytePalette.Add((byte)(value >> 16 & 0xFF)); - bytePalette.Add((byte)(value >> 8 & 0xFF)); - bytePalette.Add((byte)(value & 0xFF)); - } - FileHelper.WriteAllBytes(filename, bytePalette.ToArray()); - } } public enum NesConfigTab diff --git a/UI/ViewModels/UpdatePromptViewModel.cs b/UI/ViewModels/UpdatePromptViewModel.cs index ffbd413b..9c619752 100644 --- a/UI/ViewModels/UpdatePromptViewModel.cs +++ b/UI/ViewModels/UpdatePromptViewModel.cs @@ -103,12 +103,13 @@ namespace Mesen.ViewModels downloadPath += Path.GetExtension(entry.Name); entry.ExtractToFile(downloadPath, true); - string hash; - using(SHA256 sha256 = SHA256.Create()) { - using(FileStream fileStream = File.OpenRead(downloadPath)) { - hash = BitConverter.ToString(sha256.ComputeHash(fileStream)).Replace("-", ""); - } + string? hash = null; + using SHA256 sha256 = SHA256.Create(); + using FileStream? fileStream = FileHelper.OpenRead(downloadPath); + if(fileStream != null) { + hash = BitConverter.ToString(sha256.ComputeHash(fileStream)).Replace("-", ""); } + if(hash != _updateInfo.Hash) { File.Delete(downloadPath); }