VB6 GUI无法在多线程COM环境中工作

时间:2009-10-12 16:28:28

标签: c++ windows com vb6 atl

我有一个VB6 COM客户端,它调用进程STA ATL / COM服务器。其中一个服务器方法X可能需要一段时间才能完成,所以我需要能够取消它。我尝试的是在新线程中运行方法代码并包含另一个方法Y,它执行定时WaitForSinleObject。所以客户端首先调用X然后进入一个循环调用VB6 DoEvents然后Y直到Y表示X已经完成。这很好用,但美中不足的是X线程还通过IConnectionPoint接口将事件触发回客户端。事件通过确定但是任何GUI调用都不起作用,因为据我所知,GUI只能在一个线程上工作,即主线程。

使用我现有的代码有明显的方法吗?或者,请您建议其他方法来实现这一目标。

提前致谢。

1 个答案:

答案 0 :(得分:1)

您应始终封送您的连接点呼叫。当你不这样做时,你可以调用VB代码,但它以随机方式失败(非编组对象),或者只是不起作用(GUI)。

要使用编组,您必须实现多个接口(见下文)。

另一种可能性是将异步调用转换为VB进行同步'fetch'调用。

所以你的代码来自(在C伪代码中......):

while( !wait( X ) )
{
   doevents();
}

到:

while( !wait( X ) )
{
    doevents();
    fetch_async_data();
}

1)通过将编组添加到COM_AGGRGATE表中,为您的类添加编组:

CComPtr<IUnknown> m_pUnkMarshaler;

BEGIN_COM_MAP(..)
   ...
   COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.p)
END_COM_MAP()

2)在FinalConstruct()

中创建编组器
FinalConstruct()
{
    HRESULT rval = CoCreateFreeThreadedMarshaler( GetControllingUnknown(), &m_pUnkMarshaler.p );
    ...
}

FinalRelease()
{ ...; m_pUnkMarshaler = 0; }

3)从IConnectionPointImplMT派生您的连接点,并在您可以同时触发多个连接点时在内部锁定调用。

4)不要无限期地等待对象的方法,因为你可以在死锁中运行。

5)对每个暴露的对象和连接点重复此操作。

(这应该有效,但我很长时间没试过......)