151 lines
5.9 KiB
C#
151 lines
5.9 KiB
C#
using MAX.Framework.Logger;
|
||
using NLog;
|
||
using Prism.Autofac;
|
||
using Prism.Ioc;
|
||
using Prism.Services.Dialogs;
|
||
using Store.Management.Framework.Configs;
|
||
using Store.Management.Framework.Extensions;
|
||
using Store.Management.Framework.Services;
|
||
using System.Threading;
|
||
using System.Windows;
|
||
using System.Windows.Threading;
|
||
|
||
namespace Store.Management.Framework;
|
||
|
||
public abstract class FrameworkApplication : PrismApplication
|
||
{
|
||
private Mutex? _mutex;
|
||
private bool _ownsMutex;
|
||
private int _fatalHandling;
|
||
private int _shutdownRequested;
|
||
public static bool ShuttingDown { get; private set; }
|
||
public static bool IsAppInitialized { get; private set; }
|
||
public static event Action<Exception>? FatalErrorRaised;
|
||
|
||
protected FrameworkApplication()
|
||
{
|
||
DispatcherUnhandledException += OnDispatcherUnhandledException;
|
||
AppDomain.CurrentDomain.UnhandledException += OnDomainUnhandledException;
|
||
TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
|
||
}
|
||
|
||
/// <summary>返回 null 可允许多开;默认限制同一登录会话中的应用实例。</summary>
|
||
public virtual string? GetMutexName() => @"Local\Store.Management";
|
||
|
||
protected override void OnStartup(StartupEventArgs e)
|
||
{
|
||
try
|
||
{
|
||
//string? name = GetMutexName();
|
||
//if (!string.IsNullOrWhiteSpace(name))
|
||
//{
|
||
// _mutex = new Mutex(true, name, out _ownsMutex);
|
||
// if (!_ownsMutex)
|
||
// {
|
||
// MessageBox.Show("程序已在运行。", Config.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
|
||
// Shutdown();
|
||
// return;
|
||
// }
|
||
//}
|
||
FolderConfig.Initialize();
|
||
base.OnStartup(e);
|
||
ApplicationLogService.Initialize();
|
||
NLogger.Instance.Info($"软件启动:{Config.AppFullName},版本:{Config.GetFullVersionString()},会话:{Config.SessionID},启动时间:{Config.AppStartTime:O},Windows:{Config.WindowsVersion}");
|
||
DISource.Resolver = Resolve;
|
||
}
|
||
catch (Exception ex) { Fatal(ex); }
|
||
}
|
||
|
||
protected override void OnInitialized()
|
||
{
|
||
base.OnInitialized();
|
||
IsAppInitialized = true;
|
||
NLogger.Instance.Info("软件初始化成功,进入主页面");
|
||
}
|
||
|
||
protected override void RegisterRequiredTypes(IContainerRegistry registry)
|
||
{
|
||
base.RegisterRequiredTypes(registry);
|
||
registry.RegisterDialogWindow<Controls.DialogWindow>();
|
||
}
|
||
|
||
private object Resolve(Type type, string name)
|
||
{
|
||
if (type == null || Container is null) return null!;
|
||
return name != null ? Container.Resolve(type, name) : Container.Resolve(type);
|
||
}
|
||
|
||
private void OnDispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
|
||
{
|
||
e.Handled = true;
|
||
Fatal(e.Exception);
|
||
}
|
||
|
||
private void OnDomainUnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||
{
|
||
Exception exception = e.ExceptionObject as Exception ?? new Exception(e.ExceptionObject?.ToString());
|
||
// CLR 终止期间同步记录,不等待 UI 线程。
|
||
if (e.IsTerminating) ApplicationLogService.WriteFatal(exception, "AppDomain.UnhandledException");
|
||
else Fatal(exception);
|
||
}
|
||
|
||
private void OnUnobservedTaskException(object? sender, UnobservedTaskExceptionEventArgs e)
|
||
{
|
||
ApplicationLogService.WriteFatal(e.Exception, "TaskScheduler.UnobservedTaskException");
|
||
e.SetObserved();
|
||
}
|
||
|
||
/// <summary>先同步保存报告,再通知订阅者并关闭应用。</summary>
|
||
public static void Fatal(Exception exception)
|
||
{
|
||
ArgumentNullException.ThrowIfNull(exception);
|
||
string? path = ApplicationLogService.WriteFatal(exception, "Fatal");
|
||
if (Current is not FrameworkApplication app || Interlocked.Exchange(ref app._fatalHandling, 1) != 0) return;
|
||
foreach (Action<Exception> handler in FatalErrorRaised?.GetInvocationList() ?? [])
|
||
{
|
||
try { handler(exception); }
|
||
catch (Exception ex) { ApplicationLogService.WriteFatal(ex, "FatalErrorRaised"); }
|
||
}
|
||
void ShowErrorAndShutdown()
|
||
{
|
||
try
|
||
{
|
||
MessageBox.Show($"软件发生致命错误,即将关闭。\n{exception.Message}\n\n日志:{path ?? "写入失败,请查看调试输出"}",
|
||
Config.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
|
||
}
|
||
finally { TotalShutdown(-1); }
|
||
}
|
||
if (app.Dispatcher.CheckAccess()) ShowErrorAndShutdown();
|
||
else if (!app.Dispatcher.HasShutdownStarted) app.Dispatcher.BeginInvoke((Action)ShowErrorAndShutdown);
|
||
}
|
||
|
||
/// <summary>通过 WPF 正常退出,执行退出清理。</summary>
|
||
public static void TotalShutdown(int exitCode = 0)
|
||
{
|
||
if (Current is not FrameworkApplication app || Interlocked.Exchange(ref app._shutdownRequested, 1) != 0) return;
|
||
ShuttingDown = true;
|
||
if (app.Dispatcher.CheckAccess()) app.Shutdown(exitCode);
|
||
else if (!app.Dispatcher.HasShutdownStarted) app.Dispatcher.BeginInvoke((Action)(() => app.Shutdown(exitCode)));
|
||
}
|
||
|
||
protected override void OnExit(ExitEventArgs e)
|
||
{
|
||
ShuttingDown = true;
|
||
try { base.OnExit(e); }
|
||
finally
|
||
{
|
||
DispatcherUnhandledException -= OnDispatcherUnhandledException;
|
||
AppDomain.CurrentDomain.UnhandledException -= OnDomainUnhandledException;
|
||
TaskScheduler.UnobservedTaskException -= OnUnobservedTaskException;
|
||
DISource.Resolver = null!;
|
||
try { if (_ownsMutex) _mutex?.ReleaseMutex(); }
|
||
finally
|
||
{
|
||
_mutex?.Dispose();
|
||
try { NLogger.Instance.Info($"软件关闭,退出码:{e.ApplicationExitCode}"); }
|
||
finally { LogManager.Shutdown(); }
|
||
}
|
||
}
|
||
}
|
||
}
|