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 问题:事件不起作用

Ctrl-C / Ctrl-V在VB6中不起作用

lambda函数在多进程中不起作用

为啥 PyCharm tkinter GUI 在 macOS Monterey 12 更新中不起作用?

为啥进入动画在新线程中不起作用?