diff --git a/Ink Canvas/Helpers/PPTManager.cs b/Ink Canvas/Helpers/PPTManager.cs index 227f012a..404c47ef 100644 --- a/Ink Canvas/Helpers/PPTManager.cs +++ b/Ink Canvas/Helpers/PPTManager.cs @@ -130,6 +130,7 @@ namespace Ink_Canvas.Helpers #region Private Fields private Timer _unifiedPptTimer; private int _monitorTickCount; + private volatile bool _unifiedPptTimerRunning; private bool _isWpsMonitoringEnabled; private Process _wpsProcess; @@ -179,10 +180,12 @@ namespace Ink_Canvas.Helpers private void OnUnifiedPptTimerElapsed(object sender, ElapsedEventArgs e) { if (_disposed || _isModuleUnloading) - { return; - } + if (_unifiedPptTimerRunning) + return; + + _unifiedPptTimerRunning = true; try { var tick = Interlocked.Increment(ref _monitorTickCount); @@ -192,25 +195,23 @@ namespace Ink_Canvas.Helpers if (IsConnected) { if (tick % 2 == 0) - { CheckSlideShowState(); - } if (_isWpsMonitoringEnabled && tick % 4 == 0) - { CheckWpsProcess(); - } } if (tick >= int.MaxValue - 1000) - { Interlocked.Exchange(ref _monitorTickCount, 0); - } } catch (Exception ex) { LogHelper.WriteLogToFile($"统一PPT监控定时器执行失败: {ex}", LogHelper.LogType.Error); } + finally + { + _unifiedPptTimerRunning = false; + } } private void CheckAndConnectToPPT() diff --git a/Ink Canvas/Helpers/ROTPPTManager.cs b/Ink Canvas/Helpers/ROTPPTManager.cs index 0251bc3b..79e117db 100644 --- a/Ink Canvas/Helpers/ROTPPTManager.cs +++ b/Ink Canvas/Helpers/ROTPPTManager.cs @@ -1,6 +1,7 @@ using Microsoft.Office.Interop.PowerPoint; using System; using System.Runtime.InteropServices; +using System.Threading; using System.Timers; using System.Windows.Threading; using Application = System.Windows.Application; @@ -162,8 +163,8 @@ namespace Ink_Canvas.Helpers // 唯一持久化的 COM 对象字段:PPT 应用程序实例 private object _pptApplication; - private Timer _connectionCheckTimer; - private Timer _slideShowStateCheckTimer; + private Timer _unifiedRotTimer; + private int _rotTickCount; private bool _isModuleUnloading; private bool _lastSlideShowState; @@ -179,28 +180,32 @@ namespace Ink_Canvas.Helpers private void InitializeTimers() { - _connectionCheckTimer = new Timer(500); - _connectionCheckTimer.Elapsed += OnConnectionCheckTimerElapsed; - _connectionCheckTimer.AutoReset = true; + _unifiedRotTimer = new Timer(500); + _unifiedRotTimer.Elapsed += OnUnifiedRotTimerElapsed; + _unifiedRotTimer.AutoReset = true; + } - _slideShowStateCheckTimer = new Timer(1000); - _slideShowStateCheckTimer.Elapsed += OnSlideShowStateCheckTimerElapsed; - _slideShowStateCheckTimer.AutoReset = true; + private void OnUnifiedRotTimerElapsed(object sender, ElapsedEventArgs e) + { + var tick = Interlocked.Increment(ref _rotTickCount); + + OnConnectionCheckTimerElapsed(sender, e); + + if (tick % 2 == 0) + OnSlideShowStateCheckTimerElapsed(sender, e); } public void StartMonitoring() { if (_disposed) return; - _connectionCheckTimer?.Start(); - _slideShowStateCheckTimer?.Start(); + _unifiedRotTimer?.Start(); LogHelper.WriteLogToFile("[ROT] PPT 监控已启动", LogHelper.LogType.Trace); } public void StopMonitoring() { - _connectionCheckTimer?.Stop(); - _slideShowStateCheckTimer?.Stop(); + _unifiedRotTimer?.Stop(); DisconnectFromPPT(); LogHelper.WriteLogToFile("[ROT] PPT 监控已停止", LogHelper.LogType.Trace); } @@ -364,8 +369,7 @@ namespace Ink_Canvas.Helpers try { _isModuleUnloading = true; - _connectionCheckTimer?.Stop(); - _slideShowStateCheckTimer?.Stop(); + _unifiedRotTimer?.Stop(); PPTConnectionChanged?.Invoke(false); LogHelper.WriteLogToFile("[ROT] 准备断开 PPT 连接,先卸载监控模块", LogHelper.LogType.Event); @@ -445,8 +449,7 @@ namespace Ink_Canvas.Helpers System.Threading.Thread.Sleep(1000); _isModuleUnloading = false; - _connectionCheckTimer?.Start(); - _slideShowStateCheckTimer?.Start(); + _unifiedRotTimer?.Start(); LogHelper.WriteLogToFile("[ROT] PPT 联动模块已重新进入联动状态", LogHelper.LogType.Trace); } diff --git a/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs b/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs index e83c4841..dafffb22 100644 --- a/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs +++ b/Ink Canvas/MainWindow_cs/MW_ClipboardHandler.cs @@ -1,5 +1,6 @@ -using Ink_Canvas.Helpers; +using Ink_Canvas.Helpers; using System; +using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; @@ -7,6 +8,7 @@ using System.Windows.Controls.Primitives; using System.Windows.Forms; using System.Windows.Ink; using System.Windows.Input; +using System.Windows.Interop; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; @@ -19,17 +21,29 @@ namespace Ink_Canvas { public partial class MainWindow : Window { + private const int WM_CLIPBOARDUPDATE = 0x031D; + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool AddClipboardFormatListener(IntPtr hwnd); + + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool RemoveClipboardFormatListener(IntPtr hwnd); + private bool isClipboardMonitoringEnabled; private BitmapSource lastClipboardImage; + private HwndSource _clipboardHwndSource; // 初始化剪贴板监控 private void InitializeClipboardMonitoring() { try { - // 监听剪贴板变化 ClipboardNotification.ClipboardUpdate += OnClipboardUpdate; isClipboardMonitoringEnabled = true; + + SourceInitialized += OnSourceInitializedForClipboard; } catch (Exception ex) { @@ -37,6 +51,36 @@ namespace Ink_Canvas } } + private void OnSourceInitializedForClipboard(object sender, EventArgs e) + { + SourceInitialized -= OnSourceInitializedForClipboard; + try + { + var handle = new WindowInteropHelper(this).Handle; + if (handle == IntPtr.Zero) return; + + _clipboardHwndSource = HwndSource.FromHwnd(handle); + _clipboardHwndSource?.AddHook(ClipboardWndProc); + + if (!AddClipboardFormatListener(handle)) + LogHelper.WriteLogToFile($"AddClipboardFormatListener 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Warning); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"安装剪贴板监听失败: {ex.Message}", LogHelper.LogType.Error); + } + } + + private IntPtr ClipboardWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + if (msg == WM_CLIPBOARDUPDATE) + { + Dispatcher.BeginInvoke(new Action(() => ClipboardNotification.NotifyFromMessage()), DispatcherPriority.Background); + handled = true; + } + return IntPtr.Zero; + } + // 剪贴板内容变化事件处理 private void OnClipboardUpdate() { @@ -273,6 +317,13 @@ namespace Ink_Canvas ClipboardNotification.ClipboardUpdate -= OnClipboardUpdate; isClipboardMonitoringEnabled = false; } + + var handle = new WindowInteropHelper(this).Handle; + if (handle != IntPtr.Zero) + RemoveClipboardFormatListener(handle); + + _clipboardHwndSource?.RemoveHook(ClipboardWndProc); + _clipboardHwndSource = null; } catch (Exception ex) { @@ -286,19 +337,10 @@ namespace Ink_Canvas { public static event Action ClipboardUpdate; - private static Timer clipboardTimer; private static string lastClipboardText = ""; private static bool lastHadImage; - static ClipboardNotification() - { - clipboardTimer = new Timer(); - clipboardTimer.Interval = 500; // 每500ms检查一次 - clipboardTimer.Tick += CheckClipboard; - clipboardTimer.Start(); - } - - private static void CheckClipboard(object sender, EventArgs e) + public static void NotifyFromMessage() { try { @@ -320,8 +362,6 @@ namespace Ink_Canvas public static void Stop() { - clipboardTimer?.Stop(); - clipboardTimer?.Dispose(); } } } diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs index 10e8f092..7115a68b 100644 --- a/Ink Canvas/MainWindow_cs/MW_Settings.cs +++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs @@ -2357,9 +2357,9 @@ namespace Ink_Canvas private void StartOrStoptimerCheckAutoFold() { if (Settings.Automation.IsEnableAutoFold) - timerCheckAutoFold.Start(); + _unifiedMainWindowTimer?.Start(); else - timerCheckAutoFold.Stop(); + _unifiedMainWindowTimer?.Stop(); } private void ToggleSwitchAutoFoldInEasiNote_Toggled(object sender, RoutedEventArgs e) diff --git a/Ink Canvas/MainWindow_cs/MW_Timer.cs b/Ink Canvas/MainWindow_cs/MW_Timer.cs index 43cd3382..61e32308 100644 --- a/Ink Canvas/MainWindow_cs/MW_Timer.cs +++ b/Ink Canvas/MainWindow_cs/MW_Timer.cs @@ -57,9 +57,8 @@ namespace Ink_Canvas public partial class MainWindow : Window { - private Timer timerCheckPPT = new Timer(); private Timer timerKillProcess = new Timer(); - private Timer timerCheckAutoFold = new Timer(); + private Timer _unifiedMainWindowTimer; private string AvailableLatestVersion; private Timer timerCheckAutoUpdateWithSilence = new Timer(); private Timer timerCheckAutoUpdateRetry = new Timer(); @@ -111,13 +110,11 @@ namespace Ink_Canvas // 修改InitTimers方法中的初始时间和日期格式 private void InitTimers() { - // PPT检查现在由PPTManager处理,不再需要定时器 - // timerCheckPPT.Elapsed += TimerCheckPPT_Elapsed; - // timerCheckPPT.Interval = 500; timerKillProcess.Elapsed += TimerKillProcess_Elapsed; timerKillProcess.Interval = 2000; - timerCheckAutoFold.Elapsed += timerCheckAutoFold_Elapsed; - timerCheckAutoFold.Interval = 500; + _unifiedMainWindowTimer = new Timer(500); + _unifiedMainWindowTimer.Elapsed += OnUnifiedMainWindowTimerElapsed; + _unifiedMainWindowTimer.AutoReset = true; timerCheckAutoUpdateWithSilence.Elapsed += timerCheckAutoUpdateWithSilence_Elapsed; timerCheckAutoUpdateWithSilence.Interval = 1000 * 60 * 10; timerCheckAutoUpdateRetry.Elapsed += timerCheckAutoUpdateRetry_Elapsed; @@ -154,6 +151,11 @@ namespace Ink_Canvas InitAutoSaveStrokesTimer(); } + private void OnUnifiedMainWindowTimerElapsed(object sender, ElapsedEventArgs e) + { + timerCheckAutoFold_Elapsed(sender, e); + } + // 初始化定时保存墨迹定时器 private void InitAutoSaveStrokesTimer() {