VB6 GUI 在多线程 COM 环境中不起作用
Posted
技术标签:
【中文标题】VB6 GUI 在多线程 COM 环境中不起作用【英文标题】:VB6 GUI not working in multithreaded COM environment 【发布时间】:2010-12-06 01:08:23 【问题描述】:我有一个调用进程内 STA ATL/COM 服务器的 VB6 COM 客户端。服务器方法之一,X,可能需要一段时间才能完成,所以我需要能够取消它。我尝试的是在新线程中运行方法代码并包含另一个方法 Y,它执行定时 WaitForSinleObject。因此客户端首先调用 X,然后进入一个调用 VB6 DoEvents 的循环,然后是 Y,直到 Y 指示 X 已经完成。这很好用,但美中不足的是 X 线程还通过 IConnectionPoint 接口将事件触发回客户端。事件顺利通过,但任何 GUI 调用都不起作用,因为据我所知,GUI 只能在一个线程上工作,即主线程。
使用我现有的代码是否有明显的解决方法?或者,请您建议我可以实现此目的的其他方法。
【问题讨论】:
【参考方案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) 对每个暴露的对象和连接点重复此操作。
(这应该可以,但我很久没试过了……)
【讨论】:
非常感谢,我已经整理好了。我搜索了 IConnectionPointImplMT 并找到了这个链接 support.microsoft.com/kb/280512/EN-US/。提供的代码在更改 2 行后运行良好(应该是:第 148 行的 m_vec.GetUnknown 和第 196 行的 m_vec.GetCookie)。我不清楚为什么需要添加编组器 - 链接中没有提到这一点? 当您想在 vb6 线程中与您的对象进行通信时,需要编组器。如果不需要,... .以上是关于VB6 GUI 在多线程 COM 环境中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
@synchronized 在 MRC 中不起作用,我的应用程序在多线程中崩溃
Windows 7 中 VB6 的 .NET COM 问题:事件不起作用