创建 Microsoft.Office.Interop.Word.Application 时出现延迟

发布于 2024-12-11 13:30:07 字数 1869 浏览 0 评论 0原文

我有一个(旧版 VB.Net)应用程序,它从一些表中提取数据,填充 Word 模板,并将该模板与其他几个文件连接起来。

在多台计算机上,这可以正常工作,但对于一个客户端来说,存在一个持续存在的问题,即在尝试打开模板文件(该文件存在,并且没有权限问题等)。

Dim doc As Document
Dim msWord As Microsoft.Office.Interop.Word.Application

msWord = New Microsoft.Office.Interop.Word.Application
' next line throws "Object reference not set to an instance of an object"
doc = msWord.Documents.Add(verifiedTemplateName)

当在(实施得很糟糕的)调试模式下运行时,会抛出一堆启动-停止执行的模式对话框,则不会抛出异常。

Dim doc As Document
Dim msWord As Microsoft.Office.Interop.Word.Application

msWord = New Microsoft.Office.Interop.Word.Application
MsgBox("VooDoo coder at work")
' now no exception is thrown
doc = msWord.Documents.Add(verifiedTemplateName)

当在正常模式下运行时,延迟几秒,不会抛出异常。

Dim doc As Document
Dim msWord As Microsoft.Office.Interop.Word.Application

msWord = New Microsoft.Office.Interop.Word.Application
Delay(5) ' function that pauses for one second
' now no exception is thrown
doc = msWord.Documents.Add(verifiedTemplateName)

这表明,在某些计算机上,Word.Application 需要一些时间才能“启动”。

但是如何最好地捕获它,并在它存在后继续;或者如果时间范围不雅则抛出错误(一如既往,最好由当地司法管辖区决定)?

这也是 MSDN 论坛中其他人报告的问题 @ WordApplication.Documents.Add 方法返回 null?

我见过的唯一建议的解决方案是潜在的无限循环:

Document nulldoc = null;
do
{
    document = application.Documents.Add(template, newtemplate, documenttype, visible);
    Thread.Sleep(100);
}
while (document == nulldoc);

是否有比愚蠢的延迟或可能无限的检查循环更好的解决方案?

另请参阅:创建的实例VB.net 中的 Word。 相同的错误,类似的代码;但解决方案是确保目标文件存在(在我的例子中确实存在)。

I've got an (legacy VB.Net) application that pulls data from some tables, populates a word template, and concatenates that template with several other files.

On several machines this works with no issues, but for one client there is a persistent problem where the Word Interop code throws Object reference not set to an instance of an object when attempting to open the template file (which exists, and has no permission issues, etc).

Dim doc As Document
Dim msWord As Microsoft.Office.Interop.Word.Application

msWord = New Microsoft.Office.Interop.Word.Application
' next line throws "Object reference not set to an instance of an object"
doc = msWord.Documents.Add(verifiedTemplateName)

When operating in a (horribly implemented) debug mode that throws up a bunch of modal dialogs that starts-n-stops execution, the exception is not thrown.

Dim doc As Document
Dim msWord As Microsoft.Office.Interop.Word.Application

msWord = New Microsoft.Office.Interop.Word.Application
MsgBox("VooDoo coder at work")
' now no exception is thrown
doc = msWord.Documents.Add(verifiedTemplateName)

When operation in normal mode, with a delay of some seconds, the exception is not thrown.

Dim doc As Document
Dim msWord As Microsoft.Office.Interop.Word.Application

msWord = New Microsoft.Office.Interop.Word.Application
Delay(5) ' function that pauses for one second
' now no exception is thrown
doc = msWord.Documents.Add(verifiedTemplateName)

This suggests that, on some machines, the Word.Application takes some time to "spin up."

But how best to trap for this, and continue once it exists; or throw an error if the time-frame is obscene (as always, best decided by the local jurisdiction)?

This is also an issue reported by others in the MSDN forums @ WordApplication.Documents.Add Method return null?

The only suggested solutions I've seen are potential infinite loops:

Document nulldoc = null;
do
{
    document = application.Documents.Add(template, newtemplate, documenttype, visible);
    Thread.Sleep(100);
}
while (document == nulldoc);

Is there a better solution to this than dumb delays, or possibly-infinite check-loops?

See Also: Error when creating an instance of Word in VB.net. Same error, similar code; but the solution was to ensure that the target file existed (which does, in my case).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夜深人未静 2024-12-18 13:30:07

我记得通过实现 COM IMessageFilter 接口System.Windows.Forms.IMessageFilter)。

这篇 MSDN 文章。

由于您的问题发生在 Word 忙于启动时,因此此技术可能会有所帮助。

顺便说一句,当您将 Office 自动化时,您可能会遇到 Office 无法退出的问题,如本知识库文章中所述

为了解决这个问题,您需要小心地在实例化的每个 COM 对象上调用 Marshal.ReleaseComObject,最好是在 try/finally 构造中。为了确保您不会错过任何引用,请避免使用“双点”构造 msWord.Documents.Add,而是显式创建对 msWord.Documents 的引用。

您的代码应该看起来更像(我猜是 VB.NET 语法,但您会明白的):

Dim msWord As Application
Dim doc As Document
Dim docs As Documents

Try
    msWord = ...
    docs = msWord.Documents
    ' Test if docs is Nothing to avoid a NullReferenceException
    If Not docs Is Nothing Then
        doc = docs.Add...
        ...
    End If
    ...
Finally
    If Not doc Is Nothing Then Marshal.ReleaseComObject doc
    If Not docs Is Nothing Then Marshal.ReleaseComObject docs
    If Not msWord Is Nothing Then 
        msWord.Quit
        Marshal.ReleaseComObject msWord
    End If
End Try

I remember solving problems with communicating with a busy out-proc COM server (Visual Studio in my case), by implementing the COM IMessageFilter interface (which is not the same as System.Windows.Forms.IMessageFilter).

There's an example of the technique in this MSDN article.

Since your problem happens when Word is busy starting up, it may be that this technique will help.

As an aside, when automating Office as you are doing, you are likely to come across the problem of Office failing to quit, as described in this KB article.

To solve this, you need to be careful to call Marshal.ReleaseComObject on every COM object you instantiate, preferably in a try/finally construct. To make sure you don't miss any references, avoid the "double-dot" construct msWord.Documents.Add, and instead explicitly create a reference to msWord.Documents.

Your code should look more like (I'm guessing the VB.NET syntax, but you'll get the idea):

Dim msWord As Application
Dim doc As Document
Dim docs As Documents

Try
    msWord = ...
    docs = msWord.Documents
    ' Test if docs is Nothing to avoid a NullReferenceException
    If Not docs Is Nothing Then
        doc = docs.Add...
        ...
    End If
    ...
Finally
    If Not doc Is Nothing Then Marshal.ReleaseComObject doc
    If Not docs Is Nothing Then Marshal.ReleaseComObject docs
    If Not msWord Is Nothing Then 
        msWord.Quit
        Marshal.ReleaseComObject msWord
    End If
End Try
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文