创建 VSTO Word 应用程序时出现的问题

本文关键字:问题 VSTO Word 应用程序 创建 | 更新日期: 2023-09-27 18:35:48

在几乎所有情况下创建新的VSTO Word应用程序都可以。我使用此行创建一个新实例:

var wordApplication = new Application {Visible = false}

(应用程序是"Microsoft.Office.Interop.Word.Application")

我们在单元测试和一些自动化中经常这样做。但是在大约 1000 次调用中,有一两次初始化没有完成,并且进程挂起。(有人知道原因吗?

为了解决这个问题,我将实例化包装为超时,然后重试:

var wordApplication = Utilities.CallWithTimeout(
    // stuff to do
    () => new Application {Visible = false},
    // error handler before the TimeoutException happens
    () => 
    {
        var info = "Try to create a WordApplication failed after 15 seconds";
        Tracer.TraceEvent(TraceEventType.Error, info, TraceCategory.Application);
        KillWordApplicationOnError(before);
    },
    // timeout
    TimeSpan.FromSeconds(15)); 

(CallWithTimeout:https://gist.github.com/JuergenGutsch/b4b72fcb6a06327a6a41 使用此方法重试:https://gist.github.com/JuergenGutsch/219e9fe3e5aad1a098f3)

我们正在通过识别单词进程并杀死该进程来杀死应用程序。请记住,由于实例化挂起,我们没有使用 Quit() 的 Word 应用程序,但 winword.exe 进程正在运行,我们需要杀死它。(我们如何杀死这个过程:https://gist.github.com/JuergenGutsch/92b64117cf51c15bab83)

这解决了挂起过程的问题,我们得到了一个新问题,在大约 3000 次调用中发生一次或两次。新问题是一个安全问题,它禁用了一个对所有 Word 加载项,以及一些包含 VBA 宏的自定义 dotm 模板。

我们没有收到任何异常,并且在事件日志中没有收到任何条目。除了这个在杀死进程之后:

An exception of type 'System.Runtime.InteropServices.COMException' occurred in BIS.MEDCS.Connectivity.Word.VSTO.dll but was not handled in user code
Additional information: Retrieving the COM class factory for component with CLSID {000209FF-0000-0000-C000-000000000046} failed due to the following error: 80080005 Server execution failed (Exception from HRESULT: 0x80080005 (CO_E_SERVER_EXEC_FAILURE)).

但是此异常通过重试处理,实例化在下一次尝试时有效。

你们中有谁知道这里发生了什么吗?

创建 VSTO Word 应用程序时出现的问题

除了@Eugene之外,垃圾回收不是"立即"发生的,而是在"最佳机会"发生,您可能会看到清理正在运行的实例的速度变慢(尤其是在 COM 对象未正确释放的情况下)

要强制执行垃圾回收,请执行以下操作:

GC.Collect
GC.WaitForPendingFinalizers
GC.Collect
GC.WaitForPendingFinalizers

请注意,复制不是错误,它是由于 .NET 对象在内存中的存储方式而完成的,因此您需要执行 Collect 和 WaitForPendingFinalizer 两次。

因此,首先确保自己释放物品,并在最后的手段中收集垃圾。

您需要立即释放基础 COM 对象。使用 System.Runtime.InteropServices.Marshal.ReleaseComObject 在完成使用 Word 对象后释放该对象。然后在 Visual Basic 中将变量设置为 Nothing(在 C# 中为 null)以释放对该对象的引用。在系统地释放对象一文中阅读有关此内容的更多信息。本文与 OUtlook 相关,但相同的规则可以应用于包括 Word 在内的所有 Office 应用程序。

将 COM 对象(不减少引用计数器)保留在内存中可能会导致进程在主机关闭后保持运行状态。