【问题标题】:Issues while creating a VSTO Word Application创建 VSTO Word 应用程序时的问题
【发布时间】:2016-02-24 17:34:40
【问题描述】:

几乎在所有情况下都可以创建新的 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)

我们通过识别单词 process 并杀死该进程来杀死应用程序。请记住,因为实例化挂起,我们没有 Word 应用程序可以使用 Quit(),但是 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)).

但是这个异常是通过重试处理的,并且实例化在下一次尝试时起作用。

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

【问题讨论】:

  • 这看起来很像分配给对象的进程尚未完全释放且对象尚未“清理”时出现的错误。可能重试发生得太快?也许您应该尝试强制释放 COM 对象以及垃圾收集?
  • 非常感谢 :) 我们在重试实例化之前等待 15 秒。也许这太快了。我们如何释放一个没有实例的 com 对象?我们重试,因为实例化不起作用。

标签: c# ms-word vsto ms-office office-interop


【解决方案1】:

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

强制执行垃圾回收:

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

提醒一下,重复不是错误,这是由于 .NET 对象在内存中的存储方式造成的,因此您需要执行两次 Collect 和 WaitForPendingFinalizers。

所以首先要确保你自己释放你的物品,最后收集垃圾。

【讨论】:

  • 非常感谢 :) 正如我在另一条评论中所说,前面的单词实例并没有真正清理过这种方式,我只是在尝试
【解决方案2】:

您需要立即释放底层 COM 对象。使用完一个 Word 对象后,使用System.Runtime.InteropServices.Marshal.ReleaseComObject 释放它。然后在 Visual Basic 中将变量设置为 Nothing(在 C# 中为 null)以释放对对象的引用。在Systematically Releasing Objects 文章中阅读更多相关信息。该文章与 OUTlook 相关,但相同的规则可以应用于包括 Word 在内的所有 Office 应用程序。

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

【讨论】:

  • 谢谢 :) 我只是在尝试。实际上之前的单词实例并没有这样清理。
  • 不幸的是,这并没有改变任何东西。 Word 应用程序的初始化仍然随机挂起,将达到超时。超时后我无法以这种方式清理,因为我没有 COM 实例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-04
  • 2019-07-24
相关资源
最近更新 更多