Skip to content

Commit

Permalink
Multiple bugfixes
Browse files Browse the repository at this point in the history
- Fixed: WebView2RuntimeNotFoundException (WebView2 not installed)
- Fixed: AbandonedMutexException (Application recently closed, soon enough that the check for 'is already running' fails.
- To prevent infinite reloads to attempt to fix an issue, it has been capped to 5 before throwing an error.
- Catches update error if can't decode my update list (almost always due to me making a typo. Now has a friendly message).
- Fixed error when styles folder and stylesheet file are both deleted. Now asks for user to verify files instead of just crashing out.
  • Loading branch information
TCNOco committed Jun 12, 2021
1 parent f971546 commit c82f8ce
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 80 deletions.
90 changes: 54 additions & 36 deletions TcNo-Acc-Switcher-Client/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,16 @@ internal static class NativeMethods
// And: https://stackoverflow.com/questions/2669463/console-writeline-does-not-show-up-in-output-window/2669596#2669596
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int AllocConsole();

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern int FreeConsole();

[DllImport("kernel32.dll", SetLastError = true)]
private static extern IntPtr GetConsoleWindow();

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern bool SetWindowText(IntPtr hwnd, string lpString);

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool AttachConsole(int dwProcessId);

Expand All @@ -74,6 +78,7 @@ public static void SetWindowText(string text)

SetWindowText(handle, text);
}

public static bool AttachToConsole(int dwProcessId) => AttachConsole(dwProcessId);
}

Expand All @@ -82,12 +87,14 @@ protected override void OnExit(ExitEventArgs e)
_ = NativeMethods.FreeConsole();
Mutex.ReleaseMutex();
}

private static readonly Mutex Mutex = new(true, "{A240C23D-6F45-4E92-9979-11E6CE10A22C}");

[STAThread]
protected override async void OnStartup(StartupEventArgs e)
{
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location) ?? string.Empty); // Set working directory to same as .exe
Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location) ??
string.Empty); // Set working directory to same as .exe
// Crash handler
AppDomain.CurrentDomain.UnhandledException += Globals.CurrentDomain_UnhandledException;
// Upload crash logs if any, before starting program
Expand Down Expand Up @@ -115,7 +122,8 @@ protected override async void OnStartup(StartupEventArgs e)
// - Therefore: It was a CLI command
if (StartPage == "" && !(Globals.VerboseMode && e.Args.Length == 1))
{
if (!NativeMethods.AttachToConsole(-1)) // Attach to a parent process console (ATTACH_PARENT_PROCESS)
if (!NativeMethods
.AttachToConsole(-1)) // Attach to a parent process console (ATTACH_PARENT_PROCESS)
NativeMethods.AllocConsole();
Console.WriteLine(Environment.NewLine);
await ConsoleMain(e).ConfigureAwait(false);
Expand All @@ -126,7 +134,7 @@ protected override async void OnStartup(StartupEventArgs e)
}

}

#if DEBUG
NativeMethods.AllocConsole();
NativeMethods.SetWindowText("Debug console");
Expand All @@ -138,10 +146,11 @@ protected override async void OnStartup(StartupEventArgs e)
}
catch (UnauthorizedAccessException)
{
MessageBox.Show("Can't access log.txt in the TcNo Account Switcher directory!", "Failed to access files", MessageBoxButton.OK, MessageBoxImage.Error);
MessageBox.Show("Can't access log.txt in the TcNo Account Switcher directory!",
"Failed to access files", MessageBoxButton.OK, MessageBoxImage.Error);
Environment.Exit(4); // The system cannot open the file.
}

// Key being held down?
if ((Keyboard.Modifiers & ModifierKeys.Control) > 0 || (Keyboard.Modifiers & ModifierKeys.Alt) > 0 ||
(Keyboard.Modifiers & ModifierKeys.Shift) > 0 ||
Expand All @@ -153,35 +162,7 @@ protected override async void OnStartup(StartupEventArgs e)
}

