213 lines
8.0 KiB
C#
213 lines
8.0 KiB
C#
using Hardcodet.Wpf.TaskbarNotification;
|
|
using Ink_Canvas.Helpers;
|
|
using iNKORE.UI.WPF.Modern.Controls;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Threading;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Windows;
|
|
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
|
|
using MessageBox = System.Windows.MessageBox;
|
|
using Window = System.Windows.Window;
|
|
|
|
namespace Ink_Canvas
|
|
{
|
|
/// <summary>
|
|
/// Interaction logic for App.xaml
|
|
/// </summary>
|
|
public partial class App : Application
|
|
{
|
|
System.Threading.Mutex mutex;
|
|
|
|
public static string[] StartArgs = null;
|
|
public static string RootPath = Environment.GetEnvironmentVariable("APPDATA") + "\\Ink Canvas\\";
|
|
|
|
// 新增:保存看门狗进程对象
|
|
private static Process watchdogProcess = null;
|
|
// 新增:标记是否为软件内主动退出
|
|
public static bool IsAppExitByUser = false;
|
|
// 新增:退出信号文件路径
|
|
private static string watchdogExitSignalFile = Path.Combine(Path.GetTempPath(), "icc_watchdog_exit_" + System.Diagnostics.Process.GetCurrentProcess().Id + ".flag");
|
|
|
|
public App()
|
|
{
|
|
this.Startup += new StartupEventHandler(App_Startup);
|
|
this.DispatcherUnhandledException += App_DispatcherUnhandledException;
|
|
StartHeartbeatMonitor();
|
|
StartWatchdogIfNeeded();
|
|
this.Exit += App_Exit; // 注册退出事件
|
|
}
|
|
|
|
// 增加字段保存崩溃后操作设置
|
|
public static CrashActionType CrashAction = CrashActionType.SilentRestart;
|
|
|
|
private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
|
|
{
|
|
Ink_Canvas.MainWindow.ShowNewMessage("抱歉,出现未预期的异常,可能导致 InkCanvasForClass 运行不稳定。\n建议保存墨迹后重启应用。", true);
|
|
LogHelper.NewLog(e.Exception.ToString());
|
|
e.Handled = true;
|
|
|
|
// 新增:根据设置自动处理崩溃
|
|
if (CrashAction == CrashActionType.SilentRestart)
|
|
{
|
|
try
|
|
{
|
|
// 静默重启:启动新进程并退出当前进程
|
|
string exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
|
|
System.Diagnostics.Process.Start(exePath);
|
|
}
|
|
catch { }
|
|
Environment.Exit(1);
|
|
}
|
|
// CrashActionType.NoAction 时不做处理
|
|
}
|
|
|
|
private TaskbarIcon _taskbar;
|
|
|
|
void App_Startup(object sender, StartupEventArgs e)
|
|
{
|
|
RunWatchdogIfNeeded();
|
|
/*if (!StoreHelper.IsStoreApp) */RootPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
|
|
|
|
LogHelper.NewLog(string.Format("Ink Canvas Starting (Version: {0})", Assembly.GetExecutingAssembly().GetName().Version.ToString()));
|
|
|
|
bool ret;
|
|
mutex = new System.Threading.Mutex(true, "InkCanvasForClass", out ret);
|
|
|
|
if (!ret && !e.Args.Contains("-m")) //-m multiple
|
|
{
|
|
LogHelper.NewLog("Detected existing instance");
|
|
MessageBox.Show("已有一个程序实例正在运行");
|
|
LogHelper.NewLog("Ink Canvas automatically closed");
|
|
Environment.Exit(0);
|
|
}
|
|
|
|
_taskbar = (TaskbarIcon)FindResource("TaskbarTrayIcon");
|
|
|
|
StartArgs = e.Args;
|
|
}
|
|
|
|
private void ScrollViewer_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
|
|
{
|
|
try
|
|
{
|
|
if (System.Windows.Forms.SystemInformation.MouseWheelScrollLines == -1)
|
|
e.Handled = false;
|
|
else
|
|
try
|
|
{
|
|
ScrollViewerEx SenderScrollViewer = (ScrollViewerEx)sender;
|
|
SenderScrollViewer.ScrollToVerticalOffset(SenderScrollViewer.VerticalOffset - e.Delta * 10 * System.Windows.Forms.SystemInformation.MouseWheelScrollLines / (double)120);
|
|
e.Handled = true;
|
|
}
|
|
catch { }
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
// 新增:用于设置崩溃后操作类型
|
|
public enum CrashActionType
|
|
{
|
|
SilentRestart,
|
|
NoAction
|
|
}
|
|
|
|
// 心跳相关
|
|
private static Timer heartbeatTimer;
|
|
private static DateTime lastHeartbeat = DateTime.Now;
|
|
private static Timer watchdogTimer;
|
|
|
|
private void StartHeartbeatMonitor()
|
|
{
|
|
// 主线程定时更新心跳
|
|
heartbeatTimer = new Timer(_ => lastHeartbeat = DateTime.Now, null, 0, 1000);
|
|
// 辅助线程检测心跳超时
|
|
watchdogTimer = new Timer(_ =>
|
|
{
|
|
if ((DateTime.Now - lastHeartbeat).TotalSeconds > 10)
|
|
{
|
|
LogHelper.NewLog("检测到主线程无响应,自动重启。");
|
|
if (CrashAction == CrashActionType.SilentRestart)
|
|
{
|
|
try
|
|
{
|
|
string exePath = Process.GetCurrentProcess().MainModule.FileName;
|
|
Process.Start(exePath);
|
|
}
|
|
catch { }
|
|
Environment.Exit(1);
|
|
}
|
|
}
|
|
}, null, 0, 3000);
|
|
}
|
|
|
|
// 看门狗进程
|
|
private void StartWatchdogIfNeeded()
|
|
{
|
|
// 避免递归启动
|
|
if (Environment.GetCommandLineArgs().Contains("--watchdog")) return;
|
|
// 启动看门狗进程
|
|
string exePath = Process.GetCurrentProcess().MainModule.FileName;
|
|
var psi = new ProcessStartInfo
|
|
{
|
|
FileName = exePath,
|
|
Arguments = "--watchdog " + Process.GetCurrentProcess().Id + " \"" + watchdogExitSignalFile + "\"",
|
|
CreateNoWindow = true,
|
|
UseShellExecute = false,
|
|
WindowStyle = ProcessWindowStyle.Hidden
|
|
};
|
|
watchdogProcess = Process.Start(psi);
|
|
}
|
|
|
|
// 看门狗主逻辑(在 Main 函数或 App_Startup 入口前加判断)
|
|
public static void RunWatchdogIfNeeded()
|
|
{
|
|
var args = Environment.GetCommandLineArgs();
|
|
if (args.Length >= 4 && args[1] == "--watchdog")
|
|
{
|
|
int pid = int.Parse(args[2]);
|
|
string exitSignalFile = args[3];
|
|
try
|
|
{
|
|
var proc = Process.GetProcessById(pid);
|
|
while (!proc.HasExited)
|
|
{
|
|
// 检查退出信号文件
|
|
if (File.Exists(exitSignalFile))
|
|
{
|
|
try { File.Delete(exitSignalFile); } catch { }
|
|
Environment.Exit(0);
|
|
}
|
|
Thread.Sleep(2000);
|
|
}
|
|
// 主进程异常退出,自动重启
|
|
string exePath = Process.GetCurrentProcess().MainModule.FileName;
|
|
Process.Start(exePath);
|
|
}
|
|
catch { }
|
|
Environment.Exit(0);
|
|
}
|
|
}
|
|
|
|
private void App_Exit(object sender, ExitEventArgs e)
|
|
{
|
|
// 仅在软件内主动退出时关闭看门狗,并写入退出信号
|
|
try
|
|
{
|
|
if (IsAppExitByUser)
|
|
{
|
|
// 写入退出信号文件,通知看门狗正常退出
|
|
File.WriteAllText(watchdogExitSignalFile, "exit");
|
|
if (watchdogProcess != null && !watchdogProcess.HasExited)
|
|
{
|
|
watchdogProcess.Kill();
|
|
}
|
|
}
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
}
|