Добрый день.
Есть два DCOM сервера(один центральный-CCentrSrv, другой локальный — CLocSrv). Хочу организовать механизм событий от локального к центральному.
Прочитал кучу мануала по событиям (даже организовал события от MFC клиента к DCOM — серверу, но вот при варианте DCOM — DCOM вылетает ошибка при возбуждении события, вызове Invoke в CProxy_ILocSrvEvents : public IConnectionPointImpl
Прошу помочь)))
Приведу весь необходимый код:
//Код центрального сервера
class ATL_NO_VTABLE CCentrSrv :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CCentrSrv, &CLSID_CentrSrv>,
public IConnectionPointContainerImpl<CCentrSrv>,
public CProxy_ICentrSrvEvents<CCentrSrv>,
public IDispatchImpl<ICentrSrv, &IID_ICentrSrv, &LIBID_srvLib, /*wMajor =*/ 1, /*wMinor =*/ 0>,
public IDispEventImpl<1,CCentrSrv,&DIID__ILocSrvEvents,&LIBID_LocalSrvLib,1,0>
{
...
BEGIN_COM_MAP(CCentrSrv)
...
COM_INTERFACE_ENTRY_IID(DIID__ILocSrvEvents,CCentrSrv)
END_COM_MAP()
...
BEGIN_SINK_MAP(CCentrSrv)
SINK_ENTRY_EX(1,DIID__ILocSrvEvents,1,EventHandler)
END_SINK_MAP()
...
public:
HRESULT EventHandler()
{
MessageBox(NULL,_T("EEEEEE!"),_T("Да детка!!!"),MB_OK);
return S_OK;
}
STDMETHOD(FireLockalServerEvent)(void)
{
USES_CONVERSION;
HRESULT hr;
IID ifaceIID;
MULTI_QI* ifaces = NULL ;
COSERVERINFO csi;
csi.dwReserved1 = 0;
csi.dwReserved2 = 0;
csi.pAuthInfo = NULL;
csi.pwszName = T2W(_T("localhost"));
ifaces = new MULTI_QI[1];
ifaces[0].hr = 0;
ifaces[0].pItf = NULL;
ifaceIID = IID_ILocSrv;
ifaces[0].pIID = (IID*)&ifaceIID;
hr = CoCreateInstanceEx(CLSID_LocSrv, NULL, CLSCTX_REMOTE_SERVER, &csi, 1, ifaces);
if(FAILED(hr))
return hr;
ILocSrv* locsrv = (ILocSrv*)ifaces[0].pItf ;
//////////////////////////////////////////////////////////////////////////
IUnknown* pUnk = NULL;
hr = QueryInterface(IID_IUnknown,(void**)&pUnk);
DWORD cookie;
CComQIPtr<IConnectionPointContainer>cpc(locsrv);
IConnectionPoint* cp = NULL;
hr = cpc->FindConnectionPoint(DIID__ILocSrvEvents,&cp);
hr = cp->Advise(pUnk,&cookie);
hr = locsrv->FireEvent();
hr = cp->Unadvise(cookie);
return hr;
}
};
//Класс локальн сервера
class ATL_NO_VTABLE CLocSrv :
public CComObjectRootEx<CComMultiThreadModel>,
public CComCoClass<CLocSrv, &CLSID_LocSrv>,
public IConnectionPointContainerImpl<CLocSrv>,
public CProxy_ILocSrvEvents<CLocSrv>,
public IDispatchImpl<ILocSrv, &IID_ILocSrv, &LIBID_LocalSrvLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
{
...
STDMETHOD(FireEvent)(void)
{
Fire_LocalEvent();
return S_OK;
}
};
////////
//реализ-я конекшн поинт.. ну и так понятно))))
template <class T>
class CProxy_ILocSrvEvents : public IConnectionPointImpl<T, &__uuidof( _ILocSrvEvents ), CComDynamicUnkArray>
{
//Warning this class will be regenerated by the wizard.
public:
HRESULT Fire_LocalEvent()
{
CComVariant varResult;
T* pT = static_cast<T*>(this);
int nConnectionIndex;
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)
{
varResult.Clear();
DISPPARAMS disp = { NULL, NULL, 0, 0 };
HRESULT hr = pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, &varResult, NULL, NULL);
//Здесь возвращает мне "Ошибка на сервере" и пишет в Output :
//First-chance exception at 0x00000000 in srv.exe: 0xC0000005: Access violation reading location 0x00000000.
//First-chance exception at 0x7c812aeb in LocalSrv.exe: 0x80010105: Ошибка на сервере.
//Причем используя в качестве клиета MFC приложение все было ОК
if(FAILED(hr))
if(DISP_E_EXCEPTION != hr)
{
varResult.scode = hr;
break;
}
}
}
return varResult.scode;
}
};
...
interface ILocSrv : IDispatch{
[id(1), helpstring("method SubscribeEvent")] HRESULT SubscribeEvent(void);
};
...
library LocalSrvLib
{
...
dispinterface _ILocSrvEvents
{
properties:
methods:
[id(1), helpstring("method LocalEvent")] HRESULT LocalEvent(void);
};
...
coclass LocSrv
{
[default] interface ILocSrv;
[default, source] dispinterface _ILocSrvEvents;
};
...