// Single instance:
if (!Mutex.WaitOne(TimeSpan.Zero, true))
{
Thread.Sleep(2000); // 2 seconds before just making sure -- Might be an admin restart
try
{
if (!Mutex.WaitOne(TimeSpan.Zero, true))
{
// Try to show from tray, as user may not know it's hidden there.
var text = "";
if (!Globals.BringToFront())
text = "Another TcNo Account Switcher instance has been detected." + Environment.NewLine +
"[Something wrong? Hold Hold Alt, Ctrl, Shift or Scroll Lock while starting to close all TcNo processes!]";
else
text = "TcNo Account Switcher was running." + Environment.NewLine +
"I've brought it to the top." + Environment.NewLine +
"Make sure to check your Windows Task Tray for the icon :)" + Environment.NewLine +
"- You can exit it from there too" + Environment.NewLine + Environment.NewLine +
"[Something wrong? Hold Alt, Ctrl, Shift or Scroll Lock while starting to close all TcNo processes!]";

MessageBox.Show(text, "TcNo Account Switcher Notice", MessageBoxButton.OK, MessageBoxImage.Information,
MessageBoxResult.OK, MessageBoxOptions.DefaultDesktopOnly);
Environment.Exit(1056); // 1056 An instance of the service is already running.
}
}
catch (AbandonedMutexException)
{
// Just restarted
}
}
IsRunningAlready();

// See if updater was updated, and move files:
if (Directory.Exists("newUpdater"))
Expand All @@ -196,17 +177,54 @@ protected override async void OnStartup(StartupEventArgs e)
Globals.KillProcess("TcNo-Acc-Switcher-Updater");
GeneralFuncs.RecursiveDelete(new DirectoryInfo("updater"), false);
}

Directory.Move("newUpdater", "updater");
}

// Check for update in another thread
new Thread(CheckForUpdate).Start();

// Show window (Because no command line commands were parsed)
var mainWindow = new MainWindow();
mainWindow.ShowDialog();
}

/// <summary>
/// Shows error and exits program is program is already running
/// </summary>
private static void IsRunningAlready()
{
try
{
if (Mutex.WaitOne(TimeSpan.Zero, true)) return;

// Otherwise: It has probably just closed. Wait a few and try again
Thread.Sleep(2000); // 2 seconds before just making sure -- Might be an admin restart

if (Mutex.WaitOne(TimeSpan.Zero, true)) return;
// Try to show from tray, as user may not know it's hidden there.
var text = "";
if (!Globals.BringToFront())
text = "Another TcNo Account Switcher instance has been detected." + Environment.NewLine +
"[Something wrong? Hold Hold Alt, Ctrl, Shift or Scroll Lock while starting to close all TcNo processes!]";
else
text = "TcNo Account Switcher was running." + Environment.NewLine +
"I've brought it to the top." + Environment.NewLine +
"Make sure to check your Windows Task Tray for the icon :)" + Environment.NewLine +
"- You can exit it from there too" + Environment.NewLine + Environment.NewLine +
"[Something wrong? Hold Alt, Ctrl, Shift or Scroll Lock while starting to close all TcNo processes!]";

MessageBox.Show(text, "TcNo Account Switcher Notice", MessageBoxButton.OK,
MessageBoxImage.Information,
MessageBoxResult.OK, MessageBoxOptions.DefaultDesktopOnly);
Environment.Exit(1056); // 1056 An instance of the service is already running.
}
catch (AbandonedMutexException)
{
// Just restarted
}
}

/// <summary>
/// CLI specific interface for TcNo Account Switcher
/// (Only help commands at this moment)
Expand Down
34 changes: 26 additions & 8 deletions TcNo-Acc-Switcher-Client/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,33 @@ public MainWindow()

