通过 COM 服务器上的不同线程发送时数据丢失 - 以前在 VC6 中工作,现在在 VS2010 中损坏

Data being lost when sent via a different thread over COM server - previously worked in VC6, now broken in VS2010

我在从VC6转VS2010的过程中遇到了很多小问题,但是这个问题解决不了。下面是从我的 class 向 COM 服务器发送数据时使用的委托。

编辑 2:添加了检查 varResult 的代码。

HRESULT Fire_Msg(BSTR Msg)
{
    CComVariant varResult;
    T* pT = static_cast<T*>(this);
    int nConnectionIndex;
    CComVariant* pvars = new CComVariant[1];

    int nConnections = m_vec.GetSize();

    for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
    {
        pT->Lock();
        CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
        pT->Unlock();
        IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
        if (pDispatch != NULL)
        {
            pvars[0] = Msg;
            DISPPARAMS disp = { pvars, NULL, 1, 0 };
            pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
        }
    }

    delete [] pvars;

    // Changed to display what happens to varResult.
    if (varResult.scode != S_OK)
    {
        // Do some error handling...  (later)
        return varResult.scode;
    }
    else
    {
        return varResult.scode;
    }
}

编辑 2:无论是工作还是非工作,varResult returns S_OK。没有区别。

当我在这条线上中断时,当从主进程或线程发送时,数据看起来是正确的:

pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);

编辑: 我有工作和非工作的照片。它实际上只是表明,当从 threadex 启动的线程调用时,数据已正确设置在 "disp" 中,并且执行 "pDispatch->Invoke" 没有问题。 在职的:

不工作: :结束编辑

在另一个应用程序中,我有以下代码来响应发送的数据:

BEGIN_DISPATCH_MAP(CGenRTEvent, CCmdTarget)
    //{{AFX_DISPATCH_MAP(CGenRTEvent)
    DISP_FUNCTION(CGenRTEvent, "OnMsgStr", OnMsgStr, VT_EMPTY, VTS_BSTR)
    DISP_FUNCTION(CGenRTEvent, "OnMsg", OnMsg, VT_EMPTY, VTS_BSTR)
    DISP_FUNCTION(CGenRTEvent, "OnEndRun", OnEndRun, VT_EMPTY, "")
    DISP_FUNCTION(CGenRTEvent, "OnProgress", OnProgress, VT_EMPTY, VTS_I4 VTS_BSTR)
    DISP_FUNCTION(CGenRTEvent, "OnISocket", OnISocket, VT_EMPTY, VTS_BSTR)
//  DISP_FUNCTION(CGenRTEvent, "OnMsg", OnMsg, VT_EMPTY, VTS_PVARIANT)
    //}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()

BEGIN_INTERFACE_MAP(CGenRTEvent, CCmdTarget)
    INTERFACE_PART(CGenRTEvent, DIID__IGenRTEvents, Dispatch)
END_INTERFACE_MAP()

void CGenRTEvent::OnMsgStr(LPCTSTR strMsg) 
{
    m_pFrame->OnMsgStr(strMsg);
}

从主线程(在第一个应用程序内)使用时,会正确引发 OnMsgStr。当从不同的线程完成时,永远不会引发 OnMsgStr。这在 VC6 中一直有效,但 VS2010 不喜欢它。

编辑:我的问题是,如何防止数据丢失?我相当确定原因与从不同线程调用它有关,但不知道如何解决它。

有什么建议或意见吗?

提前致谢。

在 Paulo Madeira 的慷慨帮助下,我通过搜索 KB280512 解决了这个问题,这使我找到了一个由 PJ Naughter 编写的名为 GPSCom 的项目。 Link 在这里 http://www.naughter.com/gpscom2.html。我下载了他的代码,他提供了一个名为 "ATLCPImplMT.h" 的免费软件文件,只要未经修改,就可以以任何形式使用。我根据他的例子修改了代码如下:

HRESULT Fire_Msg(BSTR Msg)
{
    CComCritSecLock<CComAutoCriticalSection> lock(m_CPMTCritSec);

    ATL::CComVariant varResult;
    int nConnections = m_Clients.GetSize();

    int nConnectionIndex;
    ATL::CComVariant* pvars = new ATL::CComVariant[1];

    for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
    {
        ATL::CComPtr<IDispatch> sp;
        if (SUCCEEDED(GetInterfaceAt(nConnectionIndex, sp)))
        {
            VariantClear(&varResult);
            pvars[0] = Msg;
            DISPPARAMS disp = { pvars, NULL, 1, 0 };
            sp->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
            if (varResult.scode != S_OK)
            {
                // Do some error handling...  (later)
                return varResult.scode;
            }
        }
    }
    delete [] pvars;
    return varResult.scode;
}

此问题可能与此处提出的问题重复:ATL COM: Access Event Methods From Other Thread。但公平地说,当我开始搜索时——我不知道要搜索的正确词。 谢谢