2009-10-12 66 views
0

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

是否有一个显而易见的方法使用我现有的代码进行调整?另外,请你可以建议其他方式来完成这个任务。

在此先感谢。

回答

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)创建mar shaller中的FinalConstruct()

FinalConstruct() 
{ 
    HRESULT rval = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pUnkMarshaler.p); 
    ... 
} 

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

3)推导从IConnectionPointImplMT您的连接点和内部锁定来电时,你可以在同一时间触发更多然后一个。

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

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

(这个应该可以,但是我很久没有试过了......)

+0

非常感谢,我已经整理了它。我搜索了IConnectionPointImplMT并找到了此链接support.microsoft.com/kb/280512/EN-US/。更改2行后提供的代码工作正常(应该是:第148行的m_vec.GetUnknown和第196行的m_vec.GetCookie)。我不清楚为什么我需要添加编组器 - 在链接中没有提到这个问题? – Humbleton 2009-10-14 07:06:42

+0

当你想与vb6线程中的对象进行通信时,需要编组器。如果它不需要,...。 – Christopher 2009-10-14 14:49:56