通过 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。但公平地说,当我开始搜索时——我不知道要搜索的正确词。
谢谢
我在从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。但公平地说,当我开始搜索时——我不知道要搜索的正确词。 谢谢