/// <summary> /// Terminates the program gracefully /// </summary> /// <param name="exitCode">Optional exit code</param> /// <param name="exit">Whether to actually exit or just perform cleanup tasks</param> internal static void Exit(int exitCode = 0, bool exit = true) { try { Log.WriteLine(LogLevel.Warning, $"exiting with code 0x{exitCode:x8}"); DesktopKeyboardHook?.Dispose(); DesktopMouseHook?.Dispose(); TrayIcon?.Hide(); Options?.Save(); HudManager?.Dispose(); UpdateManager?.Dispose(); #if DEBUG Log.WriteLine(LogLevel.Warning, ObjectTracker.ReportActiveObjects()); #endif loggerStream.Dispose(); Log.Streams.Clear(); GC.WaitForPendingFinalizers(); } catch (Exception exception) { // try to log exceptions if (Log.Streams?.Count > 0 && Log.Streams.All(s => s.CanWrite)) { Log.WriteLine(LogLevel.Error, $"exception caught: {exception}"); } } finally { if (exit) { Environment.ExitCode = exitCode; System.Windows.Forms.Application.Exit(); } } }
private static void Main(string[] args) { #if DEBUG // black magic - tracks unmanaged D2D/D3D objects and prints out unreleased resources at exit Configuration.EnableObjectTracking = true; ObjectTracker.StackTraceProvider = () => Environment.StackTrace; #endif HandleCommandLineArgs(args); // is another instance of the application currently running? // TODO: allow multiple instances with a key switch (i.e. Shift) if (Mutex.TryOpenExisting(SingleInstanceMutexName, out Mutex _)) { Environment.Exit(1); } // create a mutex that will prevent multiple instances of the application to be run SingleInstanceMutex = new Mutex(true, SingleInstanceMutexName); // Windows Forms setup System.Windows.Forms.Application.EnableVisualStyles(); System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); #if !DEBUG System.Windows.Forms.Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException, true); System.Windows.Forms.Application.ThreadException += (s, e) => { Log.Error("unhandled exception: ${e.Exception}"); Restart(e.Exception.HResult); }; #endif // initialize file system manager and log file stream Log = new Logger(); FsManager = new FsManager(); try { // create/open log file stream loggerStream = new FileStream(Path.Combine(FsManager.GetSafePath(FsManager.LogsPath), DateTime.UtcNow.ToString("yy.MM.dd") + ".log"), FileMode.Append); Log.Streams.Add(loggerStream); } catch (Exception exception) { Log.Warn($"could not open logger stream: {exception}"); } // write version info to log Log.Info( $"{System.Windows.Forms.Application.ProductName} {Version} ({(Environment.Is64BitProcess ? 64 : 32)}-bit)"); Log.Info($"{Environment.OSVersion} ({(Environment.Is64BitOperatingSystem ? 64 : 32)}-bit)"); // initialize main components Options = Options.Load() ?? new Options(); ExtensionManager = new ExtensionManager(); EnforceIntegratedGraphics(); InitialSetup(); TrayIcon = new TrayIcon(); UpdateManager = new UpdateManager(); // global hook behaviours DesktopKeyboardHook = new DesktopKeyboardHook(); DesktopMouseHook = new DesktopMouseHook(); // HUD manager depends on the hooks HudManager = new HudManager(); DesktopKeyboardHook.RequestLock(); // release the mutex when the application is terminated System.Windows.Forms.Application.ApplicationExit += (s, e) => { lock (SingleInstanceMutex) { SingleInstanceMutex.ReleaseMutex(); } }; new Workflow { Codec = (typeof(HevcMediaFoundationVideoCodec).FullName, null), Handlers = new (string, object)[] { (typeof(FileHandler).FullName, null) },