我正在编写(并教自己如何编写)VB.NET 3.5中的实验程序集,它通过COM公开,然后从一些Excel VBA代码调用,以启动一个类的实例来捕获一些Excel事件,然后执行Excel中活动工作簿上的一些函数。
要启动该类,将从VBA传递对Excel应用程序的引用(我在程序集中使用PIA for Excel)。
我需要从我的程序集对活动工作簿执行耗时的操作,所以我决定在WinForm中使用BackgroundWorker
,这样我就可以在操作完成时显示操作的进度对话框。背景
我想知道使用后台工作者以这种方式通过COM与Excel交互是否有任何问题?询问的原因是程序集中的主类保存对Excel应用程序对象的引用,然后将其传递给BackgroundWorker
,以便它可以确定活动工作簿,然后对其执行某些操作。我只通过一个过程访问工作簿本身(而不是其他对象)。
出于某种原因,我觉得Excel可能不喜欢这样 - 我是对的吗?
答案 0 :(得分:2)
如果你参考这个:
然后,没有;你不能这样做。
Excel VBA是一个STA环境。所有对Excel对象模型的访问都必须在同一个线程中进行。你也没有选择线程;它必须是调用你的方法开始的线程。
要运行从工作线程访问Excel的代码,您必须“编组”指向工作线程的接口指针。 Mashalling创建了一对COM包装器(称为“代理/存根”对),可以根据需要在线程之间传递方法调用 - 这类似于在.NET中使用Form.Invoke()
方法时发生的情况。我不知道如何在.NET中做到这一点。无论如何,这不是我的第一个方法。
另一种选择是不要从你的工作线程访问Excel对象,而是在主表单对象中使用帮助器(你确实需要一个表单,不是吗?)。让您的工作线程通过Form.Invoke()
调用这些帮助程序,以确保它们从UI线程(VBA用来调用您的线程)运行。这在功能上与第一个替代方案相同,除了.NET完成工作,而不是COM。
第三种方法是根本不使用工作线程 - 以VB方式执行:从唯一的线程创建UI;显示它,然后从表单的Load
事件中完成您的工作。偶尔呼叫Application.DoEvents()
(每秒几次)让UI以平滑的一些相似性进行操作。
第四种选择是解决问题。使用全新的线程而不是池线程(这是从BackgroundWorker
获得的)并从那里处理UI。我们在这里反转角色:主线程将执行奇特的工作,而额外的线程创建一个表单并显示UI。同样,请确保使用Form.Invoke()
更新进度窗口。完成后确保你Dispose()
你的线程。这可能只是我的首选方法。
或者只是使用沙漏鼠标指针......你的“慢”是多么“慢”?
答案 1 :(得分:0)
对使用BackgroundWorker不太了解。我曾经使用过通过PIA和COM连接到Excel的Winforms应用程序。它使用一个普通的旧ThreadStart委托来启动一个线程,该线程在后台加载文件时显示进度条。工作得很好。据我所知,BackgroundWorker在封面下的工作方式基本相同,所以我会说它去做。