从新线程处置ExcelDnaUtil.Application

时间:2014-08-21 19:55:36

标签: multithreading excel vb.net-2010 excel-dna

我使用ExcelDNA开发XLL。

在其中,我有一个生活在我传递的DLL中的表单" ExcelDnaUtil.Application"作为成员,以促进表单和运行XLL的Excel实例之间的交互。

如果我使用以下命令在主线程中启动表单:

form1.show()

当我关闭表单然后关闭Excel时,Process Explorer显示Excel进程已正确处理。

如果我使用新主题启动表单:

Dim workerThread As Thread
workerThread = New Thread(Sub() form1.showdialog())
workerThread.Start()

当我关闭表单然后关闭Excel时,该过程仍保留在Process Explorer中。我小心不要在任何代码行中使用两个小数点,并将接口成员设置为"没有"关闭表格时。我没有使用" ReleaseCOMObject"正如其他文章所指出的那样,这是不好的做法。

问题:如何从单独的线程中正确处理Excel过程?

1 个答案:

答案 0 :(得分:1)

不可能让COM东西正确地跨线程。

您永远不应该从另一个线程与Excel COM对象模型对话。如果你遵循这个简单的规则,你永远不必担心两个点,永远不必设置任何东西,永远不必调用任何ReleaseComObject黑客。 Excel将很好地关闭。

由于Excel是单线程的(实际上因为Excel COM对象模型位于单线程单元中),因此与另一个线程的Excel交谈没有任何性能优势 - 无论如何,内部它都被编组到主线程中。

如果您敢于从另一个线程与Excel通信,那么任何COM调用都可能随时失败。这是因为Excel仍处于“活动状态”并且可以进入“对象模型被挂起”的状态,导致所有COM调用失败(甚至COM消息过滤器都无法捕获的错误)。 Excel什么时候会进入如此顽固的模式?例如,当用户做一些疯狂的事情时,例如单击鼠标按钮。

如何在另一个线程上完成一些工作后回调Excel?当Excel处于COM调用安全的模式时,Excel-DNA有一个帮助程序,可以安排在主线程上完成的工作。您只需使用包含要完成的工作的委托来调用ExcelAsyncUtil.QueueAsMacro(...)。这个调用可以在任何时候从任何线程进行,但代码只有在准备就绪时才会运行。

这有点笨拙的例子:

Public Module MyFunctions

    Dim workerThread As Thread

    Public Function OverwriteMe() As Object
        Dim caller = ExcelDnaUtil.Application.Caller
        workerThread = New Thread( _
            Sub()
                Thread.Sleep(5000)
                ExcelAsyncUtil.QueueAsMacro( _
                    Sub()
                        caller.Value = "Done!!!"
                    End Sub)
            End Sub)
        workerThread.Start()
        Return "Doing it..."
    End Function
End Module