事例:组态软件中,通过web客户端控件实现数据的动画显示,客户端控件绑定了指定的数据点名称,在客户端后台运行一服务进程与服务器通过SOCKET进行通讯,客户端后台进程解码后通过点名来触发指定的客户端控件显示数据。我的想法是在客户端通过STDMETHOD(Advise)(IUnknown* pUnkSink, DWORD* pdwCookie);建立连接时会得到pdwCookie,控件通过一REGISTER(TAGNAME,pdwCookie)向后台服务进程发送订阅,后台建立hash表记录点名与pdwCookie的映射,当解码后通过点名找到pdwCookie,我想能不能通过pdwCookie这个参数触发指定的控件显示新数据或动画,advise过程如下:
STDMETHODIMP IConnectionPointImplMT<T, piid, CDV>::Advise(IUnknown* pUnkSink,
DWORD* pdwCookie)
{
IUnknown* p;
HRESULT hRes = S_OK;
if (pUnkSink == NULL || pdwCookie == NULL)
return E_POINTER;
IID iid;
GetConnectionInterface(&iid);
hRes = pUnkSink->QueryInterface(iid, (void**)&p);
if (SUCCEEDED(hRes))
{
m_CPMTCritSec.Lock();
DWORD dwGITCookie;
hRes = m_pGIT->RegisterInterfaceInGlobal(
p, iid, &dwGITCookie);
if(hRes == S_OK)
{
// Using the CCom(Dynamic)UnkArray to store the cookie instead of an IUnknown *:
*pdwCookie = m_vec.Add(reinterpret_cast<IUnknown *>(dwGITCookie));
hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT; if (hRes != S_OK)
m_pGIT->RevokeInterfaceFromGlobal(dwGITCookie);
}
m_CPMTCritSec.Unlock();
// GIT will have AddRef'ed p:
p->Release();
}
else if (hRes == E_NOINTERFACE)
hRes = CONNECT_E_CANNOTCONNECT;
if (FAILED(hRes))
*pdwCookie = 0;
return hRes;
}
其中这个m_vec好像就是管理连接点的连接枚举器。我做过的一个出接口如下:
HRESULT Fire_Onlink2(VARIANT tagname, VARIANT value, VARIANT tagtime)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[3];
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)
{
VariantClear(&varResult);
pvars[2] = tagname;
pvars[1] = value;
pvars[0] = tagtime;
DISPPARAMS disp = { pvars, NULL, 3, 0 };
pDispatch->Invoke(0x3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
};
其中通过 m_vec使所有的连接执行。能否通过m_vec,pdwCookie找到指定的sink然后触发指定的控件呢?而不比当一个数据点值过来时触发所有的控件,然后由控件对比是不是自己绑定的点。请高人指点,跟我一样的大家也出出主意讨论下,不胜感谢。
STDMETHODIMP IConnectionPointImplMT<T, piid, CDV>::Advise(IUnknown* pUnkSink,
DWORD* pdwCookie)
{
IUnknown* p;
HRESULT hRes = S_OK;
if (pUnkSink == NULL || pdwCookie == NULL)
return E_POINTER;
IID iid;
GetConnectionInterface(&iid);
hRes = pUnkSink->QueryInterface(iid, (void**)&p);
if (SUCCEEDED(hRes))
{
m_CPMTCritSec.Lock();
DWORD dwGITCookie;
hRes = m_pGIT->RegisterInterfaceInGlobal(
p, iid, &dwGITCookie);
if(hRes == S_OK)
{
// Using the CCom(Dynamic)UnkArray to store the cookie instead of an IUnknown *:
*pdwCookie = m_vec.Add(reinterpret_cast<IUnknown *>(dwGITCookie));
hRes = (*pdwCookie != NULL) ? S_OK : CONNECT_E_ADVISELIMIT; if (hRes != S_OK)
m_pGIT->RevokeInterfaceFromGlobal(dwGITCookie);
}
m_CPMTCritSec.Unlock();
// GIT will have AddRef'ed p:
p->Release();
}
else if (hRes == E_NOINTERFACE)
hRes = CONNECT_E_CANNOTCONNECT;
if (FAILED(hRes))
*pdwCookie = 0;
return hRes;
}
其中这个m_vec好像就是管理连接点的连接枚举器。我做过的一个出接口如下:
HRESULT Fire_Onlink2(VARIANT tagname, VARIANT value, VARIANT tagtime)
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
CComVariant* pvars = new CComVariant[3];
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)
{
VariantClear(&varResult);
pvars[2] = tagname;
pvars[1] = value;
pvars[0] = tagtime;
DISPPARAMS disp = { pvars, NULL, 3, 0 };
pDispatch->Invoke(0x3, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
}
}
delete[] pvars;
return varResult.scode;
}
};
其中通过 m_vec使所有的连接执行。能否通过m_vec,pdwCookie找到指定的sink然后触发指定的控件呢?而不比当一个数据点值过来时触发所有的控件,然后由控件对比是不是自己绑定的点。请高人指点,跟我一样的大家也出出主意讨论下,不胜感谢。
{
IUnknown** pp = NULL;
if (m_nSize == 0) // no connections
{
m_pUnk = pUnk;
m_nSize = 1;
return (DWORD)m_pUnk;
}
else if (m_nSize == 1)
{
//create array
pp = (IUnknown**)malloc(sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH);
if (pp == NULL)
return 0;
memset(pp, 0, sizeof(IUnknown*)*_DEFAULT_VECTORLENGTH);
*pp = m_pUnk;
m_ppUnk = pp;
m_nSize = _DEFAULT_VECTORLENGTH;
}
for (pp = begin();pp<end();pp++)
{
if (*pp == NULL)
{
*pp = pUnk;
return (DWORD)pUnk;
}
}
int nAlloc = m_nSize*2;
pp = (IUnknown**)realloc(m_ppUnk, sizeof(IUnknown*)*nAlloc);
if (pp == NULL)
return 0;
m_ppUnk = pp;
memset(&m_ppUnk[m_nSize], 0, sizeof(IUnknown*)*m_nSize);
m_ppUnk[m_nSize] = pUnk;
m_nSize = nAlloc;
return (DWORD)pUnk;
} 查到了cookie值就是m_vec这个vector添加进去的IUnknown指针的(DWORD),这样就可以在出接口中
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
pT-> Lock();
CComPtr <IUnknown> sp = m_vec.GetAt(nConnectionIndex);
这端进行判断对指定的控件进行触发。晚了睡觉了,希望对遇到同样问题的兄弟门有帮助
服务器的RegEventClient可以类似这样写:// 客户端登记事件
HRESULT CServer::RegEventClient(IDispatch* pEventReceiver)
{
// 假设服务器的类有一个成员变量 IServerEvent* m_pRecv;
pEventReceiver->QueryInterface(IID_IServerEvent, NULL, &m_pRecv);
return S_OK;
}// 事件通知客户端
void CServer::fire_ServerEvent()
{
m_pRecv->SomeNotify(...);
}