private async void MView2_OnInitialised(object sender, EventArgs e)
{
MView2.Source = new Uri($"http://localhost:{AppSettings.ServerPort}/{App.StartPage}");
await MView2.EnsureCoreWebView2Async();
MViewAddForwarders();
MView2.NavigationStarting += UrlChanged;
try
{
MView2.Source = new Uri($"http://localhost:{AppSettings.ServerPort}/{App.StartPage}");
await MView2.EnsureCoreWebView2Async();
MViewAddForwarders();
MView2.NavigationStarting += UrlChanged;


MView2.CoreWebView2.GetDevToolsProtocolEventReceiver("Runtime.consoleAPICalled").DevToolsProtocolEventReceived += ConsoleMessage;
MView2.CoreWebView2.GetDevToolsProtocolEventReceiver("Runtime.exceptionThrown").DevToolsProtocolEventReceived += ConsoleMessage;
await MView2.CoreWebView2.CallDevToolsProtocolMethodAsync("Runtime.enable", "{}");
MView2.CoreWebView2.GetDevToolsProtocolEventReceiver("Runtime.consoleAPICalled").DevToolsProtocolEventReceived += ConsoleMessage;
MView2.CoreWebView2.GetDevToolsProtocolEventReceiver("Runtime.exceptionThrown").DevToolsProtocolEventReceived += ConsoleMessage;
await MView2.CoreWebView2.CallDevToolsProtocolMethodAsync("Runtime.enable", "{}");
}
catch (WebView2RuntimeNotFoundException)
{
// WebView2 is not installed!
MessageBox.Show("WebView2 Runtime is not installed. I've opened the website you need to download it from.", "Required runtime not found!", MessageBoxButton.OK, MessageBoxImage.Error);
Process.Start(new ProcessStartInfo("https://go.microsoft.com/fwlink/p/?LinkId=2124703")
{
UseShellExecute = true,
Verb = "open"
});
}
//MView2.CoreWebView2.OpenDevToolsWindow();
}

private int _refreshFixAttempts = 0;

/// <summary>
/// Handles console messages, and logs them to a file
/// </summary>
Expand All @@ -121,7 +136,10 @@ private void ConsoleMessage(object sender, CoreWebView2DevToolsProtocolEventRece
if (message.ContainsKey("exceptionDetails"))
{
Globals.WriteToLog(@$"{DateTime.Now:dd-MM-yy_hh:mm:ss.fff} - WebView2 EXCEPTION (Handled: refreshed): " + message.SelectToken("exceptionDetails.exception.description"));
MView2.Reload();
_refreshFixAttempts++;
if (_refreshFixAttempts < 5)
MView2.Reload();
else throw new Exception($"Refreshed too many times in attempt to fix issue. Error: {message.SelectToken("exceptionDetails.exception.description")}");
}
else
{
Expand Down
2 changes: 1 addition & 1 deletion TcNo-Acc-Switcher-Globals/Globals.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class Globals
#pragma warning disable CA2211 // Non-constant fields should not be visible - This is necessary due to it being a launch parameter.
public static bool VerboseMode;
#pragma warning restore CA2211 // Non-constant fields should not be visible
public static readonly string Version = "2021-06-12_00";
public static readonly string Version = "2021-06-13_00";
public static readonly string[] PlatformList = { "Steam", "Origin", "Ubisoft", "BattleNet", "Epic", "Riot" };

public static void DebugWriteLine(string s)
Expand Down
11 changes: 10 additions & 1 deletion TcNo-Acc-Switcher-Server/Data/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,16 @@ public async System.Threading.Tasks.Task SwapStylesheet(string swapTo)
/// </summary>
public void LoadStylesheetFromFile()
{
if (!File.Exists(StylesheetFile)) File.Copy("themes\\Default.yaml", StylesheetFile);
if (!File.Exists(StylesheetFile))
{
if (File.Exists("themes\\Default.yaml")) File.Copy("themes\\Default.yaml", StylesheetFile);
else
{
throw new Exception(
"Could not find \"themes\" folder in TcNo Account Switcher's directory. This (especially Default.yaml) is required for this software to run." + Environment.NewLine +
"You can run the Updater in the \"updater\" folder to verify files, and restore these missing files.");
}
}
// Load new stylesheet
var desc = new DeserializerBuilder().WithNamingConvention(HyphenatedNamingConvention.Instance).Build();
var attempts = 0;
Expand Down
74 changes: 40 additions & 34 deletions TcNo-Acc-Switcher-Updater/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -518,48 +518,54 @@ private void GetUpdatesList(ref Dictionary<string, string> updatesAndChanges)
#else
var versions = client.DownloadString(new Uri("https://tcno.co/Projects/AccSwitcher/api/update?v=" + _currentVersion));
#endif
var jUpdates = JObject.Parse(versions)["updates"];
Debug.Assert(jUpdates != null, nameof(jUpdates) + " != null");
var firstChecked = false;
foreach (var jToken in jUpdates)
{
var jUpdate = (JProperty) jToken;
if (CheckLatest(jUpdate.Name)) break; // Get up to the current version
if (!firstChecked)
try
{
var jUpdates = JObject.Parse(versions)["updates"];
Debug.Assert(jUpdates != null, nameof(jUpdates) + " != null");
var firstChecked = false;
foreach (var jToken in jUpdates)
{
firstChecked = true;
_latestVersion = jUpdate.Name;
if (CheckLatest(_latestVersion)) // If up to date or newer
break;
}
var jUpdate = (JProperty)jToken;
if (CheckLatest(jUpdate.Name)) break; // Get up to the current version
if (!firstChecked)
{
firstChecked = true;
_latestVersion = jUpdate.Name;
if (CheckLatest(_latestVersion)) // If up to date or newer
break;
}

var updateDetails = jUpdate.Value[0]!.ToString();
var updateSize = FileSizeString((double) jUpdate.Value[1]);
totalFileSize += (double) jUpdate.Value[1];
var updateDetails = jUpdate.Value[0]!.ToString();
var updateSize = FileSizeString((double)jUpdate.Value[1]);
totalFileSize += (double)jUpdate.Value[1];

updatesAndChanges.Add(jUpdate.Name, jUpdate.Value.ToString());
WriteLine($"Update found: {jUpdate.Name} [{updateSize}]");
WriteLine("- " + updateDetails);
WriteLine("");
}
updatesAndChanges.Add(jUpdate.Name, jUpdate.Value.ToString());
WriteLine($"Update found: {jUpdate.Name} [{updateSize}]");
WriteLine("- " + updateDetails);
WriteLine("");
}

WriteLine("-------------------------------------------");
WriteLine($"Total updates found: {updatesAndChanges.Count}");
if (updatesAndChanges.Count > 0)
{
WriteLine($"Total size: {FileSizeString(totalFileSize)}");
WriteLine("-------------------------------------------");
WriteLine("Click the button below to start the update.");
ButtonHandler(true, "Start update");
SetStatus("Waiting for user input...");
WriteLine($"Total updates found: {updatesAndChanges.Count}");
if (updatesAndChanges.Count > 0)
{
WriteLine($"Total size: {FileSizeString(totalFileSize)}");
WriteLine("-------------------------------------------");
WriteLine("Click the button below to start the update.");
ButtonHandler(true, "Start update");
SetStatus("Waiting for user input...");
}
else
{
WriteLine("-------------------------------------------");
WriteLine("You're up to date.");
SetStatus(":)");
}
}
else
catch (JsonReaderException)
{
WriteLine("-------------------------------------------");
WriteLine("You're up to date.");
SetStatus(":)");
MessageBox.Show("This is most likely due to me (TechNobo) pushing an update, and making a typo that broke the .json update file. Do let me know :)", "Failed to decode update list", MessageBoxButton.OK, MessageBoxImage.Error);
}

}

/// <summary>
Expand Down

0 comments on commit c82f8ce

Please sign in to comment.