创建 VSTO Word 应用程序时出现问题
Issues while creating a VSTO Word Application
创建新的 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 The retry is done with this method: https://gist.github.com/JuergenGutsch/219e9fe3e5aad1a098f3)
我们正在终止应用程序,通过识别单词进程并终止该进程。记住,因为实例化挂了,我们没有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 对象。使用 System.Runtime.InteropServices.Marshal.ReleaseComObject to release a Word object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects 篇文章。这篇文章与 OUtlook 相关,但同样的规则可以应用于包括 Word 在内的所有 Office 应用程序。
将 COM 对象留在内存中(不减少引用计数器)可能会导致进程在主机关闭后 运行 剩余。
除@Eugene 外,垃圾收集不会发生 'immediately' 但在 'best opportunity' 上,您可能会发现清理 运行 实例的速度变慢(特别是如果 COM 对象尚未正确发布)
强制执行垃圾收集:
GC.Collect
GC.WaitForPendingFinalizers
GC.Collect
GC.WaitForPendingFinalizers
请注意,复制不是错误,这是由于 .NET 对象存储在内存中的方式造成的,因此您需要执行两次 Collect 和 WaitForPendingFinalizers。
所以首先确保你自己释放你的对象,并在最后的手段中收集垃圾。
创建新的 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 The retry is done with this method: https://gist.github.com/JuergenGutsch/219e9fe3e5aad1a098f3)
我们正在终止应用程序,通过识别单词进程并终止该进程。记住,因为实例化挂了,我们没有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 对象。使用 System.Runtime.InteropServices.Marshal.ReleaseComObject to release a Word object when you have finished using it. Then set a variable to Nothing in Visual Basic (null in C#) to release the reference to the object. Read more about that in the Systematically Releasing Objects 篇文章。这篇文章与 OUtlook 相关,但同样的规则可以应用于包括 Word 在内的所有 Office 应用程序。
将 COM 对象留在内存中(不减少引用计数器)可能会导致进程在主机关闭后 运行 剩余。
除@Eugene 外,垃圾收集不会发生 'immediately' 但在 'best opportunity' 上,您可能会发现清理 运行 实例的速度变慢(特别是如果 COM 对象尚未正确发布)
强制执行垃圾收集:
GC.Collect
GC.WaitForPendingFinalizers
GC.Collect
GC.WaitForPendingFinalizers
请注意,复制不是错误,这是由于 .NET 对象存储在内存中的方式造成的,因此您需要执行两次 Collect 和 WaitForPendingFinalizers。
所以首先确保你自己释放你的对象,并在最后的手段中收集垃圾。