我正在使用COM Interop进行一些测试。我导出了这个测试类: -
<ClassInterface(ClassInterfaceType.None), ComSourceInterfaces(GetType(ICounterEvents))> _
Public Class Counter
Implements ICounter
Public Event CountTicked(ByVal current As Integer, ByVal max As Integer)
Public Sub StartCount(ByVal max As Integer) Implements ICounter.StartCount
ThreadPool.QueueUserWorkItem(Sub() Count(max))
End Sub
Private Sub Count(ByVal max As Integer)
For i = 1 To max
Dim x As Integer = i
'COM Seems to synchronize this automatically
RaiseEvent CountTicked(x, max)
Thread.Sleep(300)
Next
End Sub
End Class
我在VB6中对上面的内容进行了测试,结果非常奇怪。请注意,将在工作线程上调用Count,因此应在工作线程上引发其中引发的事件。然而在VB6中,我能够从事件处理程序中更改Label的标题,没有任何问题或故障,这是我不希望的。如果这是从VB.Net完成的,它将抛出一个跨线程异常。我的问题是,从VB6使用该类时会发生什么? COM会自动在VB6应用程序中的UI线程上引发事件吗?或者VB6不关心从工作线程改变控件?
答案 0 :(得分:0)
默认情况下,VB6在单线程单元中创建所有对象。每当VB6中的对象传递给另一个线程时,它实际上传递了该对象的副本(称为代理)。
从后台线程调用此代理对象不会直接调用UI线程上的原始对象。相反,它们通过消息泵编组到UI线程上的调用(使用基本相同的机制os Control.Invoke
或SynchronizationContext.Send
)。这就是为什么您可以直接编辑标签而无需手动编组电话,编组将自动为您完成
这篇文章更深入地讨论了这个问题