/// <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) },