VB6 GUI在多线程COM环境中不起作用

问题描述 投票:1回答:1

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

是否有明显的方法可以使用现有代码解决此问题?或者,请您提出其他可以实现此目标的方法。

c++ windows com vb6 atl
1个回答
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)对每个暴露的对象和连接点重复此操作。

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

© www.soinside.com 2019 - 2024. All rights reserved.