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

使用我现有的代码,有没有一种明显的解决方法?另外,请您提出其他可以实现此目标的方法。

最佳答案

您应该始终封送连接点 call 。如果不这样做,则可以调用VB代码,但是它会以随机方式(非编码对象)失败,或者根本无法工作(GUI)。

要使用封送处理,您必须实现多个接口(interface)(请参见下文)。

另一种可能性是将对VB的异步调用转换为同步的“提取”调用。

因此,您的代码来自(使用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)当您可以同时触发一个以上的 call 时,请从IConnectionPointImplMT派生您的连接点并在内部锁定 call 。

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

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

(这应该可以,但是我已经很长时间没有尝试过了……)

09-16 09:12