从新线程处理ExcelDnaUtil.Application

我正在使用ExcelDNA来开发一个XLL。

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

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

form1.show() 

当我closures表单然后closuresExcel时,Process Explorer显示Excel进程已妥善处置。

如果我使用新线程启动表单:

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

当我closures表单然后closuresExcel时,该进程仍保留在Process Explorer中。 我一直小心不要在任何代码行中使用两个小数点,并在closures表单时将接口成员设置为“无”。 我没有使用“ReleaseCOMObject”,因为其他文章指出这是不好的做法。

问题:如何从一个单独的线程正确地处理Excel进程?

这是不可能的COM线程正确的跨线程。

您不应该从另一个线程与Excel COM对象模型交谈。 如果遵循这个简单的规则,则不必担心两个点,也不需要将任何内容设置为Nothing,也不必调用任何ReleaseComObject。 Excel将closures很好。

由于Excel是单线程的(实际上是因为Excel COM对象模型存在于单线程的公寓中),所以与其他线程交谈Excel没有任何性能优势,因为它在内部全部被整理到主线程中。

如果你敢从另一个线程与Excel交谈,那么任何时候任何COM调用都可能失败。 这是因为Excel仍然“活着”,可以进入“对象模型被挂起”的状态,导致所有COM调用失败(即使COM消息filter无法捕捉到错误)。 Excel何时会进入这样一个顽固的模式? 例如,当用户做一些疯狂的事情时,比如点击鼠标button。

在完成另一个线程的工作之后,怎样才能callbackExcel呢? 当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