using System; using System.Diagnostics; using System.Globalization; using System.IO; using System.Threading.Tasks; using System.Windows; using System.Windows.Threading; using BetterGenshinImpact.Core.Recognition.OCR; using BetterGenshinImpact.Core.Recognition.ONNX; using BetterGenshinImpact.GameTask; using BetterGenshinImpact.Helpers; using BetterGenshinImpact.Helpers.Extensions; using BetterGenshinImpact.Helpers.Win32; using BetterGenshinImpact.Hutao; using BetterGenshinImpact.Service; using BetterGenshinImpact.Service.Interface; using BetterGenshinImpact.Service.Notification; using BetterGenshinImpact.Service.Notifier; using BetterGenshinImpact.View; using BetterGenshinImpact.View.Pages; using BetterGenshinImpact.ViewModel; using BetterGenshinImpact.ViewModel.Pages; using BetterGenshinImpact.ViewModel.Pages.View; using LazyCache; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Serilog; using Serilog.Events; using Serilog.Sinks.RichTextBox.Abstraction; using Wpf.Ui; using Wpf.Ui.DependencyInjection; using Wpf.Ui.Violeta.Appearance; using Wpf.Ui.Violeta.Controls; // Wine 平台适配 using BetterGenshinImpact.Platform.Wine; using BetterGenshinImpact.Service.Tavern; namespace BetterGenshinImpact; public partial class App : Application { // The.NET Generic Host provides dependency injection, configuration, logging, and other services. // https://docs.microsoft.com/dotnet/core/extensions/generic-host // https://docs.microsoft.com/dotnet/core/extensions/dependency-injection // https://docs.microsoft.com/dotnet/core/extensions/configuration // https://docs.microsoft.com/dotnet/core/extensions/logging private static readonly IHost _host = Host.CreateDefaultBuilder() .CheckIntegration() .UseElevated() .UseSingleInstance("BetterGI") .ConfigureLogging(builder => { builder.ClearProviders(); }) .ConfigureServices( (context, services) => { // 提前初始化配置 var configService = new ConfigService(); services.AddSingleton(sp => configService); var all = configService.Get(); var logFolder = Path.Combine(AppContext.BaseDirectory, "log"); Directory.CreateDirectory(logFolder); var logFile = Path.Combine(logFolder, "better-genshin-impact.log"); var richTextBox = new RichTextBoxImpl(); services.AddSingleton(richTextBox); var loggerConfiguration = new LoggerConfiguration() .WriteTo.File(logFile, outputTemplate: "[{Timestamp:HH:mm:ss.fff}] [{Level:u3}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 31, retainedFileTimeLimit: TimeSpan.FromDays(21)) .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}") .MinimumLevel.Debug() .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Warning); if (all.MaskWindowConfig.MaskEnabled) { loggerConfiguration.WriteTo.RichTextBox(richTextBox, LogEventLevel.Information, "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}"); } Log.Logger = loggerConfiguration.CreateLogger(); services.AddSingleton(); services.AddSingleton(); services.AddLogging(c => c.AddSerilog()); // if ("zh-Hans".Equals(all.OtherConfig.UiCultureInfoName, StringComparison.OrdinalIgnoreCase)) // { // services.AddLogging(c => c.AddSerilog()); // } // else // { // services.AddLogging(logging => // { // logging.ClearProviders(); // logging.SetMinimumLevel(LogLevel.Debug); // logging.AddFilter("Microsoft", LogLevel.Warning); // logging.AddFilter("Microsoft.Hosting.Lifetime", LogLevel.Warning); // logging.Services.AddSingleton(); // }); // } services.AddLocalization(); services.AddNavigationViewPageProvider(); // App Host services.AddHostedService(); // Page resolver service services.AddSingleton(); services.AddSingleton(); // Service containing navigation, same as INavigationWindow... but without window services.AddSingleton(); services.AddSingleton(); // Main window with navigation services.AddView(); services.AddSingleton(); // Views services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddView(); services.AddSingleton(); // services.AddView(); services.AddView(); // 一条龙 ViewModels // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // services.AddSingleton(); // My Services services.AddSingleton(); services.AddSingleton(); services.AddHostedService(sp => sp.GetRequiredService()); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddMemoryCache(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(TimeProvider.System); services.AddSingleton(); // Configuration //services.Configure(context.Configuration.GetSection(nameof(AppConfig))); I18N.Culture = new CultureInfo("zh-Hans"); // #1846 } ) .Build(); public static IServiceProvider ServiceProvider => _host.Services; public static ILogger GetLogger() { return _host.Services.GetService>()!; } /// /// Gets registered service. /// /// Type of the service to get. /// Instance of the service or . public static T? GetService() where T : class { return _host.Services.GetService(typeof(T)) as T; } /// /// Gets registered service. /// /// Instance of the service or . /// public static object? GetService(Type type) { return _host.Services.GetService(type); } /// /// Occurs when the application is loading. /// protected override async void OnStartup(StartupEventArgs e) { // Wine 平台适配 WinePlatformAddon.ApplyApplicationConfig(); base.OnStartup(e); try { // 分配控制台窗口以支持控制台输出 ConsoleHelper.AllocateConsole("BetterGI Console"); RegisterEvents(); await _host.StartAsync(); ServerTimeHelper.Initialize(_host.Services.GetRequiredService()); await UrlProtocolHelper.RegisterAsync(); } catch (Exception ex) { // DEBUG only, no overhead Debug.WriteLine(ex); ConsoleHelper.WriteError($"应用程序启动失败: {ex.Message}"); if (Debugger.IsAttached) { Debugger.Break(); } } } /// /// Occurs when the application is closing. /// protected override async void OnExit(ExitEventArgs e) { base.OnExit(e); ConsoleHelper.WriteLine("BetterGI 应用程序正在关闭..."); TempManager.CleanUp(); await _host.StopAsync(); _host.Dispose(); // 释放控制台窗口 ConsoleHelper.FreeConsoleWindow(); } /// /// 注册事件 /// private void RegisterEvents() { //Task线程内未捕获异常处理事件 TaskScheduler.UnobservedTaskException += TaskSchedulerUnobservedTaskException; //UI线程未捕获异常处理事件(UI主线程) this.DispatcherUnhandledException += AppDispatcherUnhandledException; //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) AppDomain.CurrentDomain.UnhandledException += CurrentDomainUnhandledException; } private static void TaskSchedulerUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e) { try { HandleException(e.Exception); } catch (Exception ex) { HandleException(ex); } finally { e.SetObserved(); } } //非UI线程未捕获异常处理事件(例如自己创建的一个子线程) private static void CurrentDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) { try { if (e.ExceptionObject is Exception exception) { HandleException(exception); } } catch (Exception ex) { HandleException(ex); } finally { //ignore } } //UI线程未捕获异常处理事件(UI主线程) private static void AppDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) { try { HandleException(e.Exception); } catch (Exception ex) { HandleException(ex); } finally { //处理完后,我们需要将Handler=true表示已此异常已处理过 e.Handled = true; } } private static void HandleException(Exception e) { if (e.InnerException != null) { e = e.InnerException; } try { ExceptionReport.Show(e); } catch { // Fallback. System.Windows.Forms.MessageBox.Show( $""" 程序异常:{e.Source} -- {e.StackTrace} -- {e.Message} """ ); } // log GetLogger().LogDebug(e, "UnHandle Exception"); } }