Newer
Older
Qwilight / Qwilight / View / QwilightClass.xaml.cs
using CommandLine;
using Ionic.Zip;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.Win32;
using Microsoft.Windows.ApplicationModel.DynamicDependency;
using Qwilight.Utilities;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Runtime;
using System.Runtime.InteropServices;
using System.Text;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
using SplashScreen = System.Windows.SplashScreen;
using StartupEventArgs = System.Windows.StartupEventArgs;
using VirtualKey = Windows.System.VirtualKey;

namespace Qwilight.View
{
    public sealed partial class QwilightClass
    {
        static SplashScreen _wpfLoadingAsset;

        [STAThread]
        static void Main(string[] args)
        {
            Parser.Default.ParseArguments<FlintSystem.FlintParams>(args)
                .WithParsed(o =>
                {
                    using (var ss = new NamedPipeClientStream(".", "Qwilight", PipeDirection.Out))
                    {
                        try
                        {
                            ss.Connect(0);
                            ss.Write(Encoding.UTF8.GetBytes(string.Join(' ', args)));
                        }
                        catch (TimeoutException)
                        {
                        }
                    }
                })
                .WithNotParsed(e =>
                {
                    #region COMPATIBLE
                    Compatible.Compatible.Qwilight(QwilightComponent.QwilightEntryPath);
                    #endregion

                    if (Utility.HasInput(VirtualKey.LeftShift))
                    {
                        PInvoke.AllocConsole();
                    }

                    GPUConfigure.Instance.Load();
                    switch (GPUConfigure.Instance.GPUModeValue)
                    {
                        case GPUConfigure.GPUMode.NVIDIA:
                            NativeLibrary.TryLoad("nvapi64", out _);
                            break;
                    }
                    _wpfLoadingAsset = new("Assets/Drawing/Loading.png");
                    _wpfLoadingAsset.Show(true, true);

#if DEBUG
            Environment.SetEnvironmentVariable("ENABLE_XAML_DIAGNOSTICS_SOURCE_INFO", "1");
#endif
                    Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", QwilightComponent.EdgeEntryPath);

                    ProfileOptimization.SetProfileRoot(QwilightComponent.QwilightEntryPath);
                    ProfileOptimization.StartProfile("Qwilight.$");

                    if (!Bootstrap.TryInitialize(65541U, out _))
                    {
#if X64
                        using var exe = Process.Start(Path.Combine(QwilightComponent.CPUAssetsEntryPath, "windowsappruntimeinstall-x64.exe"));
#else
                using var exe = Process.Start(Path.Combine(QwilightComponent.CPUAssetsEntryPath, "windowsappruntimeinstall-arm64.exe"));
#endif
                        exe.WaitForExit();
                        if (!Bootstrap.TryInitialize(65541U, out _))
                        {
                            Bootstrap.Initialize(65541U, null, default, Bootstrap.InitializeOptions.OnNoMatch_ShowUI);
                        }
                    }

                    try
                    {
                        using (var r = Registry.LocalMachine.OpenSubKey("SOFTWARE")?.OpenSubKey("WOW6432Node")?.OpenSubKey("Microsoft")?.OpenSubKey("EdgeUpdate")?.OpenSubKey("Clients")?.OpenSubKey("{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"))
                        {
                            if (string.IsNullOrEmpty(r?.GetValue("pv") as string))
                            {
                                using var exe = Process.Start(Path.Combine(QwilightComponent.AssetsEntryPath, "MicrosoftEdgeWebview2Setup.exe"));
                                exe.WaitForExit();
                            }
                        }
                    }
                    catch
                    {
                    }

                    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                    _ = PInvoke.timeBeginPeriod(1);
                    ThreadPool.GetMaxThreads(out var tw, out var tIOCP);
                    ThreadPool.SetMinThreads(tw, tIOCP);

                    Application.Start(p =>
                    {
                        SynchronizationContext.SetSynchronizationContext(new DispatcherQueueSynchronizationContext(DispatcherQueue.GetForCurrentThread()));
                        try
                        {
                            new QwilightClass().Run();
                        }
                        finally
                        {
                            Application.Current.Exit();
                        }
                    });
                });
        }

        readonly ConcurrentDictionary<Exception, object> _handledFaultMap = new();

        void OnUnhandledFault(Exception e)
        {
            if (_handledFaultMap.TryAdd(e, null))
            {
                var (logFilePath, faultText) = Utility.SaveFaultFile(QwilightComponent.FaultEntryPath, e);
                if (!QwilightComponent.IsVS)
                {
                    _ = TwilightSystem.Instance.PostWwwParallel($"{QwilightComponent.QwilightAPI}/fault", faultText);
                }
                PInvoke.MessageBox(HWND.Null, e.Message, "Qwilight", MESSAGEBOX_STYLE.MB_OK | MESSAGEBOX_STYLE.MB_ICONERROR);
                Utility.OpenAs(logFilePath);
            }
        }

        QwilightClass() => InitializeComponent();

        protected override void OnStartup(StartupEventArgs e)
        {
            AppContext.SetSwitch("MVVMTOOLKIT_DISABLE_INOTIFYPROPERTYCHANGING", true);

            AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
            {
                var fault = e.ExceptionObject as Exception;
                if (!(fault is Win32Exception && (fault as Win32Exception).NativeErrorCode == 1400))
                {
                    OnUnhandledFault(fault);
                }
            };
            UIHandler.Instance.Init(OnUnhandledFault);

            QwilightComponent.OnGetBuiltInData = data => TryFindResource(data);

            try
            {
                Directory.CreateDirectory(QwilightComponent.BundleEntryPath);
                Directory.CreateDirectory(QwilightComponent.CommentEntryPath);
                Directory.CreateDirectory(QwilightComponent.EdgeEntryPath);
                Directory.CreateDirectory(QwilightComponent.MediaEntryPath);
                Directory.CreateDirectory(LevelSystem.EntryPath);
            }
            catch
            {
                PInvoke.MessageBox(HWND.Null, $"Cannot run Qwilight from {QwilightComponent.QwilightEntryPath}", "Qwilight", MESSAGEBOX_STYLE.MB_OK | MESSAGEBOX_STYLE.MB_ICONERROR);
                Environment.Exit(1);
            }

            PIDClass.Instance.HaveIt(_wpfLoadingAsset);

            Utility.CopyEntry(Path.Combine(QwilightComponent.AssetsEntryPath, "UI"), Path.Combine(QwilightComponent.UIEntryPath));

            var qwilightBundleFilePath = Path.Combine(QwilightComponent.QwilightEntryPath, "Qwilight.zip");
            if (File.Exists(qwilightBundleFilePath))
            {
                using (var zipFile = new ZipFile(qwilightBundleFilePath))
                {
                    zipFile.ExtractAll(QwilightComponent.QwilightEntryPath, ExtractExistingFileAction.OverwriteSilently);
                }
                Utility.WipeFile(qwilightBundleFilePath);
            }

            Configure.Instance.Load();
            LanguageSystem.Instance.Init(Configure.Instance.Language);
            DB.Instance.Load();
            FastDB.Instance.Load();
            AudioSystem.Instance.Init();

            _wpfLoadingAsset = null;
        }
    }
}