我在COM对象中捆绑了一组数字密集的例程(每个例程最多需要1分钟),干净地实现IDispatch
。
因此我可以在Excel工作表中使用它们,这些例程将由按钮触发的VBA宏调用。
现在,当调用其中一个例程时,Excel用户界面被冻结,这对于工作表的最终用户来说非常不舒服。
我想找到任何机制来缓解这个问题。
这可能是例如在COM端启动的另一个线程中启动计算,立即返回,生成的线程在计算结果时回调VBA过程。
或者更简单的东西,因为我一次只需要执行一次计算。
现在,从其他线程调用VBA例程可能存在很多问题。我必须承认,我不熟悉COM,我只把它当作代码和Excel之间的黑盒子(我使用ATL)。
所以,
是否可以从其他线程回调VBA例程?
有没有更好的方法来实现我想要实现的目标?
在权衡选项并阅读互联网上的大量内容之后,我将进行合作多线程:在COM对象中,我将有三个例程,而不是一个例程:
class CMyObject : ...
{
...
STDMETHOD(ComputationLaunch)(...); // Spawn a thread and return immediately
STDMETHOD(ComputationQuery)(DOUBLE* progress, BOOL* finished);
STDMETHOD(ComputationResult)(VARIANT* out);
private:
bool finished, progress;
boost::mutex finished_lock, progress_lock;
ResultObject result; // This will be marshaled to out
// when calling ComputationResult
};
在VBA中:
Private computeActive as Boolean ' Poor man's lock
Public Sub Compute()
OnError GoTo ErrHandler:
If computeActive Then Exit Sub
computeActive = True
Dim o as MyObject
call o.ComputationLaunch
Dim finished as Boolean, progress as Double
While Not o.ComputationQuery(progress)
DoEvents
' Good place also to update a progress display
End While
Dim result as Variant
result = o.ComputationResult
' Do Something with result (eg. display it somewhere)
computeActive = False
Exit Sub
ErrHandler:
computeActive = False
Call HandleErrors
End Sub
实际上,通过在互联网上为COM加载项进行深度优先搜索,我意识到VBA宏在与Excel的GUI相同的事件循环中运行,您拥有DoEvents
工具,并且从其他线程回调VBA过程是不安全(或至少非常棘手)。这需要例如。欺骗Accesibility工具以获取Excel.Application
对象的同步句柄,并调用OnTime
方法来设置异步事件处理程序。不值得麻烦。
答案 0 :(得分:2)
如果你想做得好,你需要放弃VBA并编写COM加载项。
答案 1 :(得分:1)
发表评论作为答案......
您可以在COM对象中实现一个事件,并在完成后回调它。有关如何异步运行COM对象的示例,请参阅http://www.dailydoseofexcel.com/archives/2006/10/09/async-xmlhttp-calls/。
答案 2 :(得分:0)
我的脏黑客是:创建一个新的Excel实例,在那里运行代码。
另一种选择是为以后安排运行,让用户说出何时。 (在下面的示例中,我刚刚硬编码5秒。)这仍然会冻结用户界面,但是会在计划的稍后时间。
Sub ScheduleIt()
Application.OnTime Now + TimeValue("00:00:05"), "DoStuff"
End Sub
Sub DoStuff()
Dim d As Double
Dim i As Long
d = 1.23E+302
For i = 1 To 10000000#
' This loop takes a long time (several seconds).
d = Sqr(d)
Next i
MsgBox "done!"
End Sub