From 4f8c7d66e13c434e8572fea158baef97b424b44a Mon Sep 17 00:00:00 2001 From: CJKmkp <2564608840@qq.com> Date: Mon, 19 Jan 2026 21:02:24 +0800 Subject: [PATCH] =?UTF-8?q?improve:PPT=E8=81=94=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Ink Canvas/Helpers/PPTManager.cs | 248 ++++++++++++++++++++++- Ink Canvas/Windows/PPTQuickPanel.xaml.cs | 175 +++++++++++++++- 2 files changed, 404 insertions(+), 19 deletions(-) diff --git a/Ink Canvas/Helpers/PPTManager.cs b/Ink Canvas/Helpers/PPTManager.cs index 553ebaae..3de63ddf 100644 --- a/Ink Canvas/Helpers/PPTManager.cs +++ b/Ink Canvas/Helpers/PPTManager.cs @@ -317,6 +317,25 @@ namespace Ink_Canvas.Helpers try { + // 检查COM对象是否仍然有效 + if (!System.Runtime.InteropServices.Marshal.IsComObject(PPTApplication)) + { + DisconnectFromPPT(); + continue; + } + + try + { + var _ = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(PPTApplication); + System.Runtime.InteropServices.Marshal.Release(_); + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效 + DisconnectFromPPT(); + continue; + } + activePresentation = PPTApplication.ActivePresentation; if (!PPTROTConnectionHelper.AreComObjectsEqual(_pptActivePresentation, activePresentation)) @@ -326,14 +345,30 @@ namespace Ink_Canvas.Helpers continue; } } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效 + LogHelper.WriteLogToFile("检测到COM对象失效,断开连接", LogHelper.LogType.Trace); + DisconnectFromPPT(); + continue; + } catch (COMException ex) when ((uint)ex.ErrorCode == 0x8001010A) { LogHelper.WriteLogToFile("PowerPoint 忙,稍后重试", LogHelper.LogType.Trace); } + catch (COMException comEx) + { + // COM异常,对象可能已失效 + var hr = (uint)comEx.HResult; + LogHelper.WriteLogToFile($"检查演示文稿状态COM异常: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning); + DisconnectFromPPT(); + continue; + } catch (Exception ex) { LogHelper.WriteLogToFile($"检查演示文稿状态失败: {ex.Message}", LogHelper.LogType.Warning); - break; + DisconnectFromPPT(); + continue; } finally { @@ -590,9 +625,21 @@ namespace Ink_Canvas.Helpers Thread.Sleep(500); } } + catch (InvalidComObjectException ex) + { + LogHelper.WriteLogToFile($"PptComService异常: COM对象已失效 - {ex.Message}", LogHelper.LogType.Error); + DisconnectFromPPT(); + } + catch (COMException comEx) + { + var hr = (uint)comEx.HResult; + LogHelper.WriteLogToFile($"PptComService异常: COM异常 (HR: 0x{hr:X8}) - {comEx.Message}", LogHelper.LogType.Error); + DisconnectFromPPT(); + } catch (Exception ex) { LogHelper.WriteLogToFile($"PptComService异常: {ex.Message}", LogHelper.LogType.Error); + DisconnectFromPPT(); } } @@ -681,9 +728,22 @@ namespace Ink_Canvas.Helpers } } } + catch (InvalidComObjectException) + { + // COM对象已失效,断开连接 + LogHelper.WriteLogToFile("检测到COM对象失效,断开连接", LogHelper.LogType.Trace); + DisconnectFromPPT(); + } + catch (COMException comEx) + { + // COM异常,记录并断开连接 + var hr = (uint)comEx.HResult; + LogHelper.WriteLogToFile($"PPT连接检查COM异常: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning); + DisconnectFromPPT(); + } catch (Exception ex) { - LogHelper.WriteLogToFile($"PPT连接检查异常: {ex}", LogHelper.LogType.Error); + LogHelper.WriteLogToFile($"PptComService异常: {ex.Message}", LogHelper.LogType.Error); if (PPTApplication != null) { DisconnectFromPPT(); @@ -696,6 +756,24 @@ namespace Ink_Canvas.Helpers { try { + // 检查COM对象是否仍然有效 + if (PPTApplication == null || !System.Runtime.InteropServices.Marshal.IsComObject(PPTApplication)) + { + return; + } + + try + { + var _ = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(PPTApplication); + System.Runtime.InteropServices.Marshal.Release(_); + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效 + DisconnectFromPPT(); + return; + } + dynamic activePresentation = null; dynamic slideShowWindow = null; @@ -710,10 +788,25 @@ namespace Ink_Canvas.Helpers return; } } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效 + LogHelper.WriteLogToFile("检测到COM对象失效,断开连接", LogHelper.LogType.Trace); + DisconnectFromPPT(); + return; + } catch (COMException ex) when ((uint)ex.HResult == 0x8001010A) { LogHelper.WriteLogToFile("PowerPoint 忙,稍后重试", LogHelper.LogType.Trace); return; + } + catch (COMException comEx) + { + // COM异常,对象可能已失效 + var hr = (uint)comEx.HResult; + LogHelper.WriteLogToFile($"检查演示文稿状态COM异常: {comEx.Message} (HR: 0x{hr:X8})", LogHelper.LogType.Warning); + DisconnectFromPPT(); + return; } catch (Exception ex) { @@ -1199,14 +1292,28 @@ namespace Ink_Canvas.Helpers { UnbindEvents(); + // 安全释放所有COM对象,即使它们已失效也不会抛出异常 SafeReleaseComObject(_pptSlideShowWindow, "_pptSlideShowWindow"); SafeReleaseComObject(_pptActivePresentation, "_pptActivePresentation"); SafeReleaseComObject(CurrentSlide, "CurrentSlide"); SafeReleaseComObject(CurrentSlides, "CurrentSlides"); SafeReleaseComObject(CurrentPresentation, "CurrentPresentation"); - if (PPTApplication != null && Marshal.IsComObject(PPTApplication)) + // 释放PPTApplication + if (PPTApplication != null) + { + try { + // 检查是否为有效的COM对象 + if (Marshal.IsComObject(PPTApplication)) + { + // 检查COM对象是否仍然有效 + try + { + var _ = Marshal.GetIUnknownForObject(PPTApplication); + Marshal.Release(_); + + // 对象有效,尝试释放 try { Marshal.FinalReleaseComObject(PPTApplication); @@ -1222,9 +1329,27 @@ namespace Ink_Canvas.Helpers } } catch { } + } + } + catch (InvalidComObjectException) + { + // COM对象已失效,直接设置为null + LogHelper.WriteLogToFile("PPTApplication COM对象已失效,跳过释放", LogHelper.LogType.Trace); + } + } + } + catch (InvalidComObjectException) + { + // COM对象已失效,这是正常的 + LogHelper.WriteLogToFile("PPTApplication COM对象已失效,跳过释放", LogHelper.LogType.Trace); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"释放PPTApplication时发生异常: {ex.Message}", LogHelper.LogType.Warning); } } + // 清空所有引用 PPTApplication = null; _pptActivePresentation = null; _pptSlideShowWindow = null; @@ -1293,12 +1418,37 @@ namespace Ink_Canvas.Helpers { try { - if (comObject != null && Marshal.IsComObject(comObject)) + if (comObject != null) { + // 检查是否为有效的COM对象 + if (!Marshal.IsComObject(comObject)) + { + return; // 不是COM对象,无需释放 + } + + // 检查COM对象是否仍然有效 + try + { + // 尝试访问对象以验证其有效性 + var _ = Marshal.GetIUnknownForObject(comObject); + Marshal.Release(_); + } + catch (InvalidComObjectException) + { + // COM对象已失效,直接返回 + LogHelper.WriteLogToFile($"COM对象 {objectName} 已失效,跳过释放", LogHelper.LogType.Trace); + return; + } + int refCount = Marshal.ReleaseComObject(comObject); LogHelper.WriteLogToFile($"已释放COM对象 {objectName},引用计数: {refCount}", LogHelper.LogType.Trace); } } + catch (InvalidComObjectException) + { + // COM对象已失效,这是正常的,无需记录错误 + LogHelper.WriteLogToFile($"COM对象 {objectName} 已失效,跳过释放", LogHelper.LogType.Trace); + } catch (COMException comEx) { var hr = (uint)comEx.HResult; @@ -1327,9 +1477,36 @@ namespace Ink_Canvas.Helpers { try { - dynamic pres = _pptActivePresentation; - CurrentPresentation = pres; - CurrentSlides = pres.Slides; + // 检查COM对象是否仍然有效 + if (!Marshal.IsComObject(_pptActivePresentation)) + { + CurrentPresentation = null; + CurrentSlides = null; + } + else + { + try + { + var _ = Marshal.GetIUnknownForObject(_pptActivePresentation); + Marshal.Release(_); + } + catch (InvalidComObjectException) + { + CurrentPresentation = null; + CurrentSlides = null; + return; + } + + dynamic pres = _pptActivePresentation; + CurrentPresentation = pres; + CurrentSlides = pres.Slides; + } + } + catch (InvalidComObjectException) + { + LogHelper.WriteLogToFile($"访问演示文稿属性失败: COM对象已失效", LogHelper.LogType.Warning); + CurrentPresentation = null; + CurrentSlides = null; } catch (Exception ex) { @@ -1455,6 +1632,14 @@ namespace Ink_Canvas.Helpers SlidesCount = 0; } } + catch (InvalidComObjectException) + { + LogHelper.WriteLogToFile($"更新演示文稿信息失败: COM对象已失效", LogHelper.LogType.Warning); + CurrentPresentation = null; + CurrentSlides = null; + CurrentSlide = null; + SlidesCount = 0; + } catch (Exception ex) { LogHelper.WriteLogToFile($"更新演示文稿信息失败: {ex}", LogHelper.LogType.Error); @@ -1960,6 +2145,18 @@ namespace Ink_Canvas.Helpers if (!IsConnected || PPTApplication == null) return null; if (!Marshal.IsComObject(PPTApplication)) return null; + // 检查COM对象是否仍然有效 + try + { + var _ = Marshal.GetIUnknownForObject(PPTApplication); + Marshal.Release(_); + } + catch (InvalidComObjectException) + { + // COM对象已失效 + return null; + } + if (IsInSlideShow) { dynamic pptAppForSSW = PPTApplication; @@ -2047,11 +2244,28 @@ namespace Ink_Canvas.Helpers try { if (slideShowWindow == null) return 0; + + // 检查COM对象是否有效 + if (!Marshal.IsComObject(slideShowWindow)) + { + return 0; + } + + try + { + var _ = Marshal.GetIUnknownForObject(slideShowWindow); + Marshal.Release(_); + } + catch (InvalidComObjectException) + { + return 0; + } + dynamic ssw = slideShowWindow; view = ssw.View; - if (view != null) - { - dynamic viewObj = view; + if (view != null) + { + dynamic viewObj = view; slide = viewObj.Slide; if (slide != null) { @@ -2061,6 +2275,20 @@ namespace Ink_Canvas.Helpers } return 0; } + catch (COMException comEx) + { + // 处理 0x80048240: SlideShowView.Slide : Invalid request. No slide is currently in view. + var hr = (uint)comEx.HResult; + if (hr == 0x80048240) + { + return 0; + } + throw; + } + catch (InvalidComObjectException) + { + return 0; + } finally { SafeReleaseComObject(slide); diff --git a/Ink Canvas/Windows/PPTQuickPanel.xaml.cs b/Ink Canvas/Windows/PPTQuickPanel.xaml.cs index 704ea637..5f914e19 100644 --- a/Ink Canvas/Windows/PPTQuickPanel.xaml.cs +++ b/Ink Canvas/Windows/PPTQuickPanel.xaml.cs @@ -1389,23 +1389,104 @@ namespace Ink_Canvas.Windows if (pptManager != null) { - // 获取当前演示文稿 - var getCurrentActivePresentationMethod = pptManager.GetType().GetMethod("GetCurrentActivePresentation"); - var presentation = getCurrentActivePresentationMethod?.Invoke(pptManager, null) as Microsoft.Office.Interop.PowerPoint.Presentation; + // 尝试获取当前演示文稿,使用重试机制 + Microsoft.Office.Interop.PowerPoint.Presentation presentation = null; + + // 首先尝试使用 CurrentPresentation 属性(可能是缓存的) + try + { + var currentPresentationProperty = pptManager.GetType().GetProperty("CurrentPresentation", + System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); + presentation = currentPresentationProperty?.GetValue(pptManager) as Microsoft.Office.Interop.PowerPoint.Presentation; + } + catch { } + + // 如果 CurrentPresentation 不可用,尝试 GetCurrentActivePresentation + if (presentation == null) + { + try + { + var getCurrentActivePresentationMethod = pptManager.GetType().GetMethod("GetCurrentActivePresentation"); + presentation = getCurrentActivePresentationMethod?.Invoke(pptManager, null) as Microsoft.Office.Interop.PowerPoint.Presentation; + } + catch { } + } if (presentation != null) { - // 生成演示文稿ID(与PPTInkManager一致) - string presentationId = GeneratePresentationId(presentation); - return Path.Combine(autoSaveLocation, "Auto Saved - Presentations", presentationId); + try + { + // 立即检查COM对象是否仍然有效 + if (!System.Runtime.InteropServices.Marshal.IsComObject(presentation)) + { + return null; + } + + // 尝试访问对象以验证其有效性 + try + { + var _ = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(presentation); + System.Runtime.InteropServices.Marshal.Release(_); + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效,静默返回 + return null; + } + + // 立即生成演示文稿ID(在对象失效前) + string presentationId = GeneratePresentationId(presentation); + if (string.IsNullOrEmpty(presentationId) || presentationId.StartsWith("unknown_") || presentationId.StartsWith("invalid_") || presentationId.StartsWith("com_error_")) + { + // 生成ID失败,返回null而不是抛出异常 + return null; + } + + return Path.Combine(autoSaveLocation, "Auto Saved - Presentations", presentationId); + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效,静默返回(不记录错误日志) + return null; + } + catch (System.Runtime.InteropServices.COMException) + { + // COM异常,对象可能已失效,静默返回(不记录错误日志) + return null; + } + catch (Exception ex) + { + // 其他异常,只记录非COM相关异常 + if (!(ex is System.Runtime.InteropServices.InvalidComObjectException) && + !(ex is System.Runtime.InteropServices.COMException)) + { + LogHelper.WriteLogToFile($"获取PPT文件夹路径时发生非COM异常: {ex.Message}", LogHelper.LogType.Warning); + } + return null; + } } } } } } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效,静默返回(不记录错误日志) + return null; + } + catch (System.Runtime.InteropServices.COMException) + { + // COM异常,对象可能已失效,静默返回(不记录错误日志) + return null; + } catch (Exception ex) { - LogHelper.WriteLogToFile($"获取PPT文件夹路径失败: {ex.Message}", LogHelper.LogType.Error); + // 只记录非COM相关异常 + if (!(ex is System.Runtime.InteropServices.InvalidComObjectException) && + !(ex is System.Runtime.InteropServices.COMException)) + { + LogHelper.WriteLogToFile($"获取PPT文件夹路径失败: {ex.Message}", LogHelper.LogType.Error); + } } return null; @@ -1416,11 +1497,87 @@ namespace Ink_Canvas.Windows /// private string GeneratePresentationId(Microsoft.Office.Interop.PowerPoint.Presentation presentation) { + if (presentation == null) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + try { - var presentationPath = presentation.FullName; + // 检查COM对象是否仍然有效 + if (!System.Runtime.InteropServices.Marshal.IsComObject(presentation)) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + + // 验证COM对象有效性 + try + { + var _ = System.Runtime.InteropServices.Marshal.GetIUnknownForObject(presentation); + System.Runtime.InteropServices.Marshal.Release(_); + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效 + return $"unknown_{DateTime.Now.Ticks}"; + } + + // 逐个访问属性,每个都进行异常处理 + string presentationName = null; + string presentationPath = null; + int slidesCount = 0; + + try + { + presentationName = presentation.Name; + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + catch (System.Runtime.InteropServices.COMException) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + + try + { + presentationPath = presentation.FullName; + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + catch (System.Runtime.InteropServices.COMException) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + + try + { + slidesCount = presentation.Slides.Count; + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + catch (System.Runtime.InteropServices.COMException) + { + return $"unknown_{DateTime.Now.Ticks}"; + } + var fileHash = GetFileHash(presentationPath); - return $"{presentation.Name}_{presentation.Slides.Count}_{fileHash}"; + return $"{presentationName}_{slidesCount}_{fileHash}"; + } + catch (System.Runtime.InteropServices.InvalidComObjectException) + { + // COM对象已失效 + return $"unknown_{DateTime.Now.Ticks}"; + } + catch (System.Runtime.InteropServices.COMException) + { + // COM异常,对象可能已失效 + return $"unknown_{DateTime.Now.Ticks}"; } catch (Exception ex